diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini
index ffc4e4067..25c3d5a59 100644
--- a/custom/conf/app.example.ini
+++ b/custom/conf/app.example.ini
@@ -64,6 +64,10 @@ PREFIX_ARCHIVE_FILES = true
 DISABLE_MIRRORS = false
 ; The default branch name of new repositories
 DEFAULT_BRANCH=master
+; Allow adoption of unadopted repositories
+ALLOW_ADOPTION_OF_UNADOPTED_REPOSITORIES=false
+; Allow deletion of unadopted repositories
+ALLOW_DELETION_OF_UNADOPTED_REPOSITORIES=false
 
 [repository.editor]
 ; List of file extensions for which lines should be wrapped in the Monaco editor
diff --git a/models/error.go b/models/error.go
index 13391e5d8..1cab19aaf 100644
--- a/models/error.go
+++ b/models/error.go
@@ -743,6 +743,22 @@ func (err ErrRepoAlreadyExist) Error() string {
 	return fmt.Sprintf("repository already exists [uname: %s, name: %s]", err.Uname, err.Name)
 }
 
+// ErrRepoFilesAlreadyExist represents a "RepoFilesAlreadyExist" kind of error.
+type ErrRepoFilesAlreadyExist struct {
+	Uname string
+	Name  string
+}
+
+// IsErrRepoFilesAlreadyExist checks if an error is a ErrRepoAlreadyExist.
+func IsErrRepoFilesAlreadyExist(err error) bool {
+	_, ok := err.(ErrRepoFilesAlreadyExist)
+	return ok
+}
+
+func (err ErrRepoFilesAlreadyExist) Error() string {
+	return fmt.Sprintf("repository files already exist [uname: %s, name: %s]", err.Uname, err.Name)
+}
+
 // ErrForkAlreadyExist represents a "ForkAlreadyExist" kind of error.
 type ErrForkAlreadyExist struct {
 	Uname    string
diff --git a/models/repo.go b/models/repo.go
index 25fe3f63d..96b359bca 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -278,7 +278,7 @@ func (repo *Repository) IsBeingCreated() bool {
 func (repo *Repository) AfterLoad() {
 	// FIXME: use models migration to solve all at once.
 	if len(repo.DefaultBranch) == 0 {
-		repo.DefaultBranch = "master"
+		repo.DefaultBranch = setting.Repository.DefaultBranch
 	}
 
 	repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
@@ -1048,7 +1048,7 @@ func (repo *Repository) CloneLink() (cl *CloneLink) {
 }
 
 // CheckCreateRepository check if could created a repository
-func CheckCreateRepository(doer, u *User, name string) error {
+func CheckCreateRepository(doer, u *User, name string, overwriteOrAdopt bool) error {
 	if !doer.CanCreateRepo() {
 		return ErrReachLimitOfRepo{u.MaxRepoCreation}
 	}
@@ -1063,6 +1063,10 @@ func CheckCreateRepository(doer, u *User, name string) error {
 	} else if has {
 		return ErrRepoAlreadyExist{u.Name, name}
 	}
+
+	if !overwriteOrAdopt && com.IsExist(RepoPath(u.Name, name)) {
+		return ErrRepoFilesAlreadyExist{u.Name, name}
+	}
 	return nil
 }
 
@@ -1116,11 +1120,15 @@ var (
 
 // IsUsableRepoName returns true when repository is usable
 func IsUsableRepoName(name string) error {
+	if alphaDashDotPattern.MatchString(name) {
+		// Note: usually this error is normally caught up earlier in the UI
+		return ErrNameCharsNotAllowed{Name: name}
+	}
 	return isUsableName(reservedRepoNames, reservedRepoPatterns, name)
 }
 
 // CreateRepository creates a repository for the user/organization.
-func CreateRepository(ctx DBContext, doer, u *User, repo *Repository) (err error) {
+func CreateRepository(ctx DBContext, doer, u *User, repo *Repository, overwriteOrAdopt bool) (err error) {
 	if err = IsUsableRepoName(repo.Name); err != nil {
 		return err
 	}
@@ -1132,6 +1140,15 @@ func CreateRepository(ctx DBContext, doer, u *User, repo *Repository) (err error
 		return ErrRepoAlreadyExist{u.Name, repo.Name}
 	}
 
+	repoPath := RepoPath(u.Name, repo.Name)
+	if !overwriteOrAdopt && com.IsExist(repoPath) {
+		log.Error("Files already exist in %s and we are not going to adopt or delete.", repoPath)
+		return ErrRepoFilesAlreadyExist{
+			Uname: u.Name,
+			Name:  repo.Name,
+		}
+	}
+
 	if _, err = ctx.e.Insert(repo); err != nil {
 		return err
 	}
@@ -1856,6 +1873,10 @@ func GetUserRepositories(opts *SearchRepoOptions) ([]*Repository, int64, error)
 		cond = cond.And(builder.Eq{"is_private": false})
 	}
 
+	if opts.LowerNames != nil && len(opts.LowerNames) > 0 {
+		cond = cond.And(builder.In("lower_name", opts.LowerNames))
+	}
+
 	sess := x.NewSession()
 	defer sess.Close()
 
diff --git a/models/repo_list.go b/models/repo_list.go
index dea88d881..355b801a7 100644
--- a/models/repo_list.go
+++ b/models/repo_list.go
@@ -175,6 +175,8 @@ type SearchRepoOptions struct {
 	// True -> include just has milestones
 	// False -> include just has no milestone
 	HasMilestones util.OptionalBool
+	// LowerNames represents valid lower names to restrict to
+	LowerNames []string
 }
 
 //SearchOrderBy is used to sort the result
diff --git a/models/user.go b/models/user.go
index c7b3f0981..650d5a803 100644
--- a/models/user.go
+++ b/models/user.go
@@ -646,8 +646,8 @@ func (u *User) GetOrganizationCount() (int64, error) {
 }
 
 // GetRepositories returns repositories that user owns, including private repositories.
-func (u *User) GetRepositories(listOpts ListOptions) (err error) {
-	u.Repos, _, err = GetUserRepositories(&SearchRepoOptions{Actor: u, Private: true, ListOptions: listOpts})
+func (u *User) GetRepositories(listOpts ListOptions, names ...string) (err error) {
+	u.Repos, _, err = GetUserRepositories(&SearchRepoOptions{Actor: u, Private: true, ListOptions: listOpts, LowerNames: names})
 	return err
 }
 
diff --git a/modules/git/repo_branch.go b/modules/git/repo_branch.go
index 8f9c802e0..cd30c191e 100644
--- a/modules/git/repo_branch.go
+++ b/modules/git/repo_branch.go
@@ -74,6 +74,11 @@ func (repo *Repository) SetDefaultBranch(name string) error {
 	return err
 }
 
+// GetDefaultBranch gets default branch of repository.
+func (repo *Repository) GetDefaultBranch() (string, error) {
+	return NewCommand("symbolic-ref", "HEAD").RunInDir(repo.Path)
+}
+
 // GetBranches returns all branches of the repository.
 func (repo *Repository) GetBranches() ([]string, error) {
 	var branchNames []string
diff --git a/modules/repository/adopt.go b/modules/repository/adopt.go
new file mode 100644
index 000000000..22cd6dd91
--- /dev/null
+++ b/modules/repository/adopt.go
@@ -0,0 +1,272 @@
+// Copyright 2020 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package repository
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/modules/git"
+	"code.gitea.io/gitea/modules/log"
+	"code.gitea.io/gitea/modules/setting"
+	"code.gitea.io/gitea/modules/util"
+	"github.com/gobwas/glob"
+	"github.com/unknwon/com"
+)
+
+// AdoptRepository adopts a repository for the user/organization.
+func AdoptRepository(doer, u *models.User, opts models.CreateRepoOptions) (*models.Repository, error) {
+	if !doer.IsAdmin && !u.CanCreateRepo() {
+		return nil, models.ErrReachLimitOfRepo{
+			Limit: u.MaxRepoCreation,
+		}
+	}
+
+	if len(opts.DefaultBranch) == 0 {
+		opts.DefaultBranch = setting.Repository.DefaultBranch
+	}
+
+	repo := &models.Repository{
+		OwnerID:                         u.ID,
+		Owner:                           u,
+		OwnerName:                       u.Name,
+		Name:                            opts.Name,
+		LowerName:                       strings.ToLower(opts.Name),
+		Description:                     opts.Description,
+		OriginalURL:                     opts.OriginalURL,
+		OriginalServiceType:             opts.GitServiceType,
+		IsPrivate:                       opts.IsPrivate,
+		IsFsckEnabled:                   !opts.IsMirror,
+		CloseIssuesViaCommitInAnyBranch: setting.Repository.DefaultCloseIssuesViaCommitsInAnyBranch,
+		Status:                          opts.Status,
+		IsEmpty:                         !opts.AutoInit,
+	}
+
+	if err := models.WithTx(func(ctx models.DBContext) error {
+		repoPath := models.RepoPath(u.Name, repo.Name)
+		if !com.IsExist(repoPath) {
+			return models.ErrRepoNotExist{
+				OwnerName: u.Name,
+				Name:      repo.Name,
+			}
+		}
+
+		if err := models.CreateRepository(ctx, doer, u, repo, true); err != nil {
+			return err
+		}
+		if err := adoptRepository(ctx, repoPath, doer, repo, opts); err != nil {
+			return fmt.Errorf("createDelegateHooks: %v", err)
+		}
+
+		// Initialize Issue Labels if selected
+		if len(opts.IssueLabels) > 0 {
+			if err := models.InitializeLabels(ctx, repo.ID, opts.IssueLabels, false); err != nil {
+				return fmt.Errorf("InitializeLabels: %v", err)
+			}
+		}
+
+		if stdout, err := git.NewCommand("update-server-info").
+			SetDescription(fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath)).
+			RunInDir(repoPath); err != nil {
+			log.Error("CreateRepository(git update-server-info) in %v: Stdout: %s\nError: %v", repo, stdout, err)
+			return fmt.Errorf("CreateRepository(git update-server-info): %v", err)
+		}
+		return nil
+	}); err != nil {
+		return nil, err
+	}
+
+	return repo, nil
+}
+
+// DeleteUnadoptedRepository deletes unadopted repository files from the filesystem
+func DeleteUnadoptedRepository(doer, u *models.User, repoName string) error {
+	if err := models.IsUsableRepoName(repoName); err != nil {
+		return err
+	}
+
+	repoPath := models.RepoPath(u.Name, repoName)
+	if !com.IsExist(repoPath) {
+		return models.ErrRepoNotExist{
+			OwnerName: u.Name,
+			Name:      repoName,
+		}
+	}
+
+	if exist, err := models.IsRepositoryExist(u, repoName); err != nil {
+		return err
+	} else if exist {
+		return models.ErrRepoAlreadyExist{
+			Uname: u.Name,
+			Name:  repoName,
+		}
+	}
+
+	return util.RemoveAll(repoPath)
+}
+
+// ListUnadoptedRepositories lists all the unadopted repositories that match the provided query
+func ListUnadoptedRepositories(query string, opts *models.ListOptions) ([]string, int, error) {
+	globUser, _ := glob.Compile("*")
+	globRepo, _ := glob.Compile("*")
+
+	qsplit := strings.SplitN(query, "/", 2)
+	if len(qsplit) > 0 && len(query) > 0 {
+		var err error
+		globUser, err = glob.Compile(qsplit[0])
+		if err != nil {
+			log.Info("Invalid glob expresion '%s' (skipped): %v", qsplit[0], err)
+		}
+		if len(qsplit) > 1 {
+			globRepo, err = glob.Compile(qsplit[1])
+			if err != nil {
+				log.Info("Invalid glob expresion '%s' (skipped): %v", qsplit[1], err)
+			}
+		}
+	}
+	start := (opts.Page - 1) * opts.PageSize
+	end := start + opts.PageSize
+
+	repoNamesToCheck := make([]string, 0, opts.PageSize)
+
+	repoNames := make([]string, 0, opts.PageSize)
+	var ctxUser *models.User
+
+	count := 0
+
+	// We're going to iterate by pagesize.
+	root := filepath.Join(setting.RepoRootPath)
+	if err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
+		if err != nil {
+			return err
+		}
+		if !info.IsDir() || path == root {
+			return nil
+		}
+
+		if !strings.ContainsRune(path[len(root)+1:], filepath.Separator) {
+			// Got a new user
+
+			// Clean up old repoNamesToCheck
+			if len(repoNamesToCheck) > 0 {
+				repos, _, err := models.GetUserRepositories(&models.SearchRepoOptions{Actor: ctxUser, Private: true, ListOptions: models.ListOptions{
+					Page:     1,
+					PageSize: opts.PageSize,
+				}, LowerNames: repoNamesToCheck})
+				if err != nil {
+					return err
+				}
+				for _, name := range repoNamesToCheck {
+					found := false
+				repoLoopCatchup:
+					for i, repo := range repos {
+						if repo.LowerName == name {
+							found = true
+							repos = append(repos[:i], repos[i+1:]...)
+							break repoLoopCatchup
+						}
+					}
+					if !found {
+						if count >= start && count < end {
+							repoNames = append(repoNames, fmt.Sprintf("%s/%s", ctxUser.Name, name))
+						}
+						count++
+					}
+				}
+				repoNamesToCheck = repoNamesToCheck[:0]
+			}
+
+			if !globUser.Match(info.Name()) {
+				return filepath.SkipDir
+			}
+
+			ctxUser, err = models.GetUserByName(info.Name())
+			if err != nil {
+				if models.IsErrUserNotExist(err) {
+					log.Debug("Missing user: %s", info.Name())
+					return filepath.SkipDir
+				}
+				return err
+			}
+			return nil
+		}
+
+		name := info.Name()
+
+		if !strings.HasSuffix(name, ".git") {
+			return filepath.SkipDir
+		}
+		name = name[:len(name)-4]
+		if models.IsUsableRepoName(name) != nil || strings.ToLower(name) != name || !globRepo.Match(name) {
+			return filepath.SkipDir
+		}
+		if count < end {
+			repoNamesToCheck = append(repoNamesToCheck, name)
+			if len(repoNamesToCheck) >= opts.PageSize {
+				repos, _, err := models.GetUserRepositories(&models.SearchRepoOptions{Actor: ctxUser, Private: true, ListOptions: models.ListOptions{
+					Page:     1,
+					PageSize: opts.PageSize,
+				}, LowerNames: repoNamesToCheck})
+				if err != nil {
+					return err
+				}
+				for _, name := range repoNamesToCheck {
+					found := false
+				repoLoop:
+					for i, repo := range repos {
+						if repo.Name == name {
+							found = true
+							repos = append(repos[:i], repos[i+1:]...)
+							break repoLoop
+						}
+					}
+					if !found {
+						if count >= start && count < end {
+							repoNames = append(repoNames, fmt.Sprintf("%s/%s", ctxUser.Name, name))
+						}
+						count++
+					}
+				}
+				repoNamesToCheck = repoNamesToCheck[:0]
+			}
+			return filepath.SkipDir
+		}
+		count++
+		return filepath.SkipDir
+	}); err != nil {
+		return nil, 0, err
+	}
+
+	if len(repoNamesToCheck) > 0 {
+		repos, _, err := models.GetUserRepositories(&models.SearchRepoOptions{Actor: ctxUser, Private: true, ListOptions: models.ListOptions{
+			Page:     1,
+			PageSize: opts.PageSize,
+		}, LowerNames: repoNamesToCheck})
+		if err != nil {
+			return nil, 0, err
+		}
+		for _, name := range repoNamesToCheck {
+			found := false
+		repoLoop:
+			for i, repo := range repos {
+				if repo.LowerName == name {
+					found = true
+					repos = append(repos[:i], repos[i+1:]...)
+					break repoLoop
+				}
+			}
+			if !found {
+				if count >= start && count < end {
+					repoNames = append(repoNames, fmt.Sprintf("%s/%s", ctxUser.Name, name))
+				}
+				count++
+			}
+		}
+	}
+	return repoNames, count, nil
+}
diff --git a/modules/repository/create.go b/modules/repository/create.go
index c180b9b94..e6a3e7081 100644
--- a/modules/repository/create.go
+++ b/modules/repository/create.go
@@ -13,10 +13,12 @@ import (
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/util"
+
+	"github.com/unknwon/com"
 )
 
 // CreateRepository creates a repository for the user/organization.
-func CreateRepository(doer, u *models.User, opts models.CreateRepoOptions) (_ *models.Repository, err error) {
+func CreateRepository(doer, u *models.User, opts models.CreateRepoOptions) (*models.Repository, error) {
 	if !doer.IsAdmin && !u.CanCreateRepo() {
 		return nil, models.ErrReachLimitOfRepo{
 			Limit: u.MaxRepoCreation,
@@ -44,39 +46,64 @@ func CreateRepository(doer, u *models.User, opts models.CreateRepoOptions) (_ *m
 		TrustModel:                      opts.TrustModel,
 	}
 
-	err = models.WithTx(func(ctx models.DBContext) error {
-		if err = models.CreateRepository(ctx, doer, u, repo); err != nil {
+	if err := models.WithTx(func(ctx models.DBContext) error {
+		if err := models.CreateRepository(ctx, doer, u, repo, false); err != nil {
 			return err
 		}
 
 		// No need for init mirror.
-		if !opts.IsMirror {
-			repoPath := models.RepoPath(u.Name, repo.Name)
-			if err = initRepository(ctx, repoPath, doer, repo, opts); err != nil {
-				if err2 := util.RemoveAll(repoPath); err2 != nil {
-					log.Error("initRepository: %v", err)
-					return fmt.Errorf(
-						"delete repo directory %s/%s failed(2): %v", u.Name, repo.Name, err2)
-				}
-				return fmt.Errorf("initRepository: %v", err)
-			}
+		if opts.IsMirror {
+			return nil
+		}
 
-			// Initialize Issue Labels if selected
-			if len(opts.IssueLabels) > 0 {
-				if err = models.InitializeLabels(ctx, repo.ID, opts.IssueLabels, false); err != nil {
-					return fmt.Errorf("InitializeLabels: %v", err)
-				}
-			}
-
-			if stdout, err := git.NewCommand("update-server-info").
-				SetDescription(fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath)).
-				RunInDir(repoPath); err != nil {
-				log.Error("CreateRepository(git update-server-info) in %v: Stdout: %s\nError: %v", repo, stdout, err)
-				return fmt.Errorf("CreateRepository(git update-server-info): %v", err)
+		repoPath := models.RepoPath(u.Name, repo.Name)
+		if com.IsExist(repoPath) {
+			// repo already exists - We have two or three options.
+			// 1. We fail stating that the directory exists
+			// 2. We create the db repository to go with this data and adopt the git repo
+			// 3. We delete it and start afresh
+			//
+			// Previously Gitea would just delete and start afresh - this was naughty.
+			// So we will now fail and delegate to other functionality to adopt or delete
+			log.Error("Files already exist in %s and we are not going to adopt or delete.", repoPath)
+			return models.ErrRepoFilesAlreadyExist{
+				Uname: u.Name,
+				Name:  repo.Name,
 			}
 		}
-		return nil
-	})
 
-	return repo, err
+		if err := initRepository(ctx, repoPath, doer, repo, opts); err != nil {
+			if err2 := util.RemoveAll(repoPath); err2 != nil {
+				log.Error("initRepository: %v", err)
+				return fmt.Errorf(
+					"delete repo directory %s/%s failed(2): %v", u.Name, repo.Name, err2)
+			}
+			return fmt.Errorf("initRepository: %v", err)
+		}
+
+		// Initialize Issue Labels if selected
+		if len(opts.IssueLabels) > 0 {
+			if err := models.InitializeLabels(ctx, repo.ID, opts.IssueLabels, false); err != nil {
+				if errDelete := models.DeleteRepository(doer, u.ID, repo.ID); errDelete != nil {
+					log.Error("Rollback deleteRepository: %v", errDelete)
+				}
+				return fmt.Errorf("InitializeLabels: %v", err)
+			}
+		}
+
+		if stdout, err := git.NewCommand("update-server-info").
+			SetDescription(fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath)).
+			RunInDir(repoPath); err != nil {
+			log.Error("CreateRepository(git update-server-info) in %v: Stdout: %s\nError: %v", repo, stdout, err)
+			if errDelete := models.DeleteRepository(doer, u.ID, repo.ID); errDelete != nil {
+				log.Error("Rollback deleteRepository: %v", errDelete)
+			}
+			return fmt.Errorf("CreateRepository(git update-server-info): %v", err)
+		}
+		return nil
+	}); err != nil {
+		return nil, err
+	}
+
+	return repo, nil
 }
diff --git a/modules/repository/fork.go b/modules/repository/fork.go
index 169c391ed..cdd08e3d3 100644
--- a/modules/repository/fork.go
+++ b/modules/repository/fork.go
@@ -46,11 +46,21 @@ func ForkRepository(doer, owner *models.User, oldRepo *models.Repository, name,
 	oldRepoPath := oldRepo.RepoPath()
 
 	err = models.WithTx(func(ctx models.DBContext) error {
-		if err = models.CreateRepository(ctx, doer, owner, repo); err != nil {
+		if err = models.CreateRepository(ctx, doer, owner, repo, false); err != nil {
 			return err
 		}
 
+		rollbackRemoveFn := func() {
+			if repo.ID == 0 {
+				return
+			}
+			if errDelete := models.DeleteRepository(doer, owner.ID, repo.ID); errDelete != nil {
+				log.Error("Rollback deleteRepository: %v", errDelete)
+			}
+		}
+
 		if err = models.IncrementRepoForkNum(ctx, oldRepo.ID); err != nil {
+			rollbackRemoveFn()
 			return err
 		}
 
@@ -60,6 +70,7 @@ func ForkRepository(doer, owner *models.User, oldRepo *models.Repository, name,
 			SetDescription(fmt.Sprintf("ForkRepository(git clone): %s to %s", oldRepo.FullName(), repo.FullName())).
 			RunInDirTimeout(10*time.Minute, ""); err != nil {
 			log.Error("Fork Repository (git clone) Failed for %v (from %v):\nStdout: %s\nError: %v", repo, oldRepo, stdout, err)
+			rollbackRemoveFn()
 			return fmt.Errorf("git clone: %v", err)
 		}
 
@@ -67,10 +78,12 @@ func ForkRepository(doer, owner *models.User, oldRepo *models.Repository, name,
 			SetDescription(fmt.Sprintf("ForkRepository(git update-server-info): %s", repo.FullName())).
 			RunInDir(repoPath); err != nil {
 			log.Error("Fork Repository (git update-server-info) failed for %v:\nStdout: %s\nError: %v", repo, stdout, err)
+			rollbackRemoveFn()
 			return fmt.Errorf("git update-server-info: %v", err)
 		}
 
 		if err = createDelegateHooks(repoPath); err != nil {
+			rollbackRemoveFn()
 			return fmt.Errorf("createDelegateHooks: %v", err)
 		}
 		return nil
@@ -86,5 +99,12 @@ func ForkRepository(doer, owner *models.User, oldRepo *models.Repository, name,
 	if err := models.CopyLanguageStat(oldRepo, repo); err != nil {
 		log.Error("Copy language stat from oldRepo failed")
 	}
-	return repo, models.CopyLFS(ctx, repo, oldRepo)
+
+	if err := models.CopyLFS(ctx, repo, oldRepo); err != nil {
+		if errDelete := models.DeleteRepository(doer, owner.ID, repo.ID); errDelete != nil {
+			log.Error("Rollback deleteRepository: %v", errDelete)
+		}
+		return nil, err
+	}
+	return repo, nil
 }
diff --git a/modules/repository/generate.go b/modules/repository/generate.go
index 1314464a6..5d1ef72b6 100644
--- a/modules/repository/generate.go
+++ b/modules/repository/generate.go
@@ -19,6 +19,7 @@ import (
 	"code.gitea.io/gitea/modules/util"
 
 	"github.com/huandu/xstrings"
+	"github.com/unknwon/com"
 )
 
 type transformer struct {
@@ -246,12 +247,19 @@ func GenerateRepository(ctx models.DBContext, doer, owner *models.User, template
 		TrustModel:    templateRepo.TrustModel,
 	}
 
-	if err = models.CreateRepository(ctx, doer, owner, generateRepo); err != nil {
+	if err = models.CreateRepository(ctx, doer, owner, generateRepo, false); err != nil {
 		return nil, err
 	}
 
-	repoPath := models.RepoPath(owner.Name, generateRepo.Name)
-	if err = checkInitRepository(repoPath); err != nil {
+	repoPath := generateRepo.RepoPath()
+	if com.IsExist(repoPath) {
+		return nil, models.ErrRepoFilesAlreadyExist{
+			Uname: generateRepo.OwnerName,
+			Name:  generateRepo.Name,
+		}
+	}
+
+	if err = checkInitRepository(owner.Name, generateRepo.Name); err != nil {
 		return generateRepo, err
 	}
 
diff --git a/modules/repository/init.go b/modules/repository/init.go
index d066544a8..707f8f525 100644
--- a/modules/repository/init.go
+++ b/modules/repository/init.go
@@ -172,10 +172,14 @@ func initRepoCommit(tmpPath string, repo *models.Repository, u *models.User, def
 	return nil
 }
 
-func checkInitRepository(repoPath string) (err error) {
+func checkInitRepository(owner, name string) (err error) {
 	// Somehow the directory could exist.
+	repoPath := models.RepoPath(owner, name)
 	if com.IsExist(repoPath) {
-		return fmt.Errorf("checkInitRepository: path already exists: %s", repoPath)
+		return models.ErrRepoFilesAlreadyExist{
+			Uname: owner,
+			Name:  name,
+		}
 	}
 
 	// Init git bare new repository.
@@ -187,9 +191,85 @@ func checkInitRepository(repoPath string) (err error) {
 	return nil
 }
 
+func adoptRepository(ctx models.DBContext, repoPath string, u *models.User, repo *models.Repository, opts models.CreateRepoOptions) (err error) {
+	if !com.IsExist(repoPath) {
+		return fmt.Errorf("adoptRepository: path does not already exist: %s", repoPath)
+	}
+
+	if err := createDelegateHooks(repoPath); err != nil {
+		return fmt.Errorf("createDelegateHooks: %v", err)
+	}
+
+	// Re-fetch the repository from database before updating it (else it would
+	// override changes that were done earlier with sql)
+	if repo, err = models.GetRepositoryByIDCtx(ctx, repo.ID); err != nil {
+		return fmt.Errorf("getRepositoryByID: %v", err)
+	}
+
+	repo.IsEmpty = false
+	gitRepo, err := git.OpenRepository(repo.RepoPath())
+	if err != nil {
+		return fmt.Errorf("openRepository: %v", err)
+	}
+	defer gitRepo.Close()
+	if len(opts.DefaultBranch) > 0 {
+		repo.DefaultBranch = opts.DefaultBranch
+
+		if err = gitRepo.SetDefaultBranch(repo.DefaultBranch); err != nil {
+			return fmt.Errorf("setDefaultBranch: %v", err)
+		}
+	} else {
+		repo.DefaultBranch, err = gitRepo.GetDefaultBranch()
+		if err != nil {
+			repo.DefaultBranch = setting.Repository.DefaultBranch
+			if err = gitRepo.SetDefaultBranch(repo.DefaultBranch); err != nil {
+				return fmt.Errorf("setDefaultBranch: %v", err)
+			}
+		}
+
+		repo.DefaultBranch = strings.TrimPrefix(repo.DefaultBranch, git.BranchPrefix)
+	}
+	branches, _ := gitRepo.GetBranches()
+	found := false
+	hasDefault := false
+	hasMaster := false
+	for _, branch := range branches {
+		if branch == repo.DefaultBranch {
+			found = true
+			break
+		} else if branch == setting.Repository.DefaultBranch {
+			hasDefault = true
+		} else if branch == "master" {
+			hasMaster = true
+		}
+	}
+	if !found {
+		if hasDefault {
+			repo.DefaultBranch = setting.Repository.DefaultBranch
+		} else if hasMaster {
+			repo.DefaultBranch = "master"
+		} else if len(branches) > 0 {
+			repo.DefaultBranch = branches[0]
+		} else {
+			repo.IsEmpty = true
+			repo.DefaultBranch = setting.Repository.DefaultBranch
+		}
+
+		if err = gitRepo.SetDefaultBranch(repo.DefaultBranch); err != nil {
+			return fmt.Errorf("setDefaultBranch: %v", err)
+		}
+	}
+
+	if err = models.UpdateRepositoryCtx(ctx, repo, false); err != nil {
+		return fmt.Errorf("updateRepository: %v", err)
+	}
+
+	return nil
+}
+
 // InitRepository initializes README and .gitignore if needed.
 func initRepository(ctx models.DBContext, repoPath string, u *models.User, repo *models.Repository, opts models.CreateRepoOptions) (err error) {
-	if err = checkInitRepository(repoPath); err != nil {
+	if err = checkInitRepository(repo.OwnerName, repo.Name); err != nil {
 		return err
 	}
 
@@ -225,7 +305,8 @@ func initRepository(ctx models.DBContext, repoPath string, u *models.User, repo
 		repo.IsEmpty = true
 	}
 
-	repo.DefaultBranch = "master"
+	repo.DefaultBranch = setting.Repository.DefaultBranch
+
 	if len(opts.DefaultBranch) > 0 {
 		repo.DefaultBranch = opts.DefaultBranch
 		gitRepo, err := git.OpenRepository(repo.RepoPath())
diff --git a/modules/setting/repository.go b/modules/setting/repository.go
index 67dd80535..b5764f7fc 100644
--- a/modules/setting/repository.go
+++ b/modules/setting/repository.go
@@ -44,6 +44,8 @@ var (
 		PrefixArchiveFiles                      bool
 		DisableMirrors                          bool
 		DefaultBranch                           string
+		AllowAdoptionOfUnadoptedRepositories    bool
+		AllowDeleteOfUnadoptedRepositories      bool
 
 		// Repository editor settings
 		Editor struct {
@@ -146,6 +148,7 @@ var (
 		DefaultRepoUnits:                        []string{},
 		PrefixArchiveFiles:                      true,
 		DisableMirrors:                          false,
+		DefaultBranch:                           "master",
 
 		// Repository editor settings
 		Editor: struct {
@@ -245,7 +248,7 @@ func newRepository() {
 	Repository.DisableHTTPGit = sec.Key("DISABLE_HTTP_GIT").MustBool()
 	Repository.UseCompatSSHURI = sec.Key("USE_COMPAT_SSH_URI").MustBool()
 	Repository.MaxCreationLimit = sec.Key("MAX_CREATION_LIMIT").MustInt(-1)
-	Repository.DefaultBranch = sec.Key("DEFAULT_BRANCH").MustString("master")
+	Repository.DefaultBranch = sec.Key("DEFAULT_BRANCH").MustString(Repository.DefaultBranch)
 	RepoRootPath = sec.Key("ROOT").MustString(path.Join(homeDir, "gitea-repositories"))
 	forcePathSeparator(RepoRootPath)
 	if !filepath.IsAbs(RepoRootPath) {
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index ea76d4cb6..37d8d7272 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -356,6 +356,10 @@ lang_select_error = Select a language from the list.
 
 username_been_taken = The username is already taken.
 repo_name_been_taken = The repository name is already used.
+repository_files_already_exist = Files already exist for this repository. Contact the system administrator.
+repository_files_already_exist.adopt = Files already exist for this repository and can only be Adopted.
+repository_files_already_exist.delete = Files already exist for this repository. You must delete them.
+repository_files_already_exist.adopt_or_delete = Files already exist for this repository. Either adopt them or delete them.
 visit_rate_limit = Remote visit addressed rate limitation.
 2fa_auth_required = Remote visit required two factors authentication.
 org_name_been_taken = The organization name is already taken.
@@ -682,6 +686,15 @@ pick_reaction = Pick your reaction
 reactions_more = and %d more
 unit_disabled = The site administrator has disabled this repository section.
 language_other = Other
+adopt_search = Enter username to search for unadopted repositories... (leave blank to find all)
+adopt_preexisting_label = Adopt Files
+adopt_preexisting = Adopt pre-existing files
+adopt_preexisting_content = Create repository from %s
+adopt_preexisting_success = Adopted files and created repository from %s
+delete_preexisting_label = Delete
+delete_preexisting = Delete pre-existing files
+delete_preexisting_content = Delete files in %s
+delete_preexisting_success = Deleted unadopted files in %s
 
 desc.private = Private
 desc.public = Public
@@ -2069,6 +2082,8 @@ orgs.members = Members
 orgs.new_orga = New Organization
 
 repos.repo_manage_panel = Repository Management
+repos.unadopted = Unadopted Repositories
+repos.unadopted.no_more = No more unadopted repositories found
 repos.owner = Owner
 repos.name = Name
 repos.private = Private
diff --git a/routers/admin/repos.go b/routers/admin/repos.go
index 39a1d7596..10abaf954 100644
--- a/routers/admin/repos.go
+++ b/routers/admin/repos.go
@@ -5,17 +5,22 @@
 package admin
 
 import (
+	"strings"
+
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/log"
+	"code.gitea.io/gitea/modules/repository"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/routers"
 	repo_service "code.gitea.io/gitea/services/repository"
+	"github.com/unknwon/com"
 )
 
 const (
-	tplRepos base.TplName = "admin/repo/list"
+	tplRepos          base.TplName = "admin/repo/list"
+	tplUnadoptedRepos base.TplName = "admin/repo/unadopted"
 )
 
 // Repos show all the repositories
@@ -50,3 +55,91 @@ func DeleteRepo(ctx *context.Context) {
 		"redirect": setting.AppSubURL + "/admin/repos?page=" + ctx.Query("page") + "&sort=" + ctx.Query("sort"),
 	})
 }
+
+// UnadoptedRepos lists the unadopted repositories
+func UnadoptedRepos(ctx *context.Context) {
+	ctx.Data["Title"] = ctx.Tr("admin.repositories")
+	ctx.Data["PageIsAdmin"] = true
+	ctx.Data["PageIsAdminRepositories"] = true
+
+	opts := models.ListOptions{
+		PageSize: setting.UI.Admin.UserPagingNum,
+		Page:     ctx.QueryInt("page"),
+	}
+
+	if opts.Page <= 0 {
+		opts.Page = 1
+	}
+
+	doSearch := ctx.QueryBool("search")
+
+	ctx.Data["search"] = doSearch
+	q := ctx.Query("q")
+
+	if !doSearch {
+		pager := context.NewPagination(0, opts.PageSize, opts.Page, 5)
+		pager.SetDefaultParams(ctx)
+		ctx.Data["Page"] = pager
+		ctx.HTML(200, tplUnadoptedRepos)
+		return
+	}
+
+	ctx.Data["Keyword"] = q
+	repoNames, count, err := repository.ListUnadoptedRepositories(q, &opts)
+	if err != nil {
+		ctx.ServerError("ListUnadoptedRepositories", err)
+	}
+	ctx.Data["Dirs"] = repoNames
+	pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5)
+	pager.SetDefaultParams(ctx)
+	ctx.Data["Page"] = pager
+	ctx.HTML(200, tplUnadoptedRepos)
+}
+
+// AdoptOrDeleteRepository adopts or deletes a repository
+func AdoptOrDeleteRepository(ctx *context.Context) {
+	dir := ctx.Query("id")
+	action := ctx.Query("action")
+	dirSplit := strings.SplitN(dir, "/", 2)
+	if len(dirSplit) != 2 {
+		ctx.Redirect(setting.AppSubURL + "/admin/repos")
+		return
+	}
+
+	ctxUser, err := models.GetUserByName(dirSplit[0])
+	if err != nil {
+		if models.IsErrUserNotExist(err) {
+			log.Debug("User does not exist: %s", dirSplit[0])
+			ctx.Redirect(setting.AppSubURL + "/admin/repos")
+			return
+		}
+		ctx.ServerError("GetUserByName", err)
+		return
+	}
+
+	repoName := dirSplit[1]
+
+	// check not a repo
+	if has, err := models.IsRepositoryExist(ctxUser, repoName); err != nil {
+		ctx.ServerError("IsRepositoryExist", err)
+		return
+	} else if has || !com.IsDir(models.RepoPath(ctxUser.Name, repoName)) {
+		// Fallthrough to failure mode
+	} else if action == "adopt" {
+		if _, err := repository.AdoptRepository(ctx.User, ctxUser, models.CreateRepoOptions{
+			Name:      dirSplit[1],
+			IsPrivate: true,
+		}); err != nil {
+			ctx.ServerError("repository.AdoptRepository", err)
+			return
+		}
+		ctx.Flash.Success(ctx.Tr("repo.adopt_preexisting_success", dir))
+	} else if action == "delete" {
+		if err := repository.DeleteUnadoptedRepository(ctx.User, ctxUser, dirSplit[1]); err != nil {
+			ctx.ServerError("repository.AdoptRepository", err)
+			return
+		}
+		ctx.Flash.Success(ctx.Tr("repo.delete_preexisting_success", dir))
+	}
+	ctx.Redirect(setting.AppSubURL + "/admin/repos/unadopted")
+}
diff --git a/routers/api/v1/admin/adopt.go b/routers/api/v1/admin/adopt.go
new file mode 100644
index 000000000..1a7a62a55
--- /dev/null
+++ b/routers/api/v1/admin/adopt.go
@@ -0,0 +1,164 @@
+// Copyright 2020 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package admin
+
+import (
+	"fmt"
+	"net/http"
+
+	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/modules/context"
+	"code.gitea.io/gitea/modules/repository"
+	"code.gitea.io/gitea/routers/api/v1/utils"
+	"github.com/unknwon/com"
+)
+
+// ListUnadoptedRepositories lists the unadopted repositories that match the provided names
+func ListUnadoptedRepositories(ctx *context.APIContext) {
+	// swagger:operation GET /admin/unadopted admin adminUnadoptedList
+	// ---
+	// summary: List unadopted repositories
+	// produces:
+	// - application/json
+	// parameters:
+	// - name: page
+	//   in: query
+	//   description: page number of results to return (1-based)
+	//   type: integer
+	// - name: limit
+	//   in: query
+	//   description: page size of results
+	//   type: integer
+	// - name: pattern
+	//   in: query
+	//   description: pattern of repositories to search for
+	//   type: string
+	// responses:
+	//   "200":
+	//     "$ref": "#/responses/StringSlice"
+	//   "403":
+	//     "$ref": "#/responses/forbidden"
+
+	listOptions := utils.GetListOptions(ctx)
+	repoNames, count, err := repository.ListUnadoptedRepositories(ctx.Query("query"), &listOptions)
+	if err != nil {
+		ctx.InternalServerError(err)
+	}
+
+	ctx.Header().Set("X-Total-Count", fmt.Sprintf("%d", count))
+	ctx.Header().Set("Access-Control-Expose-Headers", "X-Total-Count")
+
+	ctx.JSON(http.StatusOK, repoNames)
+}
+
+// AdoptRepository will adopt an unadopted repository
+func AdoptRepository(ctx *context.APIContext) {
+	// swagger:operation POST /admin/unadopted/{owner}/{repo} admin adminAdoptRepository
+	// ---
+	// summary: Adopt unadopted files as a repository
+	// produces:
+	// - application/json
+	// parameters:
+	// - name: owner
+	//   in: path
+	//   description: owner of the repo
+	//   type: string
+	//   required: true
+	// - name: repo
+	//   in: path
+	//   description: name of the repo
+	//   type: string
+	//   required: true
+	// responses:
+	//   "204":
+	//     "$ref": "#/responses/empty"
+	//   "404":
+	//     "$ref": "#/responses/notFound"
+	//   "403":
+	//     "$ref": "#/responses/forbidden"
+	ownerName := ctx.Params(":username")
+	repoName := ctx.Params(":reponame")
+
+	ctxUser, err := models.GetUserByName(ownerName)
+	if err != nil {
+		if models.IsErrUserNotExist(err) {
+			ctx.NotFound()
+			return
+		}
+		ctx.InternalServerError(err)
+		return
+	}
+
+	// check not a repo
+	if has, err := models.IsRepositoryExist(ctxUser, repoName); err != nil {
+		ctx.InternalServerError(err)
+		return
+	} else if has || !com.IsDir(models.RepoPath(ctxUser.Name, repoName)) {
+		ctx.NotFound()
+		return
+	}
+	if _, err := repository.AdoptRepository(ctx.User, ctxUser, models.CreateRepoOptions{
+		Name:      repoName,
+		IsPrivate: true,
+	}); err != nil {
+		ctx.InternalServerError(err)
+		return
+	}
+
+	ctx.Status(http.StatusNoContent)
+}
+
+// DeleteUnadoptedRepository will delete an unadopted repository
+func DeleteUnadoptedRepository(ctx *context.APIContext) {
+	// swagger:operation DELETE /admin/unadopted/{owner}/{repo} admin adminDeleteUnadoptedRepository
+	// ---
+	// summary: Delete unadopted files
+	// produces:
+	// - application/json
+	// parameters:
+	// - name: owner
+	//   in: path
+	//   description: owner of the repo
+	//   type: string
+	//   required: true
+	// - name: repo
+	//   in: path
+	//   description: name of the repo
+	//   type: string
+	//   required: true
+	// responses:
+	//   "204":
+	//     "$ref": "#/responses/empty"
+	//   "403":
+	//     "$ref": "#/responses/forbidden"
+	ownerName := ctx.Params(":username")
+	repoName := ctx.Params(":reponame")
+
+	ctxUser, err := models.GetUserByName(ownerName)
+	if err != nil {
+		if models.IsErrUserNotExist(err) {
+			ctx.NotFound()
+			return
+		}
+		ctx.InternalServerError(err)
+		return
+	}
+
+	// check not a repo
+	if has, err := models.IsRepositoryExist(ctxUser, repoName); err != nil {
+		ctx.InternalServerError(err)
+		return
+	} else if has || !com.IsDir(models.RepoPath(ctxUser.Name, repoName)) {
+		ctx.NotFound()
+		return
+	}
+
+	if err := repository.DeleteUnadoptedRepository(ctx.User, ctxUser, repoName); err != nil {
+		ctx.InternalServerError(err)
+		return
+	}
+
+	ctx.Status(http.StatusNoContent)
+}
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go
index 8b3a7545c..3b6f8dbba 100644
--- a/routers/api/v1/api.go
+++ b/routers/api/v1/api.go
@@ -957,6 +957,11 @@ func RegisterRoutes(m *macaron.Macaron) {
 					m.Post("/repos", bind(api.CreateRepoOption{}), admin.CreateRepo)
 				})
 			})
+			m.Group("/unadopted", func() {
+				m.Get("", admin.ListUnadoptedRepositories)
+				m.Post("/:username/:reponame", admin.AdoptRepository)
+				m.Delete("/:username/:reponame", admin.DeleteUnadoptedRepository)
+			})
 		}, reqToken(), reqSiteAdmin())
 
 		m.Group("/topics", func() {
diff --git a/routers/api/v1/repo/migrate.go b/routers/api/v1/repo/migrate.go
index 019d82031..f9cddbb7c 100644
--- a/routers/api/v1/repo/migrate.go
+++ b/routers/api/v1/repo/migrate.go
@@ -198,6 +198,8 @@ func handleMigrateError(ctx *context.APIContext, repoOwner *models.User, remoteA
 	switch {
 	case models.IsErrRepoAlreadyExist(err):
 		ctx.Error(http.StatusConflict, "", "The repository with the same name already exists.")
+	case models.IsErrRepoFilesAlreadyExist(err):
+		ctx.Error(http.StatusConflict, "", "Files already exist for this repository. Adopt them or delete them.")
 	case migrations.IsRateLimitError(err):
 		ctx.Error(http.StatusUnprocessableEntity, "", "Remote visit addressed rate limitation.")
 	case migrations.IsTwoFactorAuthError(err):
diff --git a/routers/repo/migrate.go b/routers/repo/migrate.go
index 19dbfbab4..9b10970bf 100644
--- a/routers/repo/migrate.go
+++ b/routers/repo/migrate.go
@@ -67,6 +67,18 @@ func handleMigrateError(ctx *context.Context, owner *models.User, err error, nam
 	case models.IsErrRepoAlreadyExist(err):
 		ctx.Data["Err_RepoName"] = true
 		ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tpl, form)
+	case models.IsErrRepoFilesAlreadyExist(err):
+		ctx.Data["Err_RepoName"] = true
+		switch {
+		case ctx.IsUserSiteAdmin() || (setting.Repository.AllowAdoptionOfUnadoptedRepositories && setting.Repository.AllowDeleteOfUnadoptedRepositories):
+			ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.adopt_or_delete"), tpl, form)
+		case setting.Repository.AllowAdoptionOfUnadoptedRepositories:
+			ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.adopt"), tpl, form)
+		case setting.Repository.AllowDeleteOfUnadoptedRepositories:
+			ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.delete"), tpl, form)
+		default:
+			ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist"), tpl, form)
+		}
 	case models.IsErrNameReserved(err):
 		ctx.Data["Err_RepoName"] = true
 		ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), tpl, form)
@@ -159,7 +171,7 @@ func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) {
 		opts.Releases = false
 	}
 
-	err = models.CheckCreateRepository(ctx.User, ctxUser, opts.RepoName)
+	err = models.CheckCreateRepository(ctx.User, ctxUser, opts.RepoName, false)
 	if err != nil {
 		handleMigrateError(ctx, ctxUser, err, "MigratePost", tpl, &form)
 		return
diff --git a/routers/repo/repo.go b/routers/repo/repo.go
index 4a088ff9c..12434747e 100644
--- a/routers/repo/repo.go
+++ b/routers/repo/repo.go
@@ -160,6 +160,18 @@ func handleCreateError(ctx *context.Context, owner *models.User, err error, name
 	case models.IsErrRepoAlreadyExist(err):
 		ctx.Data["Err_RepoName"] = true
 		ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tpl, form)
+	case models.IsErrRepoFilesAlreadyExist(err):
+		ctx.Data["Err_RepoName"] = true
+		switch {
+		case ctx.IsUserSiteAdmin() || (setting.Repository.AllowAdoptionOfUnadoptedRepositories && setting.Repository.AllowDeleteOfUnadoptedRepositories):
+			ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.adopt_or_delete"), tpl, form)
+		case setting.Repository.AllowAdoptionOfUnadoptedRepositories:
+			ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.adopt"), tpl, form)
+		case setting.Repository.AllowDeleteOfUnadoptedRepositories:
+			ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.delete"), tpl, form)
+		default:
+			ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist"), tpl, form)
+		}
 	case models.IsErrNameReserved(err):
 		ctx.Data["Err_RepoName"] = true
 		ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), tpl, form)
diff --git a/routers/repo/setting.go b/routers/repo/setting.go
index d2c20fb03..865dea9bc 100644
--- a/routers/repo/setting.go
+++ b/routers/repo/setting.go
@@ -88,6 +88,18 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
 					ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tplSettingsOptions, &form)
 				case models.IsErrNameReserved(err):
 					ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), tplSettingsOptions, &form)
+				case models.IsErrRepoFilesAlreadyExist(err):
+					ctx.Data["Err_RepoName"] = true
+					switch {
+					case ctx.IsUserSiteAdmin() || (setting.Repository.AllowAdoptionOfUnadoptedRepositories && setting.Repository.AllowDeleteOfUnadoptedRepositories):
+						ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.adopt_or_delete"), tplSettingsOptions, form)
+					case setting.Repository.AllowAdoptionOfUnadoptedRepositories:
+						ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.adopt"), tplSettingsOptions, form)
+					case setting.Repository.AllowDeleteOfUnadoptedRepositories:
+						ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.delete"), tplSettingsOptions, form)
+					default:
+						ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist"), tplSettingsOptions, form)
+					}
 				case models.IsErrNamePatternNotAllowed(err):
 					ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), tplSettingsOptions, &form)
 				default:
diff --git a/routers/routes/routes.go b/routers/routes/routes.go
index 5345a1017..f60af5dad 100644
--- a/routers/routes/routes.go
+++ b/routers/routes/routes.go
@@ -402,6 +402,7 @@ func RegisterRoutes(m *macaron.Macaron) {
 		m.Post("/keys/delete", userSetting.DeleteKey)
 		m.Get("/organization", userSetting.Organization)
 		m.Get("/repos", userSetting.Repos)
+		m.Post("/repos/unadopted", userSetting.AdoptOrDeleteRepository)
 	}, reqSignIn, func(ctx *context.Context) {
 		ctx.Data["PageIsUserSettings"] = true
 		ctx.Data["AllThemes"] = setting.UI.Themes
@@ -461,6 +462,7 @@ func RegisterRoutes(m *macaron.Macaron) {
 
 		m.Group("/repos", func() {
 			m.Get("", admin.Repos)
+			m.Combo("/unadopted").Get(admin.UnadoptedRepos).Post(admin.AdoptOrDeleteRepository)
 			m.Post("/delete", admin.DeleteRepo)
 		})
 
diff --git a/routers/user/setting/adopt.go b/routers/user/setting/adopt.go
new file mode 100644
index 000000000..6ff07d6da
--- /dev/null
+++ b/routers/user/setting/adopt.go
@@ -0,0 +1,56 @@
+// Copyright 2020 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package setting
+
+import (
+	"path/filepath"
+
+	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/modules/context"
+	"code.gitea.io/gitea/modules/repository"
+	"code.gitea.io/gitea/modules/setting"
+	"github.com/unknwon/com"
+)
+
+// AdoptOrDeleteRepository adopts or deletes a repository
+func AdoptOrDeleteRepository(ctx *context.Context) {
+	ctx.Data["Title"] = ctx.Tr("settings")
+	ctx.Data["PageIsSettingsRepos"] = true
+	allowAdopt := ctx.IsUserSiteAdmin() || setting.Repository.AllowAdoptionOfUnadoptedRepositories
+	ctx.Data["allowAdopt"] = allowAdopt
+	allowDelete := ctx.IsUserSiteAdmin() || setting.Repository.AllowDeleteOfUnadoptedRepositories
+	ctx.Data["allowDelete"] = allowDelete
+
+	dir := ctx.Query("id")
+	action := ctx.Query("action")
+
+	ctxUser := ctx.User
+	root := filepath.Join(models.UserPath(ctxUser.LowerName))
+
+	// check not a repo
+	if has, err := models.IsRepositoryExist(ctxUser, dir); err != nil {
+		ctx.ServerError("IsRepositoryExist", err)
+		return
+	} else if has || !com.IsDir(filepath.Join(root, dir+".git")) {
+		// Fallthrough to failure mode
+	} else if action == "adopt" && allowAdopt {
+		if _, err := repository.AdoptRepository(ctxUser, ctxUser, models.CreateRepoOptions{
+			Name:      dir,
+			IsPrivate: true,
+		}); err != nil {
+			ctx.ServerError("repository.AdoptRepository", err)
+			return
+		}
+		ctx.Flash.Success(ctx.Tr("repo.adopt_preexisting_success", dir))
+	} else if action == "delete" && allowDelete {
+		if err := repository.DeleteUnadoptedRepository(ctxUser, ctxUser, dir); err != nil {
+			ctx.ServerError("repository.AdoptRepository", err)
+			return
+		}
+		ctx.Flash.Success(ctx.Tr("repo.delete_preexisting_success", dir))
+	}
+
+	ctx.Redirect(setting.AppSubURL + "/user/settings/repos")
+}
diff --git a/routers/user/setting/profile.go b/routers/user/setting/profile.go
index ba9ba2b25..fe0506946 100644
--- a/routers/user/setting/profile.go
+++ b/routers/user/setting/profile.go
@@ -9,6 +9,8 @@ import (
 	"errors"
 	"fmt"
 	"io/ioutil"
+	"os"
+	"path/filepath"
 	"strings"
 
 	"code.gitea.io/gitea/models"
@@ -197,32 +199,96 @@ func Organization(ctx *context.Context) {
 func Repos(ctx *context.Context) {
 	ctx.Data["Title"] = ctx.Tr("settings")
 	ctx.Data["PageIsSettingsRepos"] = true
-	ctxUser := ctx.User
+	ctx.Data["allowAdopt"] = ctx.IsUserSiteAdmin() || setting.Repository.AllowAdoptionOfUnadoptedRepositories
+	ctx.Data["allowDelete"] = ctx.IsUserSiteAdmin() || setting.Repository.AllowDeleteOfUnadoptedRepositories
 
-	var err error
-	if err = ctxUser.GetRepositories(models.ListOptions{Page: 1, PageSize: setting.UI.User.RepoPagingNum}); err != nil {
-		ctx.ServerError("GetRepositories", err)
-		return
+	opts := models.ListOptions{
+		PageSize: setting.UI.Admin.UserPagingNum,
+		Page:     ctx.QueryInt("page"),
 	}
-	repos := ctxUser.Repos
 
-	for i := range repos {
-		if repos[i].IsFork {
-			err := repos[i].GetBaseRepo()
+	if opts.Page <= 0 {
+		opts.Page = 1
+	}
+	start := (opts.Page - 1) * opts.PageSize
+	end := start + opts.PageSize
+
+	adoptOrDelete := ctx.IsUserSiteAdmin() || (setting.Repository.AllowAdoptionOfUnadoptedRepositories && setting.Repository.AllowDeleteOfUnadoptedRepositories)
+
+	ctxUser := ctx.User
+	count := 0
+
+	if adoptOrDelete {
+		repoNames := make([]string, 0, setting.UI.Admin.UserPagingNum)
+		repos := map[string]*models.Repository{}
+		// We're going to iterate by pagesize.
+		root := filepath.Join(models.UserPath(ctxUser.Name))
+		if err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
 			if err != nil {
-				ctx.ServerError("GetBaseRepo", err)
-				return
+				return err
 			}
-			err = repos[i].BaseRepo.GetOwner()
-			if err != nil {
-				ctx.ServerError("GetOwner", err)
-				return
+			if !info.IsDir() || path == root {
+				return nil
+			}
+			name := info.Name()
+			if !strings.HasSuffix(name, ".git") {
+				return filepath.SkipDir
+			}
+			name = name[:len(name)-4]
+			if models.IsUsableRepoName(name) != nil || strings.ToLower(name) != name {
+				return filepath.SkipDir
+			}
+			if count >= start && count < end {
+				repoNames = append(repoNames, name)
+			}
+			count++
+			return filepath.SkipDir
+		}); err != nil {
+			ctx.ServerError("filepath.Walk", err)
+			return
+		}
+
+		if err := ctxUser.GetRepositories(models.ListOptions{Page: 1, PageSize: setting.UI.Admin.UserPagingNum}, repoNames...); err != nil {
+			ctx.ServerError("GetRepositories", err)
+			return
+		}
+		for _, repo := range ctxUser.Repos {
+			if repo.IsFork {
+				if err := repo.GetBaseRepo(); err != nil {
+					ctx.ServerError("GetBaseRepo", err)
+					return
+				}
+			}
+			repos[repo.LowerName] = repo
+		}
+		ctx.Data["Dirs"] = repoNames
+		ctx.Data["ReposMap"] = repos
+	} else {
+		var err error
+		var count64 int64
+		ctxUser.Repos, count64, err = models.GetUserRepositories(&models.SearchRepoOptions{Actor: ctxUser, Private: true, ListOptions: opts})
+
+		if err != nil {
+			ctx.ServerError("GetRepositories", err)
+			return
+		}
+		count = int(count64)
+		repos := ctxUser.Repos
+
+		for i := range repos {
+			if repos[i].IsFork {
+				if err := repos[i].GetBaseRepo(); err != nil {
+					ctx.ServerError("GetBaseRepo", err)
+					return
+				}
 			}
 		}
+
+		ctx.Data["Repos"] = repos
 	}
-
 	ctx.Data["Owner"] = ctxUser
-	ctx.Data["Repos"] = repos
-
+	pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5)
+	pager.SetDefaultParams(ctx)
+	ctx.Data["Page"] = pager
 	ctx.HTML(200, tplSettingsRepositories)
 }
diff --git a/services/repository/generate.go b/services/repository/generate.go
index 95e5cdc6c..067f8f61d 100644
--- a/services/repository/generate.go
+++ b/services/repository/generate.go
@@ -64,7 +64,7 @@ func GenerateRepository(doer, owner *models.User, templateRepo *models.Repositor
 
 		return nil
 	}); err != nil {
-		if generateRepo != nil {
+		if generateRepo != nil && generateRepo.ID > 0 {
 			if errDelete := models.DeleteRepository(doer, owner.ID, generateRepo.ID); errDelete != nil {
 				log.Error("Rollback deleteRepository: %v", errDelete)
 			}
diff --git a/services/repository/repository.go b/services/repository/repository.go
index 77c8728d9..c6768f3f0 100644
--- a/services/repository/repository.go
+++ b/services/repository/repository.go
@@ -18,11 +18,7 @@ import (
 func CreateRepository(doer, owner *models.User, opts models.CreateRepoOptions) (*models.Repository, error) {
 	repo, err := repo_module.CreateRepository(doer, owner, opts)
 	if err != nil {
-		if repo != nil {
-			if errDelete := models.DeleteRepository(doer, owner.ID, repo.ID); errDelete != nil {
-				log.Error("Rollback deleteRepository: %v", errDelete)
-			}
-		}
+		// No need to rollback here we should do this in CreateRepository...
 		return nil, err
 	}
 
@@ -31,15 +27,28 @@ func CreateRepository(doer, owner *models.User, opts models.CreateRepoOptions) (
 	return repo, nil
 }
 
+// AdoptRepository adopts pre-existing repository files for the user/organization.
+func AdoptRepository(doer, owner *models.User, opts models.CreateRepoOptions) (*models.Repository, error) {
+	repo, err := repo_module.AdoptRepository(doer, owner, opts)
+	if err != nil {
+		// No need to rollback here we should do this in AdoptRepository...
+		return nil, err
+	}
+
+	notification.NotifyCreateRepository(doer, owner, repo)
+
+	return repo, nil
+}
+
+// DeleteUnadoptedRepository adopts pre-existing repository files for the user/organization.
+func DeleteUnadoptedRepository(doer, owner *models.User, name string) error {
+	return repo_module.DeleteUnadoptedRepository(doer, owner, name)
+}
+
 // ForkRepository forks a repository
 func ForkRepository(doer, u *models.User, oldRepo *models.Repository, name, desc string) (*models.Repository, error) {
 	repo, err := repo_module.ForkRepository(doer, u, oldRepo, name, desc)
 	if err != nil {
-		if repo != nil {
-			if errDelete := models.DeleteRepository(doer, u.ID, repo.ID); errDelete != nil {
-				log.Error("Rollback deleteRepository: %v", errDelete)
-			}
-		}
 		return nil, err
 	}
 
diff --git a/templates/admin/repo/list.tmpl b/templates/admin/repo/list.tmpl
index 4c3b77dcf..51e329e03 100644
--- a/templates/admin/repo/list.tmpl
+++ b/templates/admin/repo/list.tmpl
@@ -5,6 +5,9 @@
 		{{template "base/alert" .}}
 		<h4 class="ui top attached header">
 			{{.i18n.Tr "admin.repos.repo_manage_panel"}} ({{.i18n.Tr "admin.total" .Total}})
+			<div class="ui right">
+				<a class="ui blue tiny button" href="{{AppSubUrl}}/admin/repos/unadopted">{{.i18n.Tr "admin.repos.unadopted"}}</a>
+            </div>
 		</h4>
 		<div class="ui attached segment">
 			{{template "admin/repo/search" .}}
diff --git a/templates/admin/repo/unadopted.tmpl b/templates/admin/repo/unadopted.tmpl
new file mode 100644
index 000000000..7a046c602
--- /dev/null
+++ b/templates/admin/repo/unadopted.tmpl
@@ -0,0 +1,98 @@
+{{template "base/head" .}}
+<div class="admin user">
+	{{template "admin/navbar" .}}
+	<div class="ui container">
+		{{template "base/alert" .}}
+		<h4 class="ui top attached header">
+			{{.i18n.Tr "admin.repos.unadopted"}}
+            <div class="ui right">
+                <a class="ui blue tiny button" href="{{AppSubUrl}}/admin/repos">{{.i18n.Tr "admin.repos.repo_manage_panel"}}</a>
+            </div>
+		</h4>
+        <div class="ui attached segment">
+            <form class="ui form ignore-dirty">
+                <div class="ui fluid action input">
+                <input name="search" value="true" type="hidden">
+                <input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "repo.adopt_search"}}" autofocus>
+                <button class="ui blue button">{{.i18n.Tr "explore.search"}}</button>
+                </div>
+            </form>
+		</div>
+        {{if .search}}
+            <div class="ui attached segment settings">
+                {{if .Dirs}}
+                    <div class="ui middle aligned divided list">
+                        {{range $dirI, $dir := .Dirs}}
+                            <div class="item">
+                                <div class="content">
+                                    <span class="icon">{{svg "octicon-file-directory"}}</span>
+                                    <span class="name">{{$dir}}</span>
+                                    <div class="right floated content">
+                                        <button class="ui button submit tiny green adopt show-modal" data-modal="#adopt-unadopted-modal-{{$dirI}}"><span class="icon">{{svg "octicon-plus"}}</span><span class="label">{{$.i18n.Tr "repo.adopt_preexisting_label"}}</span></button>
+                                        <div class="ui basic modal" id="adopt-unadopted-modal-{{$dirI}}">
+                                            <i class="close icon"></i>
+                                            <div class="header">
+                                                <span class="label">{{$.i18n.Tr "repo.adopt_preexisting"}}</span>
+                                            </div>
+                                            <div class="content">
+                                                <p>{{$.i18n.Tr "repo.adopt_preexisting_content" $dir}}</p>
+                                            </div>
+                                            <form class="ui form" method="POST" action="{{AppSubUrl}}/admin/repos/unadopted">
+                                                {{$.CsrfTokenHtml}}
+                                                <input type="hidden" name="id" value="{{$dir}}">
+                                                <input type="hidden" name="action" value="adopt">
+                                                <div class="actions">
+                                                    <div class="ui red basic inverted cancel button">
+                                                        <i class="remove icon"></i>
+                                                        {{$.i18n.Tr "modal.no"}}
+                                                    </div>
+                                                    <button class="ui green basic inverted ok button">
+                                                        <i class="checkmark icon"></i>
+                                                        {{$.i18n.Tr "modal.yes"}}
+                                                    </button>
+                                                </div>
+                                            </form>
+                                        </div>
+                                        <button class="ui button submit tiny red delete show-modal" data-modal="#delete-unadopted-modal-{{$dirI}}"><span class="icon">{{svg "octicon-x"}}</span><span class="label">{{$.i18n.Tr "repo.delete_preexisting_label"}}</span></button>
+                                        <div class="ui basic modal" id="delete-unadopted-modal-{{$dirI}}">
+                                            <i class="close icon"></i>
+                                            <div class="header">
+                                                <span class="label">{{$.i18n.Tr "repo.delete_preexisting"}}</span>
+                                            </div>
+                                            <div class="content">
+                                                <p>{{$.i18n.Tr "repo.delete_preexisting_content" $dir}}</p>
+                                            </div>
+                                            <form class="ui form" method="POST" action="{{AppSubUrl}}/admin/repos/unadopted">
+                                                {{$.CsrfTokenHtml}}
+                                                <input type="hidden" name="id" value="{{$dir}}">
+                                                <input type="hidden" name="action" value="delete">
+                                                <div class="actions">
+                                                    <div class="ui red basic inverted cancel button">
+                                                        <i class="remove icon"></i>
+                                                        {{$.i18n.Tr "modal.no"}}
+                                                    </div>
+                                                    <button class="ui green basic inverted ok button">
+                                                        <i class="checkmark icon"></i>
+                                                        {{$.i18n.Tr "modal.yes"}}
+                                                    </button>
+                                                </div>
+                                            </form>
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
+                        {{end}}
+                    </div>
+                    {{template "base/paginate" .}}
+                {{else}}
+                    <div class="item">
+                        {{.i18n.Tr "admin.repos.unadopted.no_more"}}
+                    </div>
+                    {{template "base/paginate" .}}
+                {{end}}
+            </div>
+        {{end}}
+    </div>
+</div>
+
+{{template "base/footer" .}}
diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl
index c1847f044..e38344893 100644
--- a/templates/swagger/v1_json.tmpl
+++ b/templates/swagger/v1_json.tmpl
@@ -120,6 +120,119 @@
         }
       }
     },
+    "/admin/unadopted": {
+      "get": {
+        "produces": [
+          "application/json"
+        ],
+        "tags": [
+          "admin"
+        ],
+        "summary": "List unadopted repositories",
+        "operationId": "adminUnadoptedList",
+        "parameters": [
+          {
+            "type": "integer",
+            "description": "page number of results to return (1-based)",
+            "name": "page",
+            "in": "query"
+          },
+          {
+            "type": "integer",
+            "description": "page size of results",
+            "name": "limit",
+            "in": "query"
+          },
+          {
+            "type": "string",
+            "description": "pattern of repositories to search for",
+            "name": "pattern",
+            "in": "query"
+          }
+        ],
+        "responses": {
+          "200": {
+            "$ref": "#/responses/StringSlice"
+          },
+          "403": {
+            "$ref": "#/responses/forbidden"
+          }
+        }
+      }
+    },
+    "/admin/unadopted/{owner}/{repo}": {
+      "post": {
+        "produces": [
+          "application/json"
+        ],
+        "tags": [
+          "admin"
+        ],
+        "summary": "Adopt unadopted files as a repository",
+        "operationId": "adminAdoptRepository",
+        "parameters": [
+          {
+            "type": "string",
+            "description": "owner of the repo",
+            "name": "owner",
+            "in": "path",
+            "required": true
+          },
+          {
+            "type": "string",
+            "description": "name of the repo",
+            "name": "repo",
+            "in": "path",
+            "required": true
+          }
+        ],
+        "responses": {
+          "204": {
+            "$ref": "#/responses/empty"
+          },
+          "403": {
+            "$ref": "#/responses/forbidden"
+          },
+          "404": {
+            "$ref": "#/responses/notFound"
+          }
+        }
+      },
+      "delete": {
+        "produces": [
+          "application/json"
+        ],
+        "tags": [
+          "admin"
+        ],
+        "summary": "Delete unadopted files",
+        "operationId": "adminDeleteUnadoptedRepository",
+        "parameters": [
+          {
+            "type": "string",
+            "description": "owner of the repo",
+            "name": "owner",
+            "in": "path",
+            "required": true
+          },
+          {
+            "type": "string",
+            "description": "name of the repo",
+            "name": "repo",
+            "in": "path",
+            "required": true
+          }
+        ],
+        "responses": {
+          "204": {
+            "$ref": "#/responses/empty"
+          },
+          "403": {
+            "$ref": "#/responses/forbidden"
+          }
+        }
+      }
+    },
     "/admin/users": {
       "get": {
         "produces": [
diff --git a/templates/user/settings/repos.tmpl b/templates/user/settings/repos.tmpl
index 8d9065ec6..456647d9b 100644
--- a/templates/user/settings/repos.tmpl
+++ b/templates/user/settings/repos.tmpl
@@ -7,34 +7,134 @@
 			{{.i18n.Tr "settings.repos"}}
 		</h4>
 		<div class="ui attached segment">
-			{{if .Repos}}
-				<div class="ui middle aligned divided list">
-					{{range .Repos}}
-					<div class="item">
-						<div class="content">
-							{{if .IsPrivate}}
-								<span class="text gold iconFloat">{{svg "octicon-lock"}}</span>
-							{{else if .IsFork}}
-								<span class="iconFloat">{{svg "octicon-repo-forked"}}</span>
-							{{else if .IsMirror}}
-								<span class="iconFloat">{{svg "octicon-mirror"}}</span>
-							{{else}}
-								<span class="iconFloat">{{svg "octicon-repo"}}</span>
-							{{end}}
-							<a class="name" href="{{AppSubUrl}}/{{$.Owner.Name}}/{{.Name}}">{{$.Owner.Name}}/{{.Name}}</a>
-							<span>{{SizeFmt .Size}}</span>
-							{{if .IsFork}}
-								{{$.i18n.Tr "repo.forked_from"}}
-								<span><a href="{{AppSubUrl}}/{{.BaseRepo.Owner.Name}}/{{.BaseRepo.Name}}">{{.BaseRepo.Owner.Name}}/{{.BaseRepo.Name}}</a></span>
-							{{end}}
+			{{if or .allowAdopt .allowDelete}}
+				{{if .Dirs}}
+					<div class="ui middle aligned divided list">
+						{{range $dirI, $dir := .Dirs}}
+							{{ $repo := index $.ReposMap $dir}}
+							<div class="item">
+								<div class="content">
+									{{if $repo}}
+										{{if $repo.IsPrivate}}
+											<span class="text gold icon">{{svg "octicon-lock"}}</span>
+										{{else if $repo.IsFork}}
+											<span class="icon">{{svg "octicon-repo-forked"}}</span>
+										{{else if $repo.IsMirror}}
+											<span class="icon">{{svg "octicon-mirror"}}</span>
+										{{else if $repo.IsTemplate}}
+											<span class="icon">{{svg "octicon-repo-template"}}</span>
+										{{else}}
+											<span class="icon">{{svg "octicon-repo"}}</span>
+										{{end}}
+										<a class="name" href="{{AppSubUrl}}/{{$repo.OwnerName}}/{{$repo.Name}}">{{$repo.OwnerName}}/{{$repo.Name}}</a>
+										<span>{{SizeFmt $repo.Size}}</span>
+										{{if $repo.IsFork}}
+											{{$.i18n.Tr "repo.forked_from"}}
+											<span><a href="{{AppSubUrl}}/{{$repo.BaseRepo.OwnerName}}/{{$repo.BaseRepo.Name}}">{{$repo.BaseRepo.OwnerName}}/{{$repo.BaseRepo.Name}}</a></span>
+										{{end}}
+									{{else}}
+										<span class="icon">{{svg "octicon-file-directory"}}</span>
+										<span class="name">{{$.Owner.Name}}/{{$dir}}</span>
+        		                        <div class="right floated content">
+											{{if $.allowAdopt}}
+												<button class="ui button submit tiny green adopt show-modal" data-modal="#adopt-unadopted-modal-{{$dirI}}"><span class="icon">{{svg "octicon-plus"}}</span><span class="label">{{$.i18n.Tr "repo.adopt_preexisting_label"}}</span></button>
+												<div class="ui basic modal" id="adopt-unadopted-modal-{{$dirI}}">
+													<i class="close icon"></i>
+													<div class="header">
+														<span class="label">{{$.i18n.Tr "repo.adopt_preexisting"}}</span>
+													</div>
+													<div class="content">
+														<p>{{$.i18n.Tr "repo.adopt_preexisting_content" $dir}}</p>
+													</div>
+													<form class="ui form" method="POST" action="{{AppSubUrl}}/user/settings/repos/unadopted">
+														{{$.CsrfTokenHtml}}
+														<input type="hidden" name="id" value="{{$dir}}">
+														<input type="hidden" name="action" value="adopt">
+														<div class="actions">
+															<div class="ui red basic inverted cancel button">
+																<i class="remove icon"></i>
+																{{$.i18n.Tr "modal.no"}}
+															</div>
+															<button class="ui green basic inverted ok button">
+																<i class="checkmark icon"></i>
+																{{$.i18n.Tr "modal.yes"}}
+															</button>
+														</div>
+													</form>
+												</div>
+											{{end}}
+											{{if $.allowDelete}}
+												<button class="ui button submit tiny red delete show-modal" data-modal="#delete-unadopted-modal-{{$dirI}}"><span class="icon">{{svg "octicon-x"}}</span><span class="label">{{$.i18n.Tr "repo.delete_preexisting_label"}}</span></button>
+												<div class="ui basic modal" id="delete-unadopted-modal-{{$dirI}}">
+													<i class="close icon"></i>
+													<div class="header">
+														<span class="label">{{$.i18n.Tr "repo.delete_preexisting"}}</span>
+													</div>
+													<div class="content">
+														<p>{{$.i18n.Tr "repo.delete_preexisting_content" $dir}}</p>
+													</div>
+													<form class="ui form" method="POST" action="{{AppSubUrl}}/user/settings/repos/unadopted">
+														{{$.CsrfTokenHtml}}
+														<input type="hidden" name="id" value="{{$dir}}">
+														<input type="hidden" name="action" value="delete">
+														<div class="actions">
+															<div class="ui red basic inverted cancel button">
+																<i class="remove icon"></i>
+																{{$.i18n.Tr "modal.no"}}
+															</div>
+															<button class="ui green basic inverted ok button">
+																<i class="checkmark icon"></i>
+																{{$.i18n.Tr "modal.yes"}}
+															</button>
+														</div>
+													</form>
+												</div>
+											{{end}}
+										</div>
+									{{end}}
+								</div>
 							</div>
-						</div>
-					{{end}}
-				</div>
+						{{end}}
+					</div>
+					{{template "base/paginate" .}}
+				{{else}}
+					<div class="item">
+						{{.i18n.Tr "settings.repos_none"}}
+					</div>
+				{{end}}
 			{{else}}
-				<div class="item">
-					{{.i18n.Tr "settings.repos_none"}}
-				</div>
+				{{if .Repos}}
+					<div class="ui middle aligned divided list">
+						{{range .Repos}}
+							<div class="item">
+								<div class="content">
+									{{if .IsPrivate}}
+										<span class="text gold iconFloat">{{svg "octicon-lock"}}</span>
+									{{else if .IsFork}}
+										<span class="iconFloat">{{svg "octicon-repo-forked"}}</span>
+									{{else if .IsMirror}}
+										<span class="iconFloat">{{svg "octicon-mirror"}}</span>
+									{{else if .IsTemplate}}
+										<span class="iconFloat">{{svg "octicon-repo-template"}}</span>
+									{{else}}
+										<span class="iconFloat">{{svg "octicon-repo"}}</span>
+									{{end}}
+									<a class="name" href="{{AppSubUrl}}/{{$.OwnerName}}/{{.Name}}">{{$.OwnerName}}/{{.Name}}</a>
+									<span>{{SizeFmt .Size}}</span>
+									{{if .IsFork}}
+										{{$.i18n.Tr "repo.forked_from"}}
+										<span><a href="{{AppSubUrl}}/{{.BaseRepo.OwnerName}}/{{.BaseRepo.Name}}">{{.BaseRepo.OwnerName}}/{{.BaseRepo.Name}}</a></span>
+									{{end}}
+								</div>
+							</div>
+						{{end}}
+					</div>
+					{{template "base/paginate" .}}
+				{{else}}
+					<div class="item">
+						{{.i18n.Tr "settings.repos_none"}}
+					</div>
+				{{end}}
 			{{end}}
 		</div>
 	</div>
diff --git a/web_src/less/_admin.less b/web_src/less/_admin.less
index 29afe96b0..052c29dd6 100644
--- a/web_src/less/_admin.less
+++ b/web_src/less/_admin.less
@@ -30,6 +30,16 @@
     form tbody button[type='submit'] {
       padding: 5px 8px;
     }
+
+  }
+
+  .settings .button.adopt,
+  .settings .button.delete {
+    margin-top: -15px;
+    margin-bottom: -15px;
+    .label {
+      vertical-align: middle;
+    }
   }
 
   .ui.header,
diff --git a/web_src/less/_user.less b/web_src/less/_user.less
index 0b983a382..fcc5c0290 100644
--- a/web_src/less/_user.less
+++ b/web_src/less/_user.less
@@ -135,6 +135,15 @@
     }
   }
 
+  .button.adopt,
+  .button.delete {
+    margin-top: -15px;
+    margin-bottom: -15px;
+    .label {
+      vertical-align: middle;
+    }
+  }
+
   &.link-account:not(.icon) {
     padding-top: 15px;
     padding-bottom: 5px;