diff --git a/models/db/iterate_test.go b/models/db/iterate_test.go
index f9f1213721..5362f34075 100644
--- a/models/db/iterate_test.go
+++ b/models/db/iterate_test.go
@@ -19,13 +19,16 @@ func TestIterate(t *testing.T) {
 	xe := unittest.GetXORMEngine()
 	assert.NoError(t, xe.Sync(&repo_model.RepoUnit{}))
 
-	var repoCnt int
-	err := db.Iterate(db.DefaultContext, nil, func(ctx context.Context, repo *repo_model.RepoUnit) error {
-		repoCnt++
+	cnt, err := db.GetEngine(db.DefaultContext).Count(&repo_model.RepoUnit{})
+	assert.NoError(t, err)
+
+	var repoUnitCnt int
+	err = db.Iterate(db.DefaultContext, nil, func(ctx context.Context, repo *repo_model.RepoUnit) error {
+		repoUnitCnt++
 		return nil
 	})
 	assert.NoError(t, err)
-	assert.EqualValues(t, 89, repoCnt)
+	assert.EqualValues(t, cnt, repoUnitCnt)
 
 	err = db.Iterate(db.DefaultContext, nil, func(ctx context.Context, repoUnit *repo_model.RepoUnit) error {
 		reopUnit2 := repo_model.RepoUnit{ID: repoUnit.ID}
diff --git a/models/db/list_test.go b/models/db/list_test.go
index 195450b1e7..6b9bebd64b 100644
--- a/models/db/list_test.go
+++ b/models/db/list_test.go
@@ -31,15 +31,20 @@ func TestFind(t *testing.T) {
 	xe := unittest.GetXORMEngine()
 	assert.NoError(t, xe.Sync(&repo_model.RepoUnit{}))
 
+	var repoUnitCount int
+	_, err := db.GetEngine(db.DefaultContext).SQL("SELECT COUNT(*) FROM repo_unit").Get(&repoUnitCount)
+	assert.NoError(t, err)
+	assert.NotEmpty(t, repoUnitCount)
+
 	opts := mockListOptions{}
 	var repoUnits []repo_model.RepoUnit
-	err := db.Find(db.DefaultContext, &opts, &repoUnits)
+	err = db.Find(db.DefaultContext, &opts, &repoUnits)
 	assert.NoError(t, err)
-	assert.EqualValues(t, 89, len(repoUnits))
+	assert.EqualValues(t, repoUnitCount, len(repoUnits))
 
 	cnt, err := db.Count(db.DefaultContext, &opts, new(repo_model.RepoUnit))
 	assert.NoError(t, err)
-	assert.EqualValues(t, 89, cnt)
+	assert.EqualValues(t, repoUnitCount, cnt)
 
 	repoUnits = make([]repo_model.RepoUnit, 0, 10)
 	newCnt, err := db.FindAndCount(db.DefaultContext, &opts, &repoUnits)
diff --git a/models/dbfs/dbfs_test.go b/models/dbfs/dbfs_test.go
index 30aa6463c5..300758c623 100644
--- a/models/dbfs/dbfs_test.go
+++ b/models/dbfs/dbfs_test.go
@@ -12,8 +12,6 @@ import (
 	"code.gitea.io/gitea/models/db"
 
 	"github.com/stretchr/testify/assert"
-
-	_ "github.com/mattn/go-sqlite3"
 )
 
 func changeDefaultFileBlockSize(n int64) (restore func()) {
diff --git a/models/fixtures/repo_unit.yml b/models/fixtures/repo_unit.yml
index 184be2d861..5bb974a7d7 100644
--- a/models/fixtures/repo_unit.yml
+++ b/models/fixtures/repo_unit.yml
@@ -601,3 +601,9 @@
   repo_id: 57
   type: 5
   created_unix: 946684810
+
+-
+  id: 90
+  repo_id: 52
+  type: 1
+  created_unix: 946684810
diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml
index 496d1a3e7a..ef7730780f 100644
--- a/models/fixtures/repository.yml
+++ b/models/fixtures/repository.yml
@@ -1560,6 +1560,7 @@
   owner_name: user30
   lower_name: empty
   name: empty
+  default_branch: master
   num_watches: 0
   num_stars: 0
   num_forks: 0
diff --git a/models/fixtures/user.yml b/models/fixtures/user.yml
index fce4a4bda0..eba33a7c36 100644
--- a/models/fixtures/user.yml
+++ b/models/fixtures/user.yml
@@ -1091,7 +1091,7 @@
   max_repo_creation: -1
   is_active: true
   is_admin: false
-  is_restricted: true
+  is_restricted: false
   allow_git_hook: false
   allow_import_local: false
   allow_create_organization: true
diff --git a/models/repo/repo.go b/models/repo/repo.go
index 3653dae015..266cbc288c 100644
--- a/models/repo/repo.go
+++ b/models/repo/repo.go
@@ -225,6 +225,12 @@ func (repo *Repository) IsBroken() bool {
 	return repo.Status == RepositoryBroken
 }
 
+// MarkAsBrokenEmpty marks the repo as broken and empty
+func (repo *Repository) MarkAsBrokenEmpty() {
+	repo.Status = RepositoryBroken
+	repo.IsEmpty = true
+}
+
 // AfterLoad is invoked from XORM after setting the values of all fields of this object.
 func (repo *Repository) AfterLoad() {
 	repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
@@ -729,7 +735,7 @@ func IsRepositoryExist(ctx context.Context, u *user_model.User, repoName string)
 		return false, err
 	}
 	isDir, err := util.IsDir(RepoPath(u.Name, repoName))
-	return has && isDir, err
+	return has || isDir, err
 }
 
 // GetTemplateRepo populates repo.TemplateRepo for a generated repository and
diff --git a/models/unittest/fixtures.go b/models/unittest/fixtures.go
index 545452a159..f7ee766731 100644
--- a/models/unittest/fixtures.go
+++ b/models/unittest/fixtures.go
@@ -17,7 +17,7 @@ import (
 	"xorm.io/xorm/schemas"
 )
 
-var fixtures *testfixtures.Loader
+var fixturesLoader *testfixtures.Loader
 
 // GetXORMEngine gets the XORM engine
 func GetXORMEngine(engine ...*xorm.Engine) (x *xorm.Engine) {
@@ -30,11 +30,11 @@ func GetXORMEngine(engine ...*xorm.Engine) (x *xorm.Engine) {
 // InitFixtures initialize test fixtures for a test database
 func InitFixtures(opts FixturesOptions, engine ...*xorm.Engine) (err error) {
 	e := GetXORMEngine(engine...)
-	var testfiles func(*testfixtures.Loader) error
+	var fixtureOptionFiles func(*testfixtures.Loader) error
 	if opts.Dir != "" {
-		testfiles = testfixtures.Directory(opts.Dir)
+		fixtureOptionFiles = testfixtures.Directory(opts.Dir)
 	} else {
-		testfiles = testfixtures.Files(opts.Files...)
+		fixtureOptionFiles = testfixtures.Files(opts.Files...)
 	}
 	dialect := "unknown"
 	switch e.Dialect().URI().DBType {
@@ -54,14 +54,14 @@ func InitFixtures(opts FixturesOptions, engine ...*xorm.Engine) (err error) {
 		testfixtures.Database(e.DB().DB),
 		testfixtures.Dialect(dialect),
 		testfixtures.DangerousSkipTestDatabaseCheck(),
-		testfiles,
+		fixtureOptionFiles,
 	}
 
 	if e.Dialect().URI().DBType == schemas.POSTGRES {
 		loaderOptions = append(loaderOptions, testfixtures.SkipResetSequences())
 	}
 
-	fixtures, err = testfixtures.New(loaderOptions...)
+	fixturesLoader, err = testfixtures.New(loaderOptions...)
 	if err != nil {
 		return err
 	}
@@ -78,11 +78,9 @@ func InitFixtures(opts FixturesOptions, engine ...*xorm.Engine) (err error) {
 func LoadFixtures(engine ...*xorm.Engine) error {
 	e := GetXORMEngine(engine...)
 	var err error
-	// Database transaction conflicts could occur and result in ROLLBACK
-	// As a simple workaround, we just retry 20 times.
-	for i := 0; i < 20; i++ {
-		err = fixtures.Load()
-		if err == nil {
+	// (doubt) database transaction conflicts could occur and result in ROLLBACK? just try for a few times.
+	for i := 0; i < 5; i++ {
+		if err = fixturesLoader.Load(); err == nil {
 			break
 		}
 		time.Sleep(200 * time.Millisecond)
diff --git a/models/user/user_test.go b/models/user/user_test.go
index 8e78fee6b3..c2314d5c03 100644
--- a/models/user/user_test.go
+++ b/models/user/user_test.go
@@ -5,6 +5,7 @@ package user_test
 
 import (
 	"context"
+	"fmt"
 	"math/rand"
 	"strings"
 	"testing"
@@ -64,9 +65,10 @@ func TestSearchUsers(t *testing.T) {
 	testSuccess := func(opts *user_model.SearchUserOptions, expectedUserOrOrgIDs []int64) {
 		users, _, err := user_model.SearchUsers(opts)
 		assert.NoError(t, err)
-		if assert.Len(t, users, len(expectedUserOrOrgIDs), opts) {
+		cassText := fmt.Sprintf("ids: %v, opts: %v", expectedUserOrOrgIDs, opts)
+		if assert.Len(t, users, len(expectedUserOrOrgIDs), "case: %s", cassText) {
 			for i, expectedID := range expectedUserOrOrgIDs {
-				assert.EqualValues(t, expectedID, users[i].ID)
+				assert.EqualValues(t, expectedID, users[i].ID, "case: %s", cassText)
 			}
 		}
 	}
@@ -118,7 +120,7 @@ func TestSearchUsers(t *testing.T) {
 		[]int64{1})
 
 	testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsRestricted: util.OptionalBoolTrue},
-		[]int64{29, 30})
+		[]int64{29})
 
 	testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsProhibitLogin: util.OptionalBoolTrue},
 		[]int64{30})
diff --git a/modules/context/context.go b/modules/context/context.go
index 2507cc10c0..21bae91129 100644
--- a/modules/context/context.go
+++ b/modules/context/context.go
@@ -301,7 +301,7 @@ func (ctx *Context) serverErrorInternal(logMsg string, logErr error) {
 
 		// it's safe to show internal error to admin users, and it helps
 		if !setting.IsProd || (ctx.Doer != nil && ctx.Doer.IsAdmin) {
-			ctx.Data["ErrorMsg"] = logErr
+			ctx.Data["ErrorMsg"] = fmt.Sprintf("%s, %s", logMsg, logErr)
 		}
 	}
 
diff --git a/modules/context/repo.go b/modules/context/repo.go
index 8b4d0c1bf4..1736de2e4b 100644
--- a/modules/context/repo.go
+++ b/modules/context/repo.go
@@ -184,6 +184,9 @@ func (r *Repository) CanCreateIssueDependencies(user *user_model.User, isPull bo
 
 // GetCommitsCount returns cached commit count for current view
 func (r *Repository) GetCommitsCount() (int64, error) {
+	if r.Commit == nil {
+		return 0, nil
+	}
 	var contextName string
 	if r.IsViewBranch {
 		contextName = r.BranchName
@@ -642,8 +645,7 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
 	if err != nil {
 		if strings.Contains(err.Error(), "repository does not exist") || strings.Contains(err.Error(), "no such file or directory") {
 			log.Error("Repository %-v has a broken repository on the file system: %s Error: %v", ctx.Repo.Repository, ctx.Repo.Repository.RepoPath(), err)
-			ctx.Repo.Repository.Status = repo_model.RepositoryBroken
-			ctx.Repo.Repository.IsEmpty = true
+			ctx.Repo.Repository.MarkAsBrokenEmpty()
 			ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch
 			// Only allow access to base of repo or settings
 			if !isHomeOrSettings {
@@ -689,7 +691,7 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
 	ctx.Data["BranchesCount"] = len(brs)
 
 	// If not branch selected, try default one.
-	// If default branch doesn't exists, fall back to some other branch.
+	// If default branch doesn't exist, fall back to some other branch.
 	if len(ctx.Repo.BranchName) == 0 {
 		if len(ctx.Repo.Repository.DefaultBranch) > 0 && gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) {
 			ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
@@ -878,6 +880,10 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
 	return func(ctx *Context) (cancel context.CancelFunc) {
 		// Empty repository does not have reference information.
 		if ctx.Repo.Repository.IsEmpty {
+			// assume the user is viewing the (non-existent) default branch
+			ctx.Repo.IsViewBranch = true
+			ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
+			ctx.Data["TreePath"] = ""
 			return
 		}
 
@@ -907,27 +913,30 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
 			refName = ctx.Repo.Repository.DefaultBranch
 			if !ctx.Repo.GitRepo.IsBranchExist(refName) {
 				brs, _, err := ctx.Repo.GitRepo.GetBranchNames(0, 0)
-				if err != nil {
-					ctx.ServerError("GetBranches", err)
-					return
+				if err == nil && len(brs) != 0 {
+					refName = brs[0]
 				} else if len(brs) == 0 {
-					err = fmt.Errorf("No branches in non-empty repository %s",
-						ctx.Repo.GitRepo.Path)
-					ctx.ServerError("GetBranches", err)
-					return
+					log.Error("No branches in non-empty repository %s", ctx.Repo.GitRepo.Path)
+					ctx.Repo.Repository.MarkAsBrokenEmpty()
+				} else {
+					log.Error("GetBranches error: %v", err)
+					ctx.Repo.Repository.MarkAsBrokenEmpty()
 				}
-				refName = brs[0]
 			}
 			ctx.Repo.RefName = refName
 			ctx.Repo.BranchName = refName
 			ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName)
-			if err != nil {
+			if err == nil {
+				ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
+			} else if strings.Contains(err.Error(), "fatal: not a git repository") || strings.Contains(err.Error(), "object does not exist") {
+				// if the repository is broken, we can continue to the handler code, to show "Settings -> Delete Repository" for end users
+				log.Error("GetBranchCommit: %v", err)
+				ctx.Repo.Repository.MarkAsBrokenEmpty()
+			} else {
 				ctx.ServerError("GetBranchCommit", err)
 				return
 			}
-			ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
 			ctx.Repo.IsViewBranch = true
-
 		} else {
 			refName = getRefName(ctx, refType)
 			ctx.Repo.RefName = refName
diff --git a/modules/git/command.go b/modules/git/command.go
index a42d859f55..ac013d4ea1 100644
--- a/modules/git/command.go
+++ b/modules/git/command.go
@@ -211,10 +211,18 @@ type RunOpts struct {
 	Env               []string
 	Timeout           time.Duration
 	UseContextTimeout bool
-	Dir               string
-	Stdout, Stderr    io.Writer
-	Stdin             io.Reader
-	PipelineFunc      func(context.Context, context.CancelFunc) error
+
+	// Dir is the working dir for the git command, however:
+	// FIXME: this could be incorrect in many cases, for example:
+	// * /some/path/.git
+	// * /some/path/.git/gitea-data/data/repositories/user/repo.git
+	// If "user/repo.git" is invalid/broken, then running git command in it will use "/some/path/.git", and produce unexpected results
+	// The correct approach is to use `--git-dir" global argument
+	Dir string
+
+	Stdout, Stderr io.Writer
+	Stdin          io.Reader
+	PipelineFunc   func(context.Context, context.CancelFunc) error
 }
 
 func commonBaseEnvs() []string {
diff --git a/modules/git/repo.go b/modules/git/repo.go
index d29ec40ae2..3637aa47c4 100644
--- a/modules/git/repo.go
+++ b/modules/git/repo.go
@@ -80,7 +80,7 @@ func InitRepository(ctx context.Context, repoPath string, bare bool) error {
 // IsEmpty Check if repository is empty.
 func (repo *Repository) IsEmpty() (bool, error) {
 	var errbuf, output strings.Builder
-	if err := NewCommand(repo.Ctx, "show-ref", "--head", "^HEAD$").
+	if err := NewCommand(repo.Ctx).AddOptionFormat("--git-dir=%s", repo.Path).AddArguments("show-ref", "--head", "^HEAD$").
 		Run(&RunOpts{
 			Dir:    repo.Path,
 			Stdout: &output,
diff --git a/modules/git/repo_base_nogogit.go b/modules/git/repo_base_nogogit.go
index a0216d14a6..e0f2d563b3 100644
--- a/modules/git/repo_base_nogogit.go
+++ b/modules/git/repo_base_nogogit.go
@@ -61,7 +61,7 @@ func OpenRepository(ctx context.Context, repoPath string) (*Repository, error) {
 	}
 
 	repo.batchWriter, repo.batchReader, repo.batchCancel = CatFileBatch(ctx, repoPath)
-	repo.checkWriter, repo.checkReader, repo.checkCancel = CatFileBatchCheck(ctx, repo.Path)
+	repo.checkWriter, repo.checkReader, repo.checkCancel = CatFileBatchCheck(ctx, repoPath)
 
 	return repo, nil
 }
diff --git a/modules/indexer/code/indexer.go b/modules/indexer/code/indexer.go
index 027d13555c..2c493ccf94 100644
--- a/modules/indexer/code/indexer.go
+++ b/modules/indexer/code/indexer.go
@@ -154,7 +154,9 @@ func Init() {
 				log.Trace("IndexerData Process Repo: %d", indexerData.RepoID)
 
 				if err := index(ctx, indexer, indexerData.RepoID); err != nil {
-					log.Error("index: %v", err)
+					if !setting.IsInTesting {
+						log.Error("indexer index error for repo %v: %v", indexerData.RepoID, err)
+					}
 					if indexer.Ping() {
 						continue
 					}
diff --git a/modules/indexer/stats/db.go b/modules/indexer/stats/db.go
index 9bbdcad60d..2a0475dea6 100644
--- a/modules/indexer/stats/db.go
+++ b/modules/indexer/stats/db.go
@@ -11,6 +11,7 @@ import (
 	"code.gitea.io/gitea/modules/graceful"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/process"
+	"code.gitea.io/gitea/modules/setting"
 )
 
 // DBIndexer implements Indexer interface to use database's like search
@@ -46,7 +47,7 @@ func (db *DBIndexer) Index(id int64) error {
 	// Get latest commit for default branch
 	commitID, err := gitRepo.GetBranchCommitID(repo.DefaultBranch)
 	if err != nil {
-		if git.IsErrBranchNotExist(err) || git.IsErrNotExist(err) {
+		if git.IsErrBranchNotExist(err) || git.IsErrNotExist(err) || setting.IsInTesting {
 			log.Debug("Unable to get commit ID for default branch %s in %s ... skipping this repository", repo.DefaultBranch, repo.RepoPath())
 			return nil
 		}
@@ -62,7 +63,9 @@ func (db *DBIndexer) Index(id int64) error {
 	// Calculate and save language statistics to database
 	stats, err := gitRepo.GetLanguageStats(commitID)
 	if err != nil {
-		log.Error("Unable to get language stats for ID %s for default branch %s in %s. Error: %v", commitID, repo.DefaultBranch, repo.RepoPath(), err)
+		if !setting.IsInTesting {
+			log.Error("Unable to get language stats for ID %s for default branch %s in %s. Error: %v", commitID, repo.DefaultBranch, repo.RepoPath(), err)
+		}
 		return err
 	}
 	err = repo_model.UpdateLanguageStats(repo, commitID, stats)
diff --git a/modules/indexer/stats/queue.go b/modules/indexer/stats/queue.go
index 32379f2859..a57338e07d 100644
--- a/modules/indexer/stats/queue.go
+++ b/modules/indexer/stats/queue.go
@@ -10,6 +10,7 @@ import (
 	"code.gitea.io/gitea/modules/graceful"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/queue"
+	"code.gitea.io/gitea/modules/setting"
 )
 
 // statsQueue represents a queue to handle repository stats updates
@@ -20,7 +21,9 @@ func handle(data ...queue.Data) []queue.Data {
 	for _, datum := range data {
 		opts := datum.(int64)
 		if err := indexer.Index(opts); err != nil {
-			log.Error("stats queue indexer.Index(%d) failed: %v", opts, err)
+			if !setting.IsInTesting {
+				log.Error("stats queue indexer.Index(%d) failed: %v", opts, err)
+			}
 		}
 	}
 	return nil
diff --git a/modules/setting/setting.go b/modules/setting/setting.go
index 4d7a7caab8..e1a57615a8 100644
--- a/modules/setting/setting.go
+++ b/modules/setting/setting.go
@@ -27,7 +27,7 @@ import (
 var (
 	// AppVer is the version of the current build of Gitea. It is set in main.go from main.Version.
 	AppVer string
-	// AppBuiltWith represents a human readable version go runtime build version and build tags. (See main.go formatBuiltWith().)
+	// AppBuiltWith represents a human-readable version go runtime build version and build tags. (See main.go formatBuiltWith().)
 	AppBuiltWith string
 	// AppStartTime store time gitea has started
 	AppStartTime time.Time
@@ -40,7 +40,8 @@ var (
 	// AppWorkPath is used as the base path for several other paths.
 	AppWorkPath string
 
-	// Global setting objects
+	// Other global setting objects
+
 	CfgProvider ConfigProvider
 	CustomPath  string // Custom directory path
 	CustomConf  string
@@ -48,6 +49,10 @@ var (
 	RunUser     string
 	IsProd      bool
 	IsWindows   bool
+
+	// IsInTesting indicates whether the testing is running. A lot of unreliable code causes a lot of nonsense error logs during testing
+	// TODO: this is only a temporary solution, we should make the test code more reliable
+	IsInTesting = false
 )
 
 func getAppPath() (string, error) {
@@ -108,8 +113,12 @@ func getWorkPath(appPath string) string {
 
 func init() {
 	IsWindows = runtime.GOOS == "windows"
+	if AppVer == "" {
+		AppVer = "dev"
+	}
+
 	// We can rely on log.CanColorStdout being set properly because modules/log/console_windows.go comes before modules/setting/setting.go lexicographically
-	// By default set this logger at Info - we'll change it later but we need to start with something.
+	// By default set this logger at Info - we'll change it later, but we need to start with something.
 	log.NewLogger(0, "console", "console", fmt.Sprintf(`{"level": "info", "colorize": %t, "stacktraceLevel": "none"}`, log.CanColorStdout))
 
 	var err error
diff --git a/routers/init.go b/routers/init.go
index c539975aca..af768abbf4 100644
--- a/routers/init.go
+++ b/routers/init.go
@@ -108,6 +108,7 @@ func GlobalInitInstalled(ctx context.Context) {
 	}
 
 	mustInitCtx(ctx, git.InitFull)
+	log.Info("Gitea Version: %s%s", setting.AppVer, setting.AppBuiltWith)
 	log.Info("Git Version: %s (home: %s)", git.VersionInfo(), git.HomeDir())
 	log.Info("AppPath: %s", setting.AppPath)
 	log.Info("AppWorkPath: %s", setting.AppWorkPath)
@@ -115,7 +116,6 @@ func GlobalInitInstalled(ctx context.Context) {
 	log.Info("Log path: %s", setting.Log.RootPath)
 	log.Info("Configuration file: %s", setting.CustomConf)
 	log.Info("Run Mode: %s", util.ToTitleCase(setting.RunMode))
-	log.Info("Gitea v%s%s", setting.AppVer, setting.AppBuiltWith)
 
 	// Setup i18n
 	translation.InitLocales(ctx)
diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go
index 476c1d5ddd..63387df281 100644
--- a/routers/web/repo/editor.go
+++ b/routers/web/repo/editor.go
@@ -82,7 +82,7 @@ func editFile(ctx *context.Context, isNewFile bool) {
 	}
 
 	// Check if the filename (and additional path) is specified in the querystring
-	// (filename is a misnomer, but kept for compatibility with Github)
+	// (filename is a misnomer, but kept for compatibility with GitHub)
 	filePath, fileName := path.Split(ctx.Req.URL.Query().Get("filename"))
 	filePath = strings.Trim(filePath, "/")
 	treeNames, treePaths := getParentTreeFields(path.Join(ctx.Repo.TreePath, filePath))
@@ -327,6 +327,10 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
 		}
 	}
 
+	if ctx.Repo.Repository.IsEmpty {
+		_ = repo_model.UpdateRepositoryCols(ctx, &repo_model.Repository{ID: ctx.Repo.Repository.ID, IsEmpty: false}, "is_empty")
+	}
+
 	if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(ctx, unit.TypePullRequests) {
 		ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ctx.Repo.BranchName) + "..." + util.PathEscapeSegments(form.NewBranchName))
 	} else {
@@ -617,25 +621,25 @@ func UploadFilePost(ctx *context.Context) {
 		return
 	}
 
-	var newTreePath string
-	for _, part := range treeNames {
-		newTreePath = path.Join(newTreePath, part)
-		entry, err := ctx.Repo.Commit.GetTreeEntryByPath(newTreePath)
-		if err != nil {
-			if git.IsErrNotExist(err) {
-				// Means there is no item with that name, so we're good
-				break
+	if !ctx.Repo.Repository.IsEmpty {
+		var newTreePath string
+		for _, part := range treeNames {
+			newTreePath = path.Join(newTreePath, part)
+			entry, err := ctx.Repo.Commit.GetTreeEntryByPath(newTreePath)
+			if err != nil {
+				if git.IsErrNotExist(err) {
+					break // Means there is no item with that name, so we're good
+				}
+				ctx.ServerError("Repo.Commit.GetTreeEntryByPath", err)
+				return
 			}
 
-			ctx.ServerError("Repo.Commit.GetTreeEntryByPath", err)
-			return
-		}
-
-		// User can only upload files to a directory.
-		if !entry.IsDir() {
-			ctx.Data["Err_TreePath"] = true
-			ctx.RenderWithErr(ctx.Tr("repo.editor.directory_is_a_file", part), tplUploadFile, &form)
-			return
+			// User can only upload files to a directory, the directory name shouldn't be an existing file.
+			if !entry.IsDir() {
+				ctx.Data["Err_TreePath"] = true
+				ctx.RenderWithErr(ctx.Tr("repo.editor.directory_is_a_file", part), tplUploadFile, &form)
+				return
+			}
 		}
 	}
 
@@ -714,6 +718,10 @@ func UploadFilePost(ctx *context.Context) {
 		return
 	}
 
+	if ctx.Repo.Repository.IsEmpty {
+		_ = repo_model.UpdateRepositoryCols(ctx, &repo_model.Repository{ID: ctx.Repo.Repository.ID, IsEmpty: false}, "is_empty")
+	}
+
 	if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(ctx, unit.TypePullRequests) {
 		ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ctx.Repo.BranchName) + "..." + util.PathEscapeSegments(form.NewBranchName))
 	} else {
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index 150050f76b..5a11073ba9 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -154,16 +154,6 @@ func renderDirectory(ctx *context.Context, treeLink string) {
 		ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+path.Base(ctx.Repo.TreePath), ctx.Repo.RefName)
 	}
 
-	// Check permission to add or upload new file.
-	if ctx.Repo.CanWrite(unit_model.TypeCode) && ctx.Repo.IsViewBranch {
-		ctx.Data["CanAddFile"] = !ctx.Repo.Repository.IsArchived
-		ctx.Data["CanUploadFile"] = setting.Repository.Upload.Enabled && !ctx.Repo.Repository.IsArchived
-	}
-
-	if ctx.Written() {
-		return
-	}
-
 	subfolder, readmeFile, err := findReadmeFileInEntries(ctx, entries, true)
 	if err != nil {
 		ctx.ServerError("findReadmeFileInEntries", err)
@@ -868,21 +858,25 @@ func renderRepoTopics(ctx *context.Context) {
 
 func renderCode(ctx *context.Context) {
 	ctx.Data["PageIsViewCode"] = true
+	ctx.Data["RepositoryUploadEnabled"] = setting.Repository.Upload.Enabled
 
-	if ctx.Repo.Repository.IsEmpty {
-		reallyEmpty := true
+	if ctx.Repo.Commit == nil || ctx.Repo.Repository.IsEmpty || ctx.Repo.Repository.IsBroken() {
+		showEmpty := true
 		var err error
 		if ctx.Repo.GitRepo != nil {
-			reallyEmpty, err = ctx.Repo.GitRepo.IsEmpty()
+			showEmpty, err = ctx.Repo.GitRepo.IsEmpty()
 			if err != nil {
-				ctx.ServerError("GitRepo.IsEmpty", err)
-				return
+				log.Error("GitRepo.IsEmpty: %v", err)
+				ctx.Repo.Repository.Status = repo_model.RepositoryBroken
+				showEmpty = true
+				ctx.Flash.Error(ctx.Tr("error.occurred"), true)
 			}
 		}
-		if reallyEmpty {
+		if showEmpty {
 			ctx.HTML(http.StatusOK, tplRepoEMPTY)
 			return
 		}
+
 		// the repo is not really empty, so we should update the modal in database
 		// such problem may be caused by:
 		// 1) an error occurs during pushing/receiving.  2) the user replaces an empty git repo manually
@@ -898,6 +892,14 @@ func renderCode(ctx *context.Context) {
 			ctx.ServerError("UpdateRepoSize", err)
 			return
 		}
+
+		// the repo's IsEmpty has been updated, redirect to this page to make sure middlewares can get the correct values
+		link := ctx.Link
+		if ctx.Req.URL.RawQuery != "" {
+			link += "?" + ctx.Req.URL.RawQuery
+		}
+		ctx.Redirect(link)
+		return
 	}
 
 	title := ctx.Repo.Repository.Owner.Name + "/" + ctx.Repo.Repository.Name
@@ -927,11 +929,9 @@ func renderCode(ctx *context.Context) {
 		return
 	}
 
-	if !ctx.Repo.Repository.IsEmpty {
-		checkCitationFile(ctx, entry)
-		if ctx.Written() {
-			return
-		}
+	checkCitationFile(ctx, entry)
+	if ctx.Written() {
+		return
 	}
 
 	renderLanguageStats(ctx)
diff --git a/routers/web/web.go b/routers/web/web.go
index a4a1b7113c..30a8314691 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -1184,7 +1184,7 @@ func RegisterRoutes(m *web.Route) {
 				m.Post("/upload-file", repo.UploadFileToServer)
 				m.Post("/upload-remove", web.Bind(forms.RemoveUploadFileForm{}), repo.RemoveUploadFileFromServer)
 			}, repo.MustBeEditable, repo.MustBeAbleToUpload)
-		}, context.RepoRef(), canEnableEditor, context.RepoMustNotBeArchived(), repo.MustBeNotEmpty)
+		}, context.RepoRef(), canEnableEditor, context.RepoMustNotBeArchived())
 
 		m.Group("/branches", func() {
 			m.Group("/_new", func() {
diff --git a/services/auth/source/db/authenticate.go b/services/auth/source/db/authenticate.go
index 76445e0d6d..773ec601ba 100644
--- a/services/auth/source/db/authenticate.go
+++ b/services/auth/source/db/authenticate.go
@@ -32,7 +32,7 @@ func Authenticate(user *user_model.User, login, password string) (*user_model.Us
 	}
 
 	// WARN: DON'T check user.IsActive, that will be checked on reqSign so that
-	// user could be hint to resend confirm email.
+	// user could be hinted to resend confirm email.
 	if user.ProhibitLogin {
 		return nil, user_model.ErrUserProhibitLogin{
 			UID:  user.ID,
diff --git a/services/repository/files/upload.go b/services/repository/files/upload.go
index cf2f7019b6..338811f0f1 100644
--- a/services/repository/files/upload.go
+++ b/services/repository/files/upload.go
@@ -86,11 +86,22 @@ func UploadRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
 		return err
 	}
 	defer t.Close()
-	if err := t.Clone(opts.OldBranch); err != nil {
-		return err
+
+	hasOldBranch := true
+	if err = t.Clone(opts.OldBranch); err != nil {
+		if !git.IsErrBranchNotExist(err) || !repo.IsEmpty {
+			return err
+		}
+		if err = t.Init(); err != nil {
+			return err
+		}
+		hasOldBranch = false
+		opts.LastCommitID = ""
 	}
-	if err := t.SetDefaultIndex(); err != nil {
-		return err
+	if hasOldBranch {
+		if err = t.SetDefaultIndex(); err != nil {
+			return err
+		}
 	}
 
 	var filename2attribute2info map[string]map[string]string
diff --git a/templates/repo/editor/commit_form.tmpl b/templates/repo/editor/commit_form.tmpl
index 7ac0ed3df1..db798d92e8 100644
--- a/templates/repo/editor/commit_form.tmpl
+++ b/templates/repo/editor/commit_form.tmpl
@@ -39,6 +39,7 @@
 					</label>
 				</div>
 			</div>
+			{{if not .Repository.IsEmpty}}
 			<div class="field">
 				{{$pullRequestEnabled := .Repository.UnitEnabled $.Context $.UnitTypePullRequests}}
 				{{$prUnit := .Repository.MustGetUnit $.Context $.UnitTypePullRequests}}
@@ -65,6 +66,7 @@
 					<span class="text-muted js-quick-pull-normalization-info"></span>
 				</div>
 			</div>
+			{{end}}
 		</div>
 	</div>
 	<button id="commit-button" type="submit" class="ui green button">
diff --git a/templates/repo/empty.tmpl b/templates/repo/empty.tmpl
index cb883e8df5..0acb08933a 100644
--- a/templates/repo/empty.tmpl
+++ b/templates/repo/empty.tmpl
@@ -21,8 +21,21 @@
 					<div class="ui attached guide table segment empty-repo-guide">
 						<div class="item">
 							<h3>{{.locale.Tr "repo.clone_this_repo"}} <small>{{.locale.Tr "repo.clone_helper" "http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository" | Str2html}}</small></h3>
-							<div class="ui action small input">
-								{{template "repo/clone_buttons" .}}
+
+							<div class="gt-df">
+								{{if and .CanWriteCode (not .Repository.IsArchived)}}
+									<a class="ui small button" href="{{.RepoLink}}/_new/{{.BranchName | PathEscapeSegments}}/">
+										{{.locale.Tr "repo.editor.new_file"}}
+									</a>
+									{{if .RepositoryUploadEnabled}}
+									<a class="ui small button" href="{{.RepoLink}}/_upload/{{.BranchName | PathEscapeSegments}}/">
+										{{.locale.Tr "repo.editor.upload_file"}}
+									</a>
+									{{end}}
+								{{end}}
+								<div class="ui action small input gt-df gt-f1">
+									{{template "repo/clone_buttons" .}}
+								</div>
 							</div>
 						</div>
 
diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl
index 8de54611c3..4db12f2c95 100644
--- a/templates/repo/home.tmpl
+++ b/templates/repo/home.tmpl
@@ -71,29 +71,27 @@
 					{{end}}
 					<a href="{{.Repository.Link}}/find/{{.BranchNameSubURL}}" class="ui compact basic button">{{.locale.Tr "repo.find_file.go_to_file"}}</a>
 				{{end}}
-				{{if or .CanAddFile .CanUploadFile}}
+
+				{{if and .CanWriteCode .IsViewBranch (not .Repository.IsArchived)}}
 					<button class="ui basic compact dropdown jump icon button gt-mr-2"{{if not .Repository.CanEnableEditor}} disabled{{end}}>
 						<span class="text">{{.locale.Tr "repo.editor.add_file"}}</span>
 						<div class="menu">
-							{{if .CanAddFile}}
-								<a class="item" href="{{.RepoLink}}/_new/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">
-									{{.locale.Tr "repo.editor.new_file"}}
-								</a>
-							{{end}}
-							{{if .CanUploadFile}}
-								<a class="item" href="{{.RepoLink}}/_upload/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">
-									{{.locale.Tr "repo.editor.upload_file"}}
-								</a>
-							{{end}}
-							{{if .CanAddFile}}
-								<a class="item" href="{{.RepoLink}}/_diffpatch/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">
-									{{.locale.Tr "repo.editor.patch"}}
-								</a>
+							<a class="item" href="{{.RepoLink}}/_new/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">
+								{{.locale.Tr "repo.editor.new_file"}}
+							</a>
+							{{if .RepositoryUploadEnabled}}
+							<a class="item" href="{{.RepoLink}}/_upload/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">
+								{{.locale.Tr "repo.editor.upload_file"}}
+							</a>
 							{{end}}
+							<a class="item" href="{{.RepoLink}}/_diffpatch/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">
+								{{.locale.Tr "repo.editor.patch"}}
+							</a>
 						</div>
 						{{svg "octicon-triangle-down" 14 "dropdown icon"}}
 					</button>
 				{{end}}
+
 				{{if and (eq $n 0) (.Repository.IsTemplate)}}
 					<a role="button" class="ui primary compact button" href="{{AppSubUrl}}/repo/create?template_id={{.Repository.ID}}">
 						{{.locale.Tr "repo.use_template"}}
diff --git a/tests/integration/empty_repo_test.go b/tests/integration/empty_repo_test.go
index 1a83de1292..80697c7329 100644
--- a/tests/integration/empty_repo_test.go
+++ b/tests/integration/empty_repo_test.go
@@ -4,12 +4,19 @@
 package integration
 
 import (
+	"bytes"
+	"io"
+	"mime/multipart"
 	"net/http"
 	"testing"
 
+	"code.gitea.io/gitea/models/db"
 	repo_model "code.gitea.io/gitea/models/repo"
 	"code.gitea.io/gitea/models/unittest"
 	user_model "code.gitea.io/gitea/models/user"
+	"code.gitea.io/gitea/modules/json"
+	"code.gitea.io/gitea/modules/setting"
+	"code.gitea.io/gitea/modules/test"
 	"code.gitea.io/gitea/tests"
 
 	"github.com/stretchr/testify/assert"
@@ -17,7 +24,7 @@ import (
 
 func TestEmptyRepo(t *testing.T) {
 	defer tests.PrepareTestEnv(t)()
-	subpaths := []string{
+	subPaths := []string{
 		"commits/master",
 		"raw/foo",
 		"commit/1ae57b34ccf7e18373",
@@ -26,8 +33,75 @@ func TestEmptyRepo(t *testing.T) {
 	emptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 5})
 	assert.True(t, emptyRepo.IsEmpty)
 	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: emptyRepo.OwnerID})
-	for _, subpath := range subpaths {
-		req := NewRequestf(t, "GET", "/%s/%s/%s", owner.Name, emptyRepo.Name, subpath)
+	for _, subPath := range subPaths {
+		req := NewRequestf(t, "GET", "/%s/%s/%s", owner.Name, emptyRepo.Name, subPath)
 		MakeRequest(t, req, http.StatusNotFound)
 	}
 }
+
+func TestEmptyRepoAddFile(t *testing.T) {
+	defer tests.PrepareTestEnv(t)()
+
+	err := user_model.UpdateUserCols(db.DefaultContext, &user_model.User{ID: 30, ProhibitLogin: false}, "prohibit_login")
+	assert.NoError(t, err)
+
+	session := loginUser(t, "user30")
+	req := NewRequest(t, "GET", "/user30/empty/_new/"+setting.Repository.DefaultBranch)
+	resp := session.MakeRequest(t, req, http.StatusOK)
+	doc := NewHTMLParser(t, resp.Body).Find(`input[name="commit_choice"]`)
+	assert.Equal(t, "", doc.AttrOr("checked", "_no_"))
+	req = NewRequestWithValues(t, "POST", "/user30/empty/_new/"+setting.Repository.DefaultBranch, map[string]string{
+		"_csrf":         GetCSRF(t, session, "/user/settings"),
+		"commit_choice": "direct",
+		"tree_path":     "test-file.md",
+		"content":       "newly-added-test-file",
+	})
+
+	resp = session.MakeRequest(t, req, http.StatusSeeOther)
+	redirect := test.RedirectURL(resp)
+	assert.Equal(t, "/user30/empty/src/branch/"+setting.Repository.DefaultBranch+"/test-file.md", redirect)
+
+	req = NewRequest(t, "GET", redirect)
+	resp = session.MakeRequest(t, req, http.StatusOK)
+	assert.Contains(t, resp.Body.String(), "newly-added-test-file")
+}
+
+func TestEmptyRepoUploadFile(t *testing.T) {
+	defer tests.PrepareTestEnv(t)()
+
+	err := user_model.UpdateUserCols(db.DefaultContext, &user_model.User{ID: 30, ProhibitLogin: false}, "prohibit_login")
+	assert.NoError(t, err)
+
+	session := loginUser(t, "user30")
+	req := NewRequest(t, "GET", "/user30/empty/_new/"+setting.Repository.DefaultBranch)
+	resp := session.MakeRequest(t, req, http.StatusOK)
+	doc := NewHTMLParser(t, resp.Body).Find(`input[name="commit_choice"]`)
+	assert.Equal(t, "", doc.AttrOr("checked", "_no_"))
+
+	body := &bytes.Buffer{}
+	mpForm := multipart.NewWriter(body)
+	_ = mpForm.WriteField("_csrf", GetCSRF(t, session, "/user/settings"))
+	file, _ := mpForm.CreateFormFile("file", "uploaded-file.txt")
+	_, _ = io.Copy(file, bytes.NewBufferString("newly-uploaded-test-file"))
+	_ = mpForm.Close()
+
+	req = NewRequestWithBody(t, "POST", "/user30/empty/upload-file", body)
+	req.Header.Add("Content-Type", mpForm.FormDataContentType())
+	resp = session.MakeRequest(t, req, http.StatusOK)
+	respMap := map[string]string{}
+	assert.NoError(t, json.Unmarshal(resp.Body.Bytes(), &respMap))
+
+	req = NewRequestWithValues(t, "POST", "/user30/empty/_upload/"+setting.Repository.DefaultBranch, map[string]string{
+		"_csrf":         GetCSRF(t, session, "/user/settings"),
+		"commit_choice": "direct",
+		"files":         respMap["uuid"],
+		"tree_path":     "",
+	})
+	resp = session.MakeRequest(t, req, http.StatusSeeOther)
+	redirect := test.RedirectURL(resp)
+	assert.Equal(t, "/user30/empty/src/branch/"+setting.Repository.DefaultBranch+"/", redirect)
+
+	req = NewRequest(t, "GET", redirect)
+	resp = session.MakeRequest(t, req, http.StatusOK)
+	assert.Contains(t, resp.Body.String(), "uploaded-file.txt")
+}
diff --git a/tests/integration/integration_test.go b/tests/integration/integration_test.go
index 965bae576c..33a815b154 100644
--- a/tests/integration/integration_test.go
+++ b/tests/integration/integration_test.go
@@ -124,6 +124,9 @@ func TestMain(m *testing.M) {
 		fmt.Printf("Error initializing test database: %v\n", err)
 		os.Exit(1)
 	}
+
+	// FIXME: the console logger is deleted by mistake, so if there is any `log.Fatal`, developers won't see any error message.
+	// Instead, "No tests were found",  last nonsense log is "According to the configuration, subsequent logs will not be printed to the console"
 	exitCode := m.Run()
 
 	tests.WriterCloser.Reset()
@@ -366,10 +369,12 @@ const NoExpectedStatus = -1
 func MakeRequest(t testing.TB, req *http.Request, expectedStatus int) *httptest.ResponseRecorder {
 	t.Helper()
 	recorder := httptest.NewRecorder()
+	if req.RemoteAddr == "" {
+		req.RemoteAddr = "test-mock:12345"
+	}
 	c.ServeHTTP(recorder, req)
 	if expectedStatus != NoExpectedStatus {
-		if !assert.EqualValues(t, expectedStatus, recorder.Code,
-			"Request: %s %s", req.Method, req.URL.String()) {
+		if !assert.EqualValues(t, expectedStatus, recorder.Code, "Request: %s %s", req.Method, req.URL.String()) {
 			logUnexpectedResponse(t, recorder)
 		}
 	}
@@ -410,8 +415,10 @@ func logUnexpectedResponse(t testing.TB, recorder *httptest.ResponseRecorder) {
 		return
 	} else if len(respBytes) < 500 {
 		// if body is short, just log the whole thing
-		t.Log("Response:", string(respBytes))
+		t.Log("Response: ", string(respBytes))
 		return
+	} else {
+		t.Log("Response length: ", len(respBytes))
 	}
 
 	// log the "flash" error message, if one exists
diff --git a/tests/test_utils.go b/tests/test_utils.go
index 102dd3d298..b3c98427c3 100644
--- a/tests/test_utils.go
+++ b/tests/test_utils.go
@@ -10,7 +10,6 @@ import (
 	"os"
 	"path"
 	"path/filepath"
-	"runtime"
 	"testing"
 
 	"code.gitea.io/gitea/models/db"
@@ -30,29 +29,44 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
+func exitf(format string, args ...interface{}) {
+	fmt.Printf(format+"\n", args...)
+	os.Exit(1)
+}
+
 func InitTest(requireGitea bool) {
 	giteaRoot := base.SetupGiteaRoot()
 	if giteaRoot == "" {
-		fmt.Println("Environment variable $GITEA_ROOT not set")
-		os.Exit(1)
+		exitf("Environment variable $GITEA_ROOT not set")
 	}
+	setting.AppWorkPath = giteaRoot
 	if requireGitea {
 		giteaBinary := "gitea"
-		if runtime.GOOS == "windows" {
+		if setting.IsWindows {
 			giteaBinary += ".exe"
 		}
 		setting.AppPath = path.Join(giteaRoot, giteaBinary)
 		if _, err := os.Stat(setting.AppPath); err != nil {
-			fmt.Printf("Could not find gitea binary at %s\n", setting.AppPath)
-			os.Exit(1)
+			exitf("Could not find gitea binary at %s", setting.AppPath)
 		}
 	}
 
 	giteaConf := os.Getenv("GITEA_CONF")
 	if giteaConf == "" {
-		fmt.Println("Environment variable $GITEA_CONF not set")
-		os.Exit(1)
-	} else if !path.IsAbs(giteaConf) {
+		// By default, use sqlite.ini for testing, then IDE like GoLand can start the test process with debugger.
+		// It's easier for developers to debug bugs step by step with a debugger.
+		// Notice: when doing "ssh push", Gitea executes sub processes, debugger won't work for the sub processes.
+		giteaConf = "tests/sqlite.ini"
+		_ = os.Setenv("GITEA_CONF", giteaConf)
+		fmt.Printf("Environment variable $GITEA_CONF not set, use default: %s\n", giteaConf)
+		if !setting.EnableSQLite3 {
+			exitf(`Need to enable SQLite3 for sqlite.ini testing, please set: -tags "sqlite,sqlite_unlock_notify"`)
+		}
+	}
+
+	setting.IsInTesting = true
+
+	if !path.IsAbs(giteaConf) {
 		setting.CustomConf = path.Join(giteaRoot, giteaConf)
 	} else {
 		setting.CustomConf = giteaConf
@@ -69,8 +83,7 @@ func InitTest(requireGitea bool) {
 
 	setting.LoadDBSetting()
 	if err := storage.Init(); err != nil {
-		fmt.Printf("Init storage failed: %v", err)
-		os.Exit(1)
+		exitf("Init storage failed: %v", err)
 	}
 
 	switch {
@@ -221,7 +234,7 @@ func PrepareTestEnv(t testing.TB, skip ...int) func() {
 	return deferFn
 }
 
-// resetFixtures flushes queues, reloads fixtures and resets test repositories within a single test.
+// ResetFixtures flushes queues, reloads fixtures and resets test repositories within a single test.
 // Most tests should call defer tests.PrepareTestEnv(t)() (or have onGiteaRun do that for them) but sometimes
 // within a single test this is required
 func ResetFixtures(t *testing.T) {
diff --git a/web_src/css/repository.css b/web_src/css/repository.css
index 05e50548d9..8e764f54cd 100644
--- a/web_src/css/repository.css
+++ b/web_src/css/repository.css
@@ -1911,15 +1911,12 @@
   border-radius: var(--border-radius) 0 0 var(--border-radius);
 }
 
-.repository.quickstart .guide .ui.action.small.input {
-  width: 100%;
-}
-
 .repository.quickstart .guide #repo-clone-url {
   border-radius: 0;
   padding: 5px 10px;
   font-size: 1.2em;
   line-height: 1.4;
+  flex: 1
 }
 
 .repository.release #release-list {