From 57cbded4a0e46e3ccf14de1e3d63a71f7f8c92f1 Mon Sep 17 00:00:00 2001 From: bircni Date: Mon, 12 Oct 2026 20:28:35 +0200 Subject: [PATCH] fix(pr): delete the local branch on merge only when asked to Signed-off-by: bircni --- internal/app/pull_merge_form_test.go | 24 ++++++++++++++++++++++++ internal/app/pull_mutations.go | 22 +++++++++++++++------- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/internal/app/pull_merge_form_test.go b/internal/app/pull_merge_form_test.go index 28c3a6cf..56fe1042 100644 --- a/internal/app/pull_merge_form_test.go +++ b/internal/app/pull_merge_form_test.go @@ -7,6 +7,7 @@ import ( "context" "encoding/json" "net/http" + "slices" "testing" "gitea.dev/tea/internal/clierr" @@ -71,6 +72,29 @@ func TestPullMergeUsesTheRepositoryDefaults(t *testing.T) { require.Empty(t, diagnostics.String()) } +func TestPullMergeKeepsTheLocalBranchWithoutTheFlag(t *testing.T) { + for _, tc := range []struct { + name string + flags []string + local bool + }{ + {"repository default", nil, false}, + {"flag", []string{"--delete-branch"}, true}, + } { + t.Run(tc.name, func(t *testing.T) { + var payload map[string]any + server := newAuthenticatedServer(mergeServer(t, openPull, &payload)) + defer server.Close() + deps, _, _ := serverDeps(t, server.URL) + fake := &fakeGit{results: map[string]string{"symbolic-ref --short HEAD": "feature"}} + deps.Git = fake + require.NoError(t, Execute(context.Background(), deps, append([]string{"pr", "merge", "3", "-R", "alice/project", "--yes"}, tc.flags...))) + require.Equal(t, true, payload["delete_branch_after_merge"]) + require.Equal(t, tc.local, slices.Contains(fake.calls, "rev-parse --verify refs/heads/feature^{commit}"), fake.calls) + }) + } +} + func TestPullMergeAsksForTheMethodAndBranchDeletion(t *testing.T) { var payload map[string]any server := newAuthenticatedServer(mergeServer(t, openPull, &payload)) diff --git a/internal/app/pull_mutations.go b/internal/app/pull_mutations.go index 2bd33547..599de686 100644 --- a/internal/app/pull_mutations.go +++ b/internal/app/pull_mutations.go @@ -107,7 +107,7 @@ func (a *application) pullStateCommand(closing bool) *cobra.Command { a.done(cmd, "%s pull request %s", done, ref) } if deleteBranch { - a.deleteHead(cmd, service, item, false) + a.deleteHead(cmd, service, item, false, true) } return a.jsonResult(cmd, item) }} @@ -124,9 +124,9 @@ $ tea pr close 13 -c "Superseded by #15" --delete-branch` } // deleteHead deletes the head branch of a merged or closed pull request on Gitea, unless it is -// gone, and then locally, reporting each step. merging tells that Gitea deleted it as part of -// the merge. -func (a *application) deleteHead(cmd *cobra.Command, service services.Pulls, item services.Pull, merging bool) { +// gone, and then locally when local is set, reporting each step. merging tells that Gitea deleted +// it as part of the merge. +func (a *application) deleteHead(cmd *cobra.Command, service services.Pulls, item services.Pull, merging, local bool) { switch { case item.HeadRemoteDeleted && merging: a.done(cmd, "Deleted remote branch %s", item.Head) @@ -141,7 +141,9 @@ func (a *application) deleteHead(cmd *cobra.Command, service services.Pulls, ite a.done(cmd, "Deleted remote branch %s", item.Head) } } - a.deleteLocalHead(cmd, item) + if local { + a.deleteLocalHead(cmd, item) + } } // deleteLocalHead deletes the checked-out branch when it is at the head of the pull request, @@ -311,6 +313,9 @@ the base branch.`, Annotations: pullArgumentsAnnotation(map[string]string{"tea.c } else if !slices.Contains(repoSettings.Styles, method) { return clierr.Wrap(clierr.Usage, fmt.Errorf("%s merges are disabled in %s; use one of: %s", method, t.Repo, strings.Join(repoSettings.Styles, ", "))) } + // The repository setting deletes the branch on Gitea only; the local branch goes when + // --delete-branch or the form asks for it. + deleteLocal := deleteBranch if !cmd.Flags().Changed("delete-branch") { deleteBranch = repoSettings.DeleteBranch } @@ -328,6 +333,9 @@ the base branch.`, Annotations: pullArgumentsAnnotation(map[string]string{"tea.c return err } method, deleteBranch = values.Method, values.DeleteBranch + if askDelete { + deleteLocal = deleteBranch + } } else if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: header + "?", DefaultYes: true, NonTTY: "merge " + t.Repo + "#" + fmt.Sprint(n)}); err != nil { return err } @@ -349,7 +357,7 @@ the base branch.`, Annotations: pullArgumentsAnnotation(map[string]string{"tea.c } else { a.done(cmd, "%s pull request %s", mergeVerbs[method], ref) if deleteBranch { - a.deleteHead(cmd, service, merged, true) + a.deleteHead(cmd, service, merged, true, deleteLocal) } } return a.jsonResult(cmd, merged) @@ -361,7 +369,7 @@ the base branch.`, Annotations: pullArgumentsAnnotation(map[string]string{"tea.c cmd.Flags().BoolVar(&style.merge, "merge", false, "Create a merge commit") cmd.Flags().BoolVar(&style.squash, "squash", false, "Squash the commits into one commit and merge it") cmd.Flags().BoolVar(&style.rebase, "rebase", false, "Rebase the commits onto the base branch") - cmd.Flags().BoolVarP(&deleteBranch, "delete-branch", "d", false, "Delete the head branch after merging (default: the repository setting)") + cmd.Flags().BoolVarP(&deleteBranch, "delete-branch", "d", false, "Delete the head branch on Gitea and locally after merging (default: the repository setting, on Gitea only)") cmd.Flags().BoolVar(&auto, "auto", false, "Merge once the required checks succeed") cmd.Flags().StringVarP(&title, "title", "t", "", "Merge commit title") cmd.Flags().StringVarP(&message, "message", "b", "", "Merge commit message")