[PATCH v6 2/4] branch: let delete_branches() name where a branch landed
- From
Harald Nordgren via GitGitGadget <gitgitgadget@gmail.com>
- Date
- Nov 1, 2026, 08:22 UTC
- Message-ID
- <9858c8c81e9c58bcd5d3dc55c65bbc70129a55c4.1793521331.git.gitgitgadget@gmail.com>
- In-Reply-To
- <pull.2425.v6.git.git.1793521331.gitgitgadget@gmail.com>
From: Harald Nordgren <haraldnordgren@gmail.com>
A later commit lets "git branch" delete branches whose commits are not in their upstream but whose changes are, such as after a squash merge. Their tips are not reachable from the upstream, so the merge check in delete_branches() would refuse to delete them, and the output should say where their changes went.
Let delete_branches() take a map from branch names to the upstream commit where each branch landed. A branch in the map skips the merge check and is reported as
Deleted branch topic (was 1a2b3c4, landed as 9f8e7d6).
No caller passes a map yet, so there is no change in behavior.
Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> --- builtin/branch.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-)
diff --git a/builtin/branch.c b/builtin/branch.c index 171b13b081..99b0dd45e9 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -236,7 +236,7 @@ static void delete_branch_config(const char *branchname) } static int delete_branches(int argc, const char **argv, int kinds, - unsigned int flags) + unsigned int flags, struct strmap *landed_commits) { struct commit *head_rev = NULL; struct object_id oid; @@ -334,6 +334,8 @@ static int delete_branches(int argc, const char **argv, int kinds, } if (!(ref_flags & (REF_ISSYMREF|REF_ISBROKEN)) && + !(landed_commits && + strmap_contains(landed_commits, bname.buf)) && check_branch_commit(bname.buf, name, &oid, head_rev, kinds, flags)) { if (!(flags & DELETE_BRANCH_SKIP_UNMERGED)) @@ -357,15 +359,33 @@ static int delete_branches(int argc, const char **argv, int kinds, for_each_string_list_item(item, &refs_to_delete) { char *describe_ref = item->util; char *name = item->string; + struct commit *landed = landed_commits ? + strmap_get(landed_commits, name + branch_name_pos) : NULL; + const char *landed_abbrev = landed ? + repo_find_unique_abbrev(the_repository, + &landed->object.oid, + DEFAULT_ABBREV) : NULL; + if (flags & DELETE_BRANCH_DRY_RUN) { - if (!(flags & DELETE_BRANCH_QUIET)) + if (flags & DELETE_BRANCH_QUIET) + ; + else if (landed) + printf(_("Would delete branch %s (was %s, landed as %s).\n"), + name + branch_name_pos, describe_ref, + landed_abbrev); + else printf(remote_branch ? _("Would delete remote-tracking branch %s (was %s).\n") : _("Would delete branch %s (was %s).\n"), name + branch_name_pos, describe_ref); } else if (!refs_ref_exists(get_main_ref_store(the_repository), name)) { char *refname = name + branch_name_pos; - if (!(flags & DELETE_BRANCH_QUIET)) + if (flags & DELETE_BRANCH_QUIET) + ; + else if (landed) + printf(_("Deleted branch %s (was %s, landed as %s).\n"), + refname, describe_ref, landed_abbrev); + else printf(remote_branch ? _("Deleted remote-tracking branch %s (was %s).\n") : _("Deleted branch %s (was %s).\n"), @@ -901,7 +921,7 @@ static int delete_merged_branches(const struct strvec *upstreams, FILTER_REFS_BRANCHES, DELETE_BRANCH_SKIP_UNMERGED | DELETE_BRANCH_NO_HEAD_FALLBACK | - flags); + flags, NULL); if (!ret && !(flags & DELETE_BRANCH_DRY_RUN)) clear_deleted_upstreams(&protected_branch_names, @@ -1141,7 +1161,7 @@ int cmd_branch(int argc, die(_("branch name required")); ret = delete_branches(argc, argv, filter.kind, (delete > 1 ? DELETE_BRANCH_FORCE : 0) | - (quiet ? DELETE_BRANCH_QUIET : 0)); + (quiet ? DELETE_BRANCH_QUIET : 0), NULL); goto out; } else if (delete_merged.nr) { ret = delete_merged_branches(&delete_merged, argv,
-- gitgitgadget