From 30ee9c70e81d186d2c98005e153cbc10c0f1d33d Mon Sep 17 00:00:00 2001
From: a1012112796 <1012112796@qq.com>
Date: Fri, 14 May 2021 17:58:51 +0800
Subject: [PATCH 1/8] Add a simple way to rename branch like gh
- update default branch if needed
- Update protected branch if needed
- Update all not merged pull request base branch name
- rename git branch
- record this rename work and auto redirect for old branch
on ui
Signed-off-by: a1012112796 <1012112796@qq.com>
---
models/branches.go | 97 ++++++++++++++++++++++++
models/branches_test.go | 49 ++++++++++++
models/fixtures/renamed_branch.yml | 5 ++
models/migrations/migrations.go | 2 +
models/migrations/v180.go | 19 +++++
models/models.go | 1 +
modules/context/repo.go | 73 +++++++++++++-----
modules/git/repo_branch.go | 6 ++
options/locale/locale_en-US.ini | 7 ++
routers/repo/setting_protected_branch.go | 58 ++++++++++++++
routers/routes/web.go | 1 +
services/forms/repo_branch_form.go | 12 +++
templates/repo/settings/branches.tmpl | 22 ++++++
13 files changed, 333 insertions(+), 19 deletions(-)
create mode 100644 models/fixtures/renamed_branch.yml
create mode 100644 models/migrations/v180.go
diff --git a/models/branches.go b/models/branches.go
index 1ac1fa49e580..cf15266d45c3 100644
--- a/models/branches.go
+++ b/models/branches.go
@@ -596,3 +596,100 @@ func RemoveOldDeletedBranches(ctx context.Context, olderThan time.Duration) {
log.Error("DeletedBranchesCleanup: %v", err)
}
}
+
+// RenamedBranch proivde renamed branch log
+// will check it when an branch can't be found
+type RenamedBranch struct {
+ ID int64 `xorm:"pk autoincr"`
+ RepoID int64 `xorm:"INDEX NOT NULL"`
+ From string
+ To string
+}
+
+// FindRenamedBranch check if a branch was renamed
+func FindRenamedBranch(repoID int64, from string) (branch *RenamedBranch, exist bool, err error) {
+ branch = &RenamedBranch{
+ RepoID: repoID,
+ From: from,
+ }
+ exist, err = x.Get(branch)
+
+ return
+}
+
+// RenameBranch rename a branch
+func (repo *Repository) RenameBranch(from, to string, gitAction func(isDefault bool) error) (err error) {
+ sess := x.NewSession()
+ defer sess.Close()
+ if err := sess.Begin(); err != nil {
+ return err
+ }
+
+ // 1. update default branch if needed
+ isDefault := repo.DefaultBranch == from
+ if isDefault {
+ repo.DefaultBranch = to
+ _, err = sess.Cols("default_branch").Update(repo)
+ if err != nil {
+ return err
+ }
+ }
+
+ // 2. Update protected branch if needed
+ protectedBranch, err := getProtectedBranchBy(sess, repo.ID, from)
+ if err != nil {
+ if err2 := sess.Rollback(); err2 != nil {
+ log.Error("RenameBranch: sess.Rollback: %v", err2)
+ }
+ return err
+ }
+
+ if protectedBranch != nil {
+ protectedBranch.BranchName = to
+ _, err = sess.Cols("branch_name").Update(protectedBranch)
+ if err != nil {
+ if err2 := sess.Rollback(); err2 != nil {
+ log.Error("RenameBranch: sess.Rollback: %v", err2)
+ }
+ return err
+ }
+ }
+
+ // 3. Update all not merged pull request base branch name
+ _, err = sess.Table(new(PullRequest)).Where("base_repo_id=? AND base_branch=? AND has_merged=?",
+ repo.ID, from, false).
+ Update(map[string]interface{}{"base_branch": to})
+ if err != nil {
+ if err2 := sess.Rollback(); err2 != nil {
+ log.Error("RenameBranch: sess.Rollback: %v", err2)
+ }
+ return err
+ }
+
+ // 4. do git action
+ if err = gitAction(isDefault); err != nil {
+ if err2 := sess.Rollback(); err2 != nil {
+ log.Error("RenameBranch: sess.Rollback: %v", err2)
+ }
+
+ return err
+ }
+
+ // 5. insert renamed branch record
+ renamedBranch := &RenamedBranch{
+ RepoID: repo.ID,
+ From: from,
+ To: to,
+ }
+
+ _, err = sess.Insert(renamedBranch)
+ if err != nil {
+ if err2 := sess.Rollback(); err2 != nil {
+ log.Error("RenameBranch: sess.Rollback: %v", err2)
+ }
+
+ return err
+ }
+
+ return sess.Commit()
+}
diff --git a/models/branches_test.go b/models/branches_test.go
index b7984331edb1..acbc99639cc4 100644
--- a/models/branches_test.go
+++ b/models/branches_test.go
@@ -78,3 +78,52 @@ func getDeletedBranch(t *testing.T, branch *DeletedBranch) *DeletedBranch {
return deletedBranch
}
+
+func TestFindRenamedBranch(t *testing.T) {
+ assert.NoError(t, PrepareTestDatabase())
+ branch, exist, err := FindRenamedBranch(1, "dev")
+ assert.NoError(t, err)
+ assert.Equal(t, true, exist)
+ assert.Equal(t, "master", branch.To)
+
+ _, exist, err = FindRenamedBranch(1, "unknow")
+ assert.NoError(t, err)
+ assert.Equal(t, false, exist)
+}
+
+func TestRenameBranch(t *testing.T) {
+ assert.NoError(t, PrepareTestDatabase())
+ repo1 := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
+ _isDefault := false
+
+ err := UpdateProtectBranch(repo1, &ProtectedBranch{
+ RepoID: repo1.ID,
+ BranchName: "master",
+ }, WhitelistOptions{})
+ assert.NoError(t, err)
+
+ assert.NoError(t, repo1.RenameBranch("master", "main", func(isDefault bool) error {
+ _isDefault = isDefault
+ return nil
+ }))
+
+ assert.Equal(t, true, _isDefault)
+ repo1 = AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
+ assert.Equal(t, "main", repo1.DefaultBranch)
+
+ pull := AssertExistsAndLoadBean(t, &PullRequest{ID: 1}).(*PullRequest) // merged
+ assert.Equal(t, "master", pull.BaseBranch)
+
+ pull = AssertExistsAndLoadBean(t, &PullRequest{ID: 2}).(*PullRequest) // open
+ assert.Equal(t, "main", pull.BaseBranch)
+
+ renamedBranch := AssertExistsAndLoadBean(t, &RenamedBranch{ID: 2}).(*RenamedBranch)
+ assert.Equal(t, "master", renamedBranch.From)
+ assert.Equal(t, "main", renamedBranch.To)
+ assert.Equal(t, int64(1), renamedBranch.RepoID)
+
+ AssertExistsAndLoadBean(t, &ProtectedBranch{
+ RepoID: repo1.ID,
+ BranchName: "main",
+ })
+}
diff --git a/models/fixtures/renamed_branch.yml b/models/fixtures/renamed_branch.yml
new file mode 100644
index 000000000000..efa5130a2b9e
--- /dev/null
+++ b/models/fixtures/renamed_branch.yml
@@ -0,0 +1,5 @@
+-
+ id: 1
+ repo_id: 1
+ from: dev
+ to: master
diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go
index c54c383fb810..0dc4f597d55e 100644
--- a/models/migrations/migrations.go
+++ b/models/migrations/migrations.go
@@ -309,6 +309,8 @@ var migrations = []Migration{
NewMigration("Add LFS columns to Mirror", addLFSMirrorColumns),
// v179 -> v180
NewMigration("Convert avatar url to text", convertAvatarURLToText),
+ // v180 -> v181
+ NewMigration("Add renamed_branch table", addRenamedBranchTable),
}
// GetCurrentDBVersion returns the current db version
diff --git a/models/migrations/v180.go b/models/migrations/v180.go
new file mode 100644
index 000000000000..7fbd091f9c12
--- /dev/null
+++ b/models/migrations/v180.go
@@ -0,0 +1,19 @@
+// Copyright 2021 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 migrations
+
+import (
+ "xorm.io/xorm"
+)
+
+func addRenamedBranchTable(x *xorm.Engine) error {
+ type RenamedBranch struct {
+ ID int64 `xorm:"pk autoincr"`
+ RepoID int64 `xorm:"INDEX NOT NULL"`
+ From string
+ To string
+ }
+ return x.Sync2(new(RenamedBranch))
+}
diff --git a/models/models.go b/models/models.go
index b0a9062566ee..921af19da8d6 100644
--- a/models/models.go
+++ b/models/models.go
@@ -134,6 +134,7 @@ func init() {
new(ProjectIssue),
new(Session),
new(RepoTransfer),
+ new(RenamedBranch),
)
gonicNames := []string{"SSL", "UID"}
diff --git a/modules/context/repo.go b/modules/context/repo.go
index 3e48b34b3d16..e1e8deab0aa2 100644
--- a/modules/context/repo.go
+++ b/modules/context/repo.go
@@ -49,23 +49,25 @@ type PullRequest struct {
// Repository contains information to operate a repository
type Repository struct {
models.Permission
- IsWatching bool
- IsViewBranch bool
- IsViewTag bool
- IsViewCommit bool
- Repository *models.Repository
- Owner *models.User
- Commit *git.Commit
- Tag *git.Tag
- GitRepo *git.Repository
- BranchName string
- TagName string
- TreePath string
- CommitID string
- RepoLink string
- CloneLink models.CloneLink
- CommitsCount int64
- Mirror *models.Mirror
+ IsWatching bool
+ IsViewBranch bool
+ IsViewTag bool
+ IsViewCommit bool
+ Repository *models.Repository
+ Owner *models.User
+ Commit *git.Commit
+ Tag *git.Tag
+ GitRepo *git.Repository
+ BranchName string
+ IsRenamedBranch bool
+ RenamedBranchName string
+ TagName string
+ TreePath string
+ CommitID string
+ RepoLink string
+ CloneLink models.CloneLink
+ CommitsCount int64
+ Mirror *models.Mirror
PullRequest *PullRequest
}
@@ -701,7 +703,28 @@ func getRefName(ctx *Context, pathType RepoRefType) string {
ctx.Repo.TreePath = path
return ctx.Repo.Repository.DefaultBranch
case RepoRefBranch:
- return getRefNameFromPath(ctx, path, ctx.Repo.GitRepo.IsBranchExist)
+ ref := getRefNameFromPath(ctx, path, ctx.Repo.GitRepo.IsBranchExist)
+ if len(ref) == 0 {
+ // maybe it's a renamed branch
+ return getRefNameFromPath(ctx, path, func(s string) bool {
+ b, exist, err := models.FindRenamedBranch(ctx.Repo.Repository.ID, s)
+ if err != nil {
+ log.Error("FindRenamedBranch", err)
+ return false
+ }
+
+ if !exist {
+ return false
+ }
+
+ ctx.Repo.IsRenamedBranch = true
+ ctx.Repo.RenamedBranchName = b.To
+
+ return true
+ })
+ }
+
+ return ref
case RepoRefTag:
return getRefNameFromPath(ctx, path, ctx.Repo.GitRepo.IsTagExist)
case RepoRefCommit:
@@ -780,9 +803,21 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
} else {
refName = getRefName(ctx, refType)
ctx.Repo.BranchName = refName
- if refType.RefTypeIncludesBranches() && ctx.Repo.GitRepo.IsBranchExist(refName) {
+ if refType.RefTypeIncludesBranches() {
ctx.Repo.IsViewBranch = true
+ if ctx.Repo.IsRenamedBranch {
+ ctx.Flash.Info(ctx.Tr("repo.branch.renamed", refName, ctx.Repo.RenamedBranchName))
+ link := strings.Replace(ctx.Req.RequestURI, refName, ctx.Repo.RenamedBranchName, 1)
+ ctx.Redirect(link)
+ return
+ }
+
+ if !ctx.Repo.GitRepo.IsBranchExist(refName) {
+ ctx.NotFound("RepoRef invalid repo", fmt.Errorf("branch or tag not exist: %s", refName))
+ return
+ }
+
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName)
if err != nil {
ctx.ServerError("GetBranchCommit", err)
diff --git a/modules/git/repo_branch.go b/modules/git/repo_branch.go
index 58781eb1c71a..44c81e8aeb47 100644
--- a/modules/git/repo_branch.go
+++ b/modules/git/repo_branch.go
@@ -156,3 +156,9 @@ func (repo *Repository) RemoveRemote(name string) error {
func (branch *Branch) GetCommit() (*Commit, error) {
return branch.gitRepo.GetBranchCommit(branch.Name)
}
+
+// RenameBranch rename a branch
+func (repo *Repository) RenameBranch(from, to string) error {
+ _, err := NewCommand("branch", "-m", from, to).RunInDir(repo.Path)
+ return err
+}
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 936677e31d33..422c8041b504 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -1862,6 +1862,12 @@ settings.lfs_pointers.inRepo=In Repo
settings.lfs_pointers.exists=Exists in store
settings.lfs_pointers.accessible=Accessible to User
settings.lfs_pointers.associateAccessible=Associate accessible %d OIDs
+settings.rename_branch_failed_exist=can not rename branch because target branch %s is exist
+settings.rename_branch_failed_not_exist= can not rename branch because target branch %s is not exist
+settings.rename_branch_success = branch %s has been succed renamed to %s
+settings.rename_branch_from=old branch name
+settings.rename_branch_to=new branch name
+settings.rename_branch = Rename branch
diff.browse_source = Browse Source
diff.parent = parent
@@ -1976,6 +1982,7 @@ branch.restore = Restore Branch '%s'
branch.download = Download Branch '%s'
branch.included_desc = This branch is part of the default branch
branch.included = Included
+branch.renamed = Branch %s was renamed to %s.
tag.create_tag = Create tag %s
tag.create_success = Tag '%s' has been created.
diff --git a/routers/repo/setting_protected_branch.go b/routers/repo/setting_protected_branch.go
index fba2c095cf93..865f696d930c 100644
--- a/routers/repo/setting_protected_branch.go
+++ b/routers/repo/setting_protected_branch.go
@@ -15,6 +15,7 @@ import (
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/notification"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/services/forms"
@@ -284,3 +285,60 @@ func SettingsProtectedBranchPost(ctx *context.Context) {
ctx.Redirect(fmt.Sprintf("%s/settings/branches", ctx.Repo.RepoLink))
}
}
+
+// RenameBranchPost responses for rename a branch
+func RenameBranchPost(ctx *context.Context) {
+ form := web.GetForm(ctx).(*forms.RenameBranchForm)
+
+ if !ctx.Repo.CanCreateBranch() {
+ ctx.NotFound("RenameBranch", nil)
+ return
+ }
+
+ if ctx.HasError() {
+ ctx.Flash.Error(ctx.GetErrMsg())
+ ctx.Redirect(fmt.Sprintf("%s/settings/branches", ctx.Repo.RepoLink))
+ return
+ }
+
+ if form.From == form.To {
+ ctx.Flash.Error(ctx.Tr("repo.settings.rename_branch_failed_exist", form.To))
+ ctx.Redirect(fmt.Sprintf("%s/settings/branches", ctx.Repo.RepoLink))
+ return
+ }
+
+ if ctx.Repo.GitRepo.IsBranchExist(form.To) {
+ ctx.Flash.Error(ctx.Tr("repo.settings.rename_branch_failed_exist", form.To))
+ ctx.Redirect(fmt.Sprintf("%s/settings/branches", ctx.Repo.RepoLink))
+ }
+
+ if !ctx.Repo.GitRepo.IsBranchExist(form.From) {
+ ctx.Flash.Error(ctx.Tr("repo.settings.rename_branch_failed_not_exist", form.From))
+ ctx.Redirect(fmt.Sprintf("%s/settings/branches", ctx.Repo.RepoLink))
+ }
+
+ if err := ctx.Repo.Repository.RenameBranch(form.From, form.To, func(isDefault bool) error {
+ err2 := ctx.Repo.GitRepo.RenameBranch(form.From, form.To)
+ if err2 != nil {
+ return err2
+ }
+
+ if isDefault {
+ err2 = ctx.Repo.GitRepo.SetDefaultBranch(form.To)
+ if err2 != nil {
+ return err2
+ }
+ }
+
+ return nil
+ }); err != nil {
+ ctx.ServerError("RenameBranch", err)
+ return
+ }
+
+ notification.NotifyDeleteRef(ctx.User, ctx.Repo.Repository, "branch", "refs/heads/"+form.From)
+ notification.NotifyCreateRef(ctx.User, ctx.Repo.Repository, "branch", "refs/heads/"+form.To)
+
+ ctx.Flash.Success(ctx.Tr("repo.settings.rename_branch_success", form.From, form.To))
+ ctx.Redirect(fmt.Sprintf("%s/settings/branches", ctx.Repo.RepoLink))
+}
diff --git a/routers/routes/web.go b/routers/routes/web.go
index 008c745d6e09..c8c0336efee7 100644
--- a/routers/routes/web.go
+++ b/routers/routes/web.go
@@ -664,6 +664,7 @@ func RegisterRoutes(m *web.Route) {
m.Combo("/*").Get(repo.SettingsProtectedBranch).
Post(bindIgnErr(forms.ProtectBranchForm{}), context.RepoMustNotBeArchived(), repo.SettingsProtectedBranchPost)
}, repo.MustBeNotEmpty)
+ m.Post("/rename_branch", bindIgnErr(forms.RenameBranchForm{}), context.RepoMustNotBeArchived(), repo.RenameBranchPost)
m.Group("/hooks/git", func() {
m.Get("", repo.GitHooks)
diff --git a/services/forms/repo_branch_form.go b/services/forms/repo_branch_form.go
index 88a069b8310c..f9262aaede77 100644
--- a/services/forms/repo_branch_form.go
+++ b/services/forms/repo_branch_form.go
@@ -24,3 +24,15 @@ func (f *NewBranchForm) Validate(req *http.Request, errs binding.Errors) binding
ctx := context.GetContext(req)
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
}
+
+// RenameBranchForm form for rename a branch
+type RenameBranchForm struct {
+ From string `binding:"Required;MaxSize(100);GitRefName"`
+ To string `binding:"Required;MaxSize(100);GitRefName"`
+}
+
+// Validate validates the fields
+func (f *RenameBranchForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
+}
diff --git a/templates/repo/settings/branches.tmpl b/templates/repo/settings/branches.tmpl
index fbe9a7463e5e..fe936667fc48 100644
--- a/templates/repo/settings/branches.tmpl
+++ b/templates/repo/settings/branches.tmpl
@@ -77,6 +77,28 @@
+
+ {{if $.Repository.CanCreateBranch}}
+
+
+ {{end}}
{{end}}
From b51c6a7b6fc56b735bff6b4b0e950622e2ba44f0 Mon Sep 17 00:00:00 2001
From: a1012112796 <1012112796@qq.com>
Date: Fri, 14 May 2021 19:11:23 +0800
Subject: [PATCH 2/8] fix bug
---
modules/context/repo.go | 21 ++++++++-------------
1 file changed, 8 insertions(+), 13 deletions(-)
diff --git a/modules/context/repo.go b/modules/context/repo.go
index e1e8deab0aa2..81a94d562c73 100644
--- a/modules/context/repo.go
+++ b/modules/context/repo.go
@@ -803,20 +803,15 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
} else {
refName = getRefName(ctx, refType)
ctx.Repo.BranchName = refName
- if refType.RefTypeIncludesBranches() {
- ctx.Repo.IsViewBranch = true
-
- if ctx.Repo.IsRenamedBranch {
- ctx.Flash.Info(ctx.Tr("repo.branch.renamed", refName, ctx.Repo.RenamedBranchName))
- link := strings.Replace(ctx.Req.RequestURI, refName, ctx.Repo.RenamedBranchName, 1)
- ctx.Redirect(link)
- return
- }
+ if ctx.Repo.IsRenamedBranch {
+ ctx.Flash.Info(ctx.Tr("repo.branch.renamed", refName, ctx.Repo.RenamedBranchName))
+ link := strings.Replace(ctx.Req.RequestURI, refName, ctx.Repo.RenamedBranchName, 1)
+ ctx.Redirect(link)
+ return
+ }
- if !ctx.Repo.GitRepo.IsBranchExist(refName) {
- ctx.NotFound("RepoRef invalid repo", fmt.Errorf("branch or tag not exist: %s", refName))
- return
- }
+ if refType.RefTypeIncludesBranches() && ctx.Repo.GitRepo.IsBranchExist(refName) {
+ ctx.Repo.IsViewBranch = true
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName)
if err != nil {
From 7059da87d35576e497e61638817c0c379e5a7e62 Mon Sep 17 00:00:00 2001
From: a1012112796 <1012112796@qq.com>
Date: Fri, 14 May 2021 19:45:15 +0800
Subject: [PATCH 3/8] add test
---
integrations/rename_branch_test.go | 43 ++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
create mode 100644 integrations/rename_branch_test.go
diff --git a/integrations/rename_branch_test.go b/integrations/rename_branch_test.go
new file mode 100644
index 000000000000..76fb91a08f3d
--- /dev/null
+++ b/integrations/rename_branch_test.go
@@ -0,0 +1,43 @@
+// Copyright 2021 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 integrations
+
+import (
+ "net/http"
+ "testing"
+
+ "code.gitea.io/gitea/models"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestRenameBranch(t *testing.T) {
+ // get branch setting page
+ session := loginUser(t, "user2")
+ req := NewRequest(t, "GET", "/user2/repo1/settings/branches")
+ resp := session.MakeRequest(t, req, http.StatusOK)
+ htmlDoc := NewHTMLParser(t, resp.Body)
+
+ postData := map[string]string{
+ "_csrf": htmlDoc.GetCSRF(),
+ "from": "master",
+ "to": "main",
+ }
+ req = NewRequestWithValues(t, "POST", "/user2/repo1/settings/rename_branch", postData)
+ session.MakeRequest(t, req, http.StatusFound)
+
+ // check new branch link
+ req = NewRequestWithValues(t, "GET", "/user2/repo1/src/branch/main/README.md", postData)
+ session.MakeRequest(t, req, http.StatusOK)
+
+ // check old branch link
+ req = NewRequestWithValues(t, "GET", "/user2/repo1/src/branch/master/README.md", postData)
+ resp = session.MakeRequest(t, req, http.StatusFound)
+ location := resp.HeaderMap.Get("Location")
+ assert.Equal(t, "/user2/repo1/src/branch/main/README.md", location)
+
+ // check db
+ repo1 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)
+ assert.Equal(t, "main", repo1.DefaultBranch)
+}
From 83ab12d48935a408ec1e748280cc75bca64539fb Mon Sep 17 00:00:00 2001
From: a1012112796 <1012112796@qq.com>
Date: Sat, 15 May 2021 10:51:41 +0800
Subject: [PATCH 4/8] add id condition
---
models/branches.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/models/branches.go b/models/branches.go
index cf15266d45c3..2d904c302462 100644
--- a/models/branches.go
+++ b/models/branches.go
@@ -629,7 +629,7 @@ func (repo *Repository) RenameBranch(from, to string, gitAction func(isDefault b
isDefault := repo.DefaultBranch == from
if isDefault {
repo.DefaultBranch = to
- _, err = sess.Cols("default_branch").Update(repo)
+ _, err = sess.ID(repo.ID).Cols("default_branch").Update(repo)
if err != nil {
return err
}
@@ -646,7 +646,7 @@ func (repo *Repository) RenameBranch(from, to string, gitAction func(isDefault b
if protectedBranch != nil {
protectedBranch.BranchName = to
- _, err = sess.Cols("branch_name").Update(protectedBranch)
+ _, err = sess.ID(protectedBranch.ID).Cols("branch_name").Update(protectedBranch)
if err != nil {
if err2 := sess.Rollback(); err2 != nil {
log.Error("RenameBranch: sess.Rollback: %v", err2)
From 9e5d9aa6e026dfd108963a3737b707482da61979 Mon Sep 17 00:00:00 2001
From: a1012112796 <1012112796@qq.com>
Date: Sun, 16 May 2021 22:59:51 +0800
Subject: [PATCH 5/8] apply suggestions from code review
---
models/branches.go | 27 +++----------
models/migrations/v180.go | 9 +++--
modules/context/repo.go | 48 +++++++++++------------
routers/repo/setting_protected_branch.go | 34 ++++------------
services/repository/branch.go | 49 ++++++++++++++++++++++++
5 files changed, 90 insertions(+), 77 deletions(-)
create mode 100644 services/repository/branch.go
diff --git a/models/branches.go b/models/branches.go
index 2d904c302462..4bce14a8e031 100644
--- a/models/branches.go
+++ b/models/branches.go
@@ -600,10 +600,11 @@ func RemoveOldDeletedBranches(ctx context.Context, olderThan time.Duration) {
// RenamedBranch proivde renamed branch log
// will check it when an branch can't be found
type RenamedBranch struct {
- ID int64 `xorm:"pk autoincr"`
- RepoID int64 `xorm:"INDEX NOT NULL"`
- From string
- To string
+ ID int64 `xorm:"pk autoincr"`
+ RepoID int64 `xorm:"INDEX NOT NULL"`
+ From string
+ To string
+ CreatedUnix timeutil.TimeStamp `xorm:"created"`
}
// FindRenamedBranch check if a branch was renamed
@@ -638,9 +639,6 @@ func (repo *Repository) RenameBranch(from, to string, gitAction func(isDefault b
// 2. Update protected branch if needed
protectedBranch, err := getProtectedBranchBy(sess, repo.ID, from)
if err != nil {
- if err2 := sess.Rollback(); err2 != nil {
- log.Error("RenameBranch: sess.Rollback: %v", err2)
- }
return err
}
@@ -648,9 +646,6 @@ func (repo *Repository) RenameBranch(from, to string, gitAction func(isDefault b
protectedBranch.BranchName = to
_, err = sess.ID(protectedBranch.ID).Cols("branch_name").Update(protectedBranch)
if err != nil {
- if err2 := sess.Rollback(); err2 != nil {
- log.Error("RenameBranch: sess.Rollback: %v", err2)
- }
return err
}
}
@@ -660,18 +655,11 @@ func (repo *Repository) RenameBranch(from, to string, gitAction func(isDefault b
repo.ID, from, false).
Update(map[string]interface{}{"base_branch": to})
if err != nil {
- if err2 := sess.Rollback(); err2 != nil {
- log.Error("RenameBranch: sess.Rollback: %v", err2)
- }
return err
}
// 4. do git action
if err = gitAction(isDefault); err != nil {
- if err2 := sess.Rollback(); err2 != nil {
- log.Error("RenameBranch: sess.Rollback: %v", err2)
- }
-
return err
}
@@ -681,13 +669,8 @@ func (repo *Repository) RenameBranch(from, to string, gitAction func(isDefault b
From: from,
To: to,
}
-
_, err = sess.Insert(renamedBranch)
if err != nil {
- if err2 := sess.Rollback(); err2 != nil {
- log.Error("RenameBranch: sess.Rollback: %v", err2)
- }
-
return err
}
diff --git a/models/migrations/v180.go b/models/migrations/v180.go
index 7fbd091f9c12..3517896a23dd 100644
--- a/models/migrations/v180.go
+++ b/models/migrations/v180.go
@@ -10,10 +10,11 @@ import (
func addRenamedBranchTable(x *xorm.Engine) error {
type RenamedBranch struct {
- ID int64 `xorm:"pk autoincr"`
- RepoID int64 `xorm:"INDEX NOT NULL"`
- From string
- To string
+ ID int64 `xorm:"pk autoincr"`
+ RepoID int64 `xorm:"INDEX NOT NULL"`
+ From string
+ To string
+ CreatedUnix int64 `xorm:"created"`
}
return x.Sync2(new(RenamedBranch))
}
diff --git a/modules/context/repo.go b/modules/context/repo.go
index 81a94d562c73..9090ae940ff8 100644
--- a/modules/context/repo.go
+++ b/modules/context/repo.go
@@ -49,25 +49,23 @@ type PullRequest struct {
// Repository contains information to operate a repository
type Repository struct {
models.Permission
- IsWatching bool
- IsViewBranch bool
- IsViewTag bool
- IsViewCommit bool
- Repository *models.Repository
- Owner *models.User
- Commit *git.Commit
- Tag *git.Tag
- GitRepo *git.Repository
- BranchName string
- IsRenamedBranch bool
- RenamedBranchName string
- TagName string
- TreePath string
- CommitID string
- RepoLink string
- CloneLink models.CloneLink
- CommitsCount int64
- Mirror *models.Mirror
+ IsWatching bool
+ IsViewBranch bool
+ IsViewTag bool
+ IsViewCommit bool
+ Repository *models.Repository
+ Owner *models.User
+ Commit *git.Commit
+ Tag *git.Tag
+ GitRepo *git.Repository
+ BranchName string
+ TagName string
+ TreePath string
+ CommitID string
+ RepoLink string
+ CloneLink models.CloneLink
+ CommitsCount int64
+ Mirror *models.Mirror
PullRequest *PullRequest
}
@@ -717,8 +715,8 @@ func getRefName(ctx *Context, pathType RepoRefType) string {
return false
}
- ctx.Repo.IsRenamedBranch = true
- ctx.Repo.RenamedBranchName = b.To
+ ctx.Data["IsRenamedBranch"] = true
+ ctx.Data["RenamedBranchName"] = b.To
return true
})
@@ -803,9 +801,11 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
} else {
refName = getRefName(ctx, refType)
ctx.Repo.BranchName = refName
- if ctx.Repo.IsRenamedBranch {
- ctx.Flash.Info(ctx.Tr("repo.branch.renamed", refName, ctx.Repo.RenamedBranchName))
- link := strings.Replace(ctx.Req.RequestURI, refName, ctx.Repo.RenamedBranchName, 1)
+ isRenamedBranch, has := ctx.Data["IsRenamedBranch"].(bool)
+ if isRenamedBranch && has {
+ renamedBranchName := ctx.Data["RenamedBranchName"].(string)
+ ctx.Flash.Info(ctx.Tr("repo.branch.renamed", refName, renamedBranchName))
+ link := strings.Replace(ctx.Req.RequestURI, refName, renamedBranchName, 1)
ctx.Redirect(link)
return
}
diff --git a/routers/repo/setting_protected_branch.go b/routers/repo/setting_protected_branch.go
index 865f696d930c..19606bd1b8c0 100644
--- a/routers/repo/setting_protected_branch.go
+++ b/routers/repo/setting_protected_branch.go
@@ -15,11 +15,11 @@ import (
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
- "code.gitea.io/gitea/modules/notification"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/services/forms"
pull_service "code.gitea.io/gitea/services/pull"
+ "code.gitea.io/gitea/services/repository"
)
// ProtectedBranch render the page to protect the repository
@@ -301,44 +301,24 @@ func RenameBranchPost(ctx *context.Context) {
return
}
- if form.From == form.To {
- ctx.Flash.Error(ctx.Tr("repo.settings.rename_branch_failed_exist", form.To))
- ctx.Redirect(fmt.Sprintf("%s/settings/branches", ctx.Repo.RepoLink))
+ msg, err := repository.RenameBranch(ctx.Repo.Repository, ctx.User, ctx.Repo.GitRepo, form.From, form.To)
+ if err != nil {
+ ctx.ServerError("RenameBranch", err)
return
}
- if ctx.Repo.GitRepo.IsBranchExist(form.To) {
+ if msg == "target_exist" {
ctx.Flash.Error(ctx.Tr("repo.settings.rename_branch_failed_exist", form.To))
ctx.Redirect(fmt.Sprintf("%s/settings/branches", ctx.Repo.RepoLink))
+ return
}
- if !ctx.Repo.GitRepo.IsBranchExist(form.From) {
+ if msg == "from_not_exist" {
ctx.Flash.Error(ctx.Tr("repo.settings.rename_branch_failed_not_exist", form.From))
ctx.Redirect(fmt.Sprintf("%s/settings/branches", ctx.Repo.RepoLink))
- }
-
- if err := ctx.Repo.Repository.RenameBranch(form.From, form.To, func(isDefault bool) error {
- err2 := ctx.Repo.GitRepo.RenameBranch(form.From, form.To)
- if err2 != nil {
- return err2
- }
-
- if isDefault {
- err2 = ctx.Repo.GitRepo.SetDefaultBranch(form.To)
- if err2 != nil {
- return err2
- }
- }
-
- return nil
- }); err != nil {
- ctx.ServerError("RenameBranch", err)
return
}
- notification.NotifyDeleteRef(ctx.User, ctx.Repo.Repository, "branch", "refs/heads/"+form.From)
- notification.NotifyCreateRef(ctx.User, ctx.Repo.Repository, "branch", "refs/heads/"+form.To)
-
ctx.Flash.Success(ctx.Tr("repo.settings.rename_branch_success", form.From, form.To))
ctx.Redirect(fmt.Sprintf("%s/settings/branches", ctx.Repo.RepoLink))
}
diff --git a/services/repository/branch.go b/services/repository/branch.go
new file mode 100644
index 000000000000..194249e63aa7
--- /dev/null
+++ b/services/repository/branch.go
@@ -0,0 +1,49 @@
+// Copyright 2021 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 (
+ "code.gitea.io/gitea/models"
+ "code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/notification"
+)
+
+// RenameBranch rename a branch
+func RenameBranch(repo *models.Repository, doer *models.User, gitRepo *git.Repository, from, to string) (string, error) {
+ if from == to {
+ return "target_exist", nil
+ }
+
+ if gitRepo.IsBranchExist(to) {
+ return "target_exist", nil
+ }
+
+ if !gitRepo.IsBranchExist(from) {
+ return "from_not_exist", nil
+ }
+
+ if err := repo.RenameBranch(from, to, func(isDefault bool) error {
+ err2 := gitRepo.RenameBranch(from, to)
+ if err2 != nil {
+ return err2
+ }
+
+ if isDefault {
+ err2 = gitRepo.SetDefaultBranch(to)
+ if err2 != nil {
+ return err2
+ }
+ }
+
+ return nil
+ }); err != nil {
+ return "", err
+ }
+
+ notification.NotifyDeleteRef(doer, repo, "branch", "refs/heads/"+from)
+ notification.NotifyCreateRef(doer, repo, "branch", "refs/heads/"+to)
+
+ return "", nil
+}
From c01d4d27ef07ef4d8184a2950e770c7a318ac081 Mon Sep 17 00:00:00 2001
From: a1012112796 <1012112796@qq.com>
Date: Sun, 3 Oct 2021 12:11:58 +0800
Subject: [PATCH 6/8] Update models/branches.go
Co-authored-by: delvh
---
models/branches.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/models/branches.go b/models/branches.go
index 7349e29daf2c..aeb5079eae5e 100644
--- a/models/branches.go
+++ b/models/branches.go
@@ -572,8 +572,8 @@ func RemoveOldDeletedBranches(ctx context.Context, olderThan time.Duration) {
}
}
-// RenamedBranch proivde renamed branch log
-// will check it when an branch can't be found
+// RenamedBranch provide renamed branch log
+// will check it when a branch can't be found
type RenamedBranch struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"INDEX NOT NULL"`
From 7216645d73265ccb3b9c169c72f535b36a17be4f Mon Sep 17 00:00:00 2001
From: a1012112796 <1012112796@qq.com>
Date: Sun, 3 Oct 2021 12:17:42 +0800
Subject: [PATCH 7/8] Update options/locale/locale_en-US.ini
Co-authored-by: delvh
---
options/locale/locale_en-US.ini | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 7f21a6e58d3f..69a303de8a3a 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -1974,12 +1974,12 @@ settings.lfs_pointers.inRepo=In Repo
settings.lfs_pointers.exists=Exists in store
settings.lfs_pointers.accessible=Accessible to User
settings.lfs_pointers.associateAccessible=Associate accessible %d OIDs
-settings.rename_branch_failed_exist=can not rename branch because target branch %s is exist
-settings.rename_branch_failed_not_exist= can not rename branch because target branch %s is not exist
-settings.rename_branch_success = branch %s has been succed renamed to %s
+settings.rename_branch_failed_exist=Cannot rename branch because target branch %s exists.
+settings.rename_branch_failed_not_exist=Cannot rename branch %s because it does not exist.
+settings.rename_branch_success =Branch %s was successfully renamed to %s.
settings.rename_branch_from=old branch name
settings.rename_branch_to=new branch name
-settings.rename_branch = Rename branch
+settings.rename_branch=Rename branch
diff.browse_source = Browse Source
diff.parent = parent
From 57fc73892a669d7da8834708e92c8e1181bfd37e Mon Sep 17 00:00:00 2001
From: a1012112796 <1012112796@qq.com>
Date: Thu, 7 Oct 2021 15:42:32 +0800
Subject: [PATCH 8/8] fix db
---
models/branches.go | 1 +
1 file changed, 1 insertion(+)
diff --git a/models/branches.go b/models/branches.go
index 124b82871400..3c62c7a87bd8 100644
--- a/models/branches.go
+++ b/models/branches.go
@@ -53,6 +53,7 @@ type ProtectedBranch struct {
func init() {
db.RegisterModel(new(ProtectedBranch))
db.RegisterModel(new(DeletedBranch))
+ db.RegisterModel(new(RenamedBranch))
}
// IsProtected returns if the branch is protected