Delete non-exist branch should return 404 (#36694)

Fix #36682

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
Lunny Xiao
2026-03-02 11:08:16 -08:00
committed by GitHub
parent 716a800f50
commit 0e0daa8afe
8 changed files with 68 additions and 45 deletions

View File

@@ -573,8 +573,38 @@ func CanDeleteBranch(ctx context.Context, repo *repo_model.Repository, branchNam
return nil
}
func deleteBranchInternal(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, branchName string, branchCommit *git.Commit) (branchExisted bool, err error) {
activeInDB, err := git_model.IsBranchExist(ctx, repo.ID, branchName)
if err != nil {
return false, fmt.Errorf("IsBranchExist: %w", err)
}
// process the branch in db
if activeInDB {
if err := git_model.MarkBranchAsDeleted(ctx, repo.ID, branchName, doer.ID); err != nil {
return false, err
}
}
// process the branch in git
if branchCommit != nil {
err := gitrepo.DeleteBranch(ctx, repo, branchName, true)
if err != nil {
return false, fmt.Errorf("DeleteBranch: %w", err)
}
// since the branch existed in git, return branchExisted=true
branchExisted = true
} else {
// the branch didn't exist in git, return activeInDB to indicate whether the branch was active in DB,
// for consistency with that the user had seen on the web ui or in the branch list API response.
branchExisted = activeInDB
}
return branchExisted, nil
}
// DeleteBranch delete branch
func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, gitRepo *git.Repository, branchName string, pr *issues_model.PullRequest) error {
func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, gitRepo *git.Repository, branchName string) error {
err := repo.MustNotBeArchived()
if err != nil {
return err
@@ -584,46 +614,31 @@ func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.R
return err
}
rawBranch, err := git_model.GetBranch(ctx, repo.ID, branchName)
if err != nil && !git_model.IsErrBranchNotExist(err) {
return fmt.Errorf("GetBranch: %vc", err)
}
// database branch record not exist or it's a deleted branch
notExist := git_model.IsErrBranchNotExist(err) || rawBranch.IsDeleted
branchCommit, err := gitRepo.GetBranchCommit(branchName)
// branchCommit can be nil if the branch doesn't exist in git
if err != nil && !errors.Is(err, util.ErrNotExist) {
return err
}
if err := db.WithTx(ctx, func(ctx context.Context) error {
if !notExist {
if err := git_model.AddDeletedBranch(ctx, repo.ID, branchName, doer.ID); err != nil {
return err
}
}
if pr != nil {
if err := issues_model.AddDeletePRBranchComment(ctx, doer, pr.BaseRepo, pr.Issue.ID, pr.HeadBranch); err != nil {
return fmt.Errorf("DeleteBranch: %v", err)
}
}
if branchCommit == nil {
return nil
}
return gitrepo.DeleteBranch(ctx, repo, branchName, true)
}); err != nil {
branchExisted, err := db.WithTx2(ctx, func(ctx context.Context) (bool, error) {
return deleteBranchInternal(ctx, doer, repo, branchName, branchCommit)
})
if err != nil {
return err
}
if branchCommit == nil {
return nil
if !branchExisted {
return git.ErrBranchNotExist{Name: branchName}
}
// Don't return error below this
// Don't return error below this since the deletion has succeeded
if branchCommit != nil {
deleteBranchSuccessPostProcess(doer, repo, branchName, branchCommit)
}
return nil
}
func deleteBranchSuccessPostProcess(doer *user_model.User, repo *repo_model.Repository, branchName string, branchCommit *git.Commit) {
objectFormat := git.ObjectFormatFromName(repo.ObjectFormatName)
if err := PushUpdate(
&repo_module.PushUpdateOptions{
@@ -637,8 +652,6 @@ func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.R
}); err != nil {
log.Error("PushUpdateOptions: %v", err)
}
return nil
}
type BranchSyncOptions struct {
@@ -886,9 +899,17 @@ func DeleteBranchAfterMerge(ctx context.Context, doer *user_model.User, prID int
return util.ErrorWrapTranslatable(util.ErrUnprocessableContent, "repo.branch.delete_branch_has_new_commits", fullBranchName)
}
err = DeleteBranch(ctx, doer, pr.HeadRepo, gitHeadRepo, pr.HeadBranch, pr)
err = DeleteBranch(ctx, doer, pr.HeadRepo, gitHeadRepo, pr.HeadBranch)
if errors.Is(err, util.ErrPermissionDenied) || errors.Is(err, util.ErrNotExist) {
return errFailedToDelete(err)
}
return err
if err != nil {
return err
}
// intentionally ignore the following error, since the branch has already been deleted successfully
if err := issues_model.AddDeletePRBranchComment(ctx, doer, pr.BaseRepo, pr.Issue.ID, pr.HeadBranch); err != nil {
log.Error("AddDeletePRBranchComment: %v", err)
}
return nil
}