Subject: [PATCH v11 2/6] branch: let delete_branches warn instead of error on bulk refusal

From: "Harald Nordgren via GitGitGadget" <[email-masked]>
Date: Fri, 22 May 2026 11:31:34 +0000

From: Harald Nordgren <[email-masked]>

Add a warn_only flag to delete_branches() and check_branch_commit()
so a bulk caller can report not-fully-merged branches as one-line
warnings and continue, instead of erroring with the four-line "use
'git branch -D'" advice that the standalone "git branch -d" path
emits.  Default callers pass 0 and are unaffected.

Signed-off-by: Harald Nordgren <[email-masked]>
---
 builtin/branch.c | 26 +++++++++++++++++---------
 1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 2d34ad34dc..96f6ae6dec 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -193,7 +193,7 @@ static int branch_merged(int kind, const char *name,
 
 static int check_branch_commit(const char *branchname, const char *refname,
 			       const struct object_id *oid, struct commit *head_rev,
-			       int kinds, int force)
+			       int kinds, int force, int warn_only)
 {
 	struct commit *rev = lookup_commit_reference(the_repository, oid);
 	if (!force && !rev) {
@@ -201,10 +201,16 @@ static int check_branch_commit(const char *branchname, const char *refname,
 		return -1;
 	}
 	if (!force && !branch_merged(kinds, branchname, rev, head_rev)) {
-		error(_("the branch '%s' is not fully merged"), branchname);
-		advise_if_enabled(ADVICE_FORCE_DELETE_BRANCH,
-				  _("If you are sure you want to delete it, "
-				  "run 'git branch -D %s'"), branchname);
+		if (warn_only) {
+			warning(_("the branch '%s' is not fully merged"),
+				branchname);
+		} else {
+			error(_("the branch '%s' is not fully merged"),
+			      branchname);
+			advise_if_enabled(ADVICE_FORCE_DELETE_BRANCH,
+					  _("If you are sure you want to delete it, "
+					  "run 'git branch -D %s'"), branchname);
+		}
 		return -1;
 	}
 	return 0;
@@ -220,7 +226,7 @@ static void delete_branch_config(const char *branchname)
 }
 
 static int delete_branches(int argc, const char **argv, int force, int kinds,
-			   int quiet)
+			   int quiet, int warn_only)
 {
 	struct commit *head_rev = NULL;
 	struct object_id oid;
@@ -310,8 +316,9 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
 
 		if (!(flags & (REF_ISSYMREF|REF_ISBROKEN)) &&
 		    check_branch_commit(bname.buf, name, &oid, head_rev, kinds,
-					force)) {
-			ret = 1;
+					force, warn_only)) {
+			if (!warn_only)
+				ret = 1;
 			goto next;
 		}
 
@@ -1019,7 +1026,8 @@ int cmd_branch(int argc,
 	if (delete) {
 		if (!argc)
 			die(_("branch name required"));
-		ret = delete_branches(argc, argv, delete > 1, filter.kind, quiet);
+		ret = delete_branches(argc, argv, delete > 1, filter.kind,
+				      quiet, 0);
 		goto out;
 	} else if (forked) {
 		ret = list_forked_branches(argc, argv);
-- 
gitgitgadget