git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v4 4/4] branch: do not mark the branch the current worktree is rebasing

From
JMJasper Mayone <me@jaspermayone.com>
Date
Nov 2, 2026, 18:29 UTC
Message-ID
<20261102182930.3511-5-me@jaspermayone.com>
In-Reply-To
<20261102182930.3511-1-me@jaspermayone.com>

Since the previous commit, "git branch" marks a branch with "+" when a worktree is rebasing or bisecting it. In that worktree itself, the list already starts with "* (no branch, rebasing topic)", so the "+ topic" line below it says the same thing twice.

The default format cannot tell that apart: %(worktreepath) gives the same path either way, and comparing it with %(if:equals=...) is not safe because a path, or a branch name, can contain the ")" that ends the atom. So build a second format that has no "+" marker and no "(path)" for -vv, and use it for each branch that branch_checked_out_worktree() maps to the current worktree. A branch that is checked out normally in the current worktree also gets that format, but %(HEAD) still marks it with "*" and -vv already hides its path, so its output does not change.

To pick a format for each branch, print_ref_list() now formats the branches itself in place of print_formatted_ref_array(), keeping --omit-empty. A format given with --format is used for every branch, as before.

Suggested-by: Phillip Wood <phillip.wood123@gmail.com>
Signed-off-by: Jasper Mayone <me@jaspermayone.com>
---
 builtin/branch.c         | 103 ++++++++++++++++++++++++++++++---------
 t/t3203-branch-output.sh |  22 ++++++++-
 2 files changed, 101 insertions(+), 24 deletions(-)
diff --git a/builtin/branch.c b/builtin/branch.c
index a613148fc7..b55a400217 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -418,16 +418,28 @@ static const char *quote_literal_for_format(const char *s)
 	return buf.buf;
 }
 
-static char *build_format(struct ref_filter *filter, int maxwidth, const char *remote_prefix)
+/*
+ * With "show_worktree" unset, the format does not mark a branch that is
+ * checked out in a worktree, nor show the path of that worktree. It is
+ * used for a branch that the current worktree is rebasing or bisecting,
+ * because the "(no branch, ...)" line already names it.
+ */
+static char *build_format(struct ref_filter *filter, int maxwidth,
+			  const char *remote_prefix, int show_worktree)
 {
 	struct strbuf fmt = STRBUF_INIT;
 	struct strbuf local = STRBUF_INIT;
 	struct strbuf remote = STRBUF_INIT;
 
-	strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)%%(if)%%(worktreepath)%%(then)+ %s%%(else)  %s%%(end)%%(end)",
-			branch_get_color(BRANCH_COLOR_CURRENT),
-			branch_get_color(BRANCH_COLOR_WORKTREE),
-			branch_get_color(BRANCH_COLOR_LOCAL));
+	if (show_worktree)
+		strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)%%(if)%%(worktreepath)%%(then)+ %s%%(else)  %s%%(end)%%(end)",
+			    branch_get_color(BRANCH_COLOR_CURRENT),
+			    branch_get_color(BRANCH_COLOR_WORKTREE),
+			    branch_get_color(BRANCH_COLOR_LOCAL));
+	else
+		strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)",
+			    branch_get_color(BRANCH_COLOR_CURRENT),
+			    branch_get_color(BRANCH_COLOR_LOCAL));
 	strbuf_addf(&remote, "  %s",
 		    branch_get_color(BRANCH_COLOR_REMOTE));
 
@@ -447,8 +459,9 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
 
 		if (filter->verbose > 1)
 		{
-			strbuf_addf(&local, "%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)(%s%%(worktreepath)%s) %%(end)%%(end)",
-				    branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));
+			if (show_worktree)
+				strbuf_addf(&local, "%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)(%s%%(worktreepath)%s) %%(end)%%(end)",
+					    branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));
 			strbuf_addf(&local, "%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)"
 				    "%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)",
 				    branch_get_color(BRANCH_COLOR_UPSTREAM), branch_get_color(BRANCH_COLOR_RESET));
@@ -477,6 +490,32 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
 	return strbuf_detach(&fmt, NULL);
 }
 
+static char *current_worktree_path(void)
+{
+	struct worktree **worktrees = get_worktrees(the_repository);
+	char *path = NULL;
+
+	for (size_t i = 0; worktrees[i]; i++) {
+		if (worktrees[i]->is_current) {
+			path = xstrdup(worktrees[i]->path);
+			break;
+		}
+	}
+	free_worktrees(worktrees);
+	return path;
+}
+
+/*
+ * Is "refname" checked out in the worktree at "here", or is that
+ * worktree rebasing or bisecting it?
+ */
+static int checked_out_here(const char *refname, const char *here)
+{
+	const char *path = branch_checked_out_worktree(refname);
+
+	return path && !strcmp(path, here);
+}
+
 static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting,
 			   struct ref_format *format, struct string_list *output)
 {
@@ -485,6 +524,9 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
 	int maxwidth = 0;
 	const char *remote_prefix = "";
 	char *to_free = NULL;
+	struct ref_format here_format = REF_FORMAT_INIT;
+	char *here_to_free = NULL, *here = NULL;
+	struct strbuf out = STRBUF_INIT, err = STRBUF_INIT;
 
 	/*
 	 * If we are listing more than just remote branches,
@@ -501,39 +543,54 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
 	if (filter->verbose)
 		maxwidth = calc_maxwidth(&array, strlen(remote_prefix));
 
-	if (!format->format)
-		format->format = to_free = build_format(filter, maxwidth, remote_prefix);
+	if (!format->format) {
+		format->format = to_free = build_format(filter, maxwidth,
+							remote_prefix, 1);
+		here = current_worktree_path();
+		here_format = *format;
+		here_format.format = here_to_free = build_format(filter, maxwidth,
+								 remote_prefix, 0);
+	}
 	format->use_color = branch_use_color;
+	here_format.use_color = branch_use_color;
 
-	if (verify_ref_format(format))
+	if (verify_ref_format(format) ||
+	    (here && verify_ref_format(&here_format)))
 		die(_("unable to parse format string"));
 
 	filter_ahead_behind(the_repository, &array);
 	ref_array_sort(sorting, &array);
 
-	if (column_active(colopts)) {
-		struct strbuf out = STRBUF_INIT, err = STRBUF_INIT;
-
+	if (column_active(colopts))
 		assert(!filter->verbose && "--column and --verbose are incompatible");
 
-		for (i = 0; i < array.nr; i++) {
-			strbuf_reset(&err);
-			strbuf_reset(&out);
-			if (format_ref_array_item(array.items[i], format, &out, &err))
-				die("%s", err.buf);
+	for (i = 0; i < array.nr; i++) {
+		struct ref_array_item *item = array.items[i];
+		struct ref_format *f = format;
 
+		if (here && checked_out_here(item->refname, here))
+			f = &here_format;
+
+		strbuf_reset(&err);
+		strbuf_reset(&out);
+		if (format_ref_array_item(item, f, &out, &err))
+			die("%s", err.buf);
+
+		if (column_active(colopts))
 			/* format to a string_list to let print_columns() do its job */
 			string_list_append(output, out.buf);
+		else if (out.len || !format->array_opts.omit_empty) {
+			fwrite(out.buf, 1, out.len, stdout);
+			putchar('\n');
 		}
-
-		strbuf_release(&err);
-		strbuf_release(&out);
-	} else {
-		print_formatted_ref_array(&array, format);
 	}
 
+	strbuf_release(&err);
+	strbuf_release(&out);
 	ref_array_clear(&array);
 	free(to_free);
+	free(here_to_free);
+	free(here);
 }
 
 static void print_current_branch_name(void)
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index debfac5f26..5541f1429b 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -456,6 +456,23 @@ test_expect_success 'branch being rebased in a worktree is marked' '
 	test_cmp expect actual
 '
 
+test_expect_success 'branch being rebased is not marked in its own worktree' '
+	test_when_finished "git -C rebase_dir rebase --abort; rm -rf rebase_dir; git worktree prune; git branch -D rebasing" &&
+	git worktree add -b rebasing rebase_dir branch-two &&
+	(
+		cd rebase_dir &&
+		git commit --allow-empty -m rebase-me &&
+		test_must_fail git rebase -f -x false HEAD~1 &&
+		git branch --list rebasing >actual &&
+		echo "  rebasing" >expect &&
+		test_cmp expect actual &&
+		git branch -vv --list rebasing >actual &&
+		test_grep ! "$(pwd)" actual &&
+		git branch >actual &&
+		test_grep "^\* (no branch, rebasing rebasing)" actual
+	)
+'
+
 test_expect_success 'branch being bisected in a worktree is marked' '
 	test_when_finished "git -C bisect_dir bisect reset; rm -rf bisect_dir; git worktree prune; git branch -D bisecting" &&
 	git worktree add -b bisecting bisect_dir branch-two &&
@@ -464,7 +481,10 @@ test_expect_success 'branch being bisected in a worktree is marked' '
 		git commit --allow-empty -m bisect-one &&
 		git commit --allow-empty -m bisect-two &&
 		git bisect start HEAD HEAD~2 &&
-		test_must_fail git symbolic-ref -q HEAD
+		test_must_fail git symbolic-ref -q HEAD &&
+		git branch --list bisecting >actual &&
+		echo "  bisecting" >expect &&
+		test_cmp expect actual
 	) &&
 	git branch --list bisecting >actual &&
 	echo "+ bisecting" >expect &&
-- 
2.56.0
Previous: Jasper MayoneNext: Harald Nordgren
Message 29 of 33 in “worktree list: add --merged and --no-merged”
  1. 0/1 worktree list: add --merged and --no-mergedJasper Mayone, Oct 21, 2026
  2. 1/1 worktree list: add --merged and --no-mergedJasper Mayone, Oct 21, 2026
  3. Junio C HamanoOct 23, 2026
  4. Eric SunshineOct 24, 2026
  5. worktree list: add --branch to select worktrees by branchJasper Mayone, Oct 24, 2026
  6. Phillip WoodOct 25, 2026
  7. Phillip WoodOct 26, 2026
  8. Eric SunshineOct 28, 2026
  9. Junio C HamanoOct 28, 2026
  10. Kristoffer HaugsbakkOct 28, 2026
  11. Jasper MayoneOct 29, 2026
  12. Eric SunshineOct 29, 2026
  13. Phillip WoodOct 29, 2026
  14. Ben KnobleOct 29, 2026
  15. Phillip WoodOct 29, 2026
  16. 0/2 worktree: treat a branch being rebased or bisected as checked outJasper Mayone, Oct 30, 2026
  17. 1/2 worktree remove: refuse a worktree in the middle of a rebase or bisectJasper Mayone, Oct 30, 2026
  18. Phillip WoodNov 2, 2026
  19. Jasper MayoneNov 2, 2026
  20. 2/2 ref-filter: name the worktree of a branch being rebased or bisectedJasper Mayone, Oct 30, 2026
  21. Phillip WoodNov 2, 2026
  22. Jasper MayoneNov 2, 2026
  23. Junio C HamanoOct 30, 2026
  24. Jasper MayoneOct 30, 2026
  25. 0/4 worktree: treat a branch being rebased or bisected as checked outJasper Mayone, Nov 2, 2026
  26. 1/4 worktree remove: refuse a worktree in the middle of an operationJasper Mayone, Nov 2, 2026
  27. 2/4 doc: for-each-ref: say how to read %(worktreepath) safelyJasper Mayone, Nov 2, 2026
  28. 3/4 ref-filter: name the worktree of a branch being rebased or bisectedJasper Mayone, Nov 2, 2026
  29. 4/4 branch: do not mark the branch the current worktree is rebasingJasper Mayone, Nov 2, 2026
  30. Harald NordgrenOct 21, 2026
  31. Junio C HamanoOct 21, 2026
  32. Harald NordgrenOct 22, 2026
  33. Kristoffer HaugsbakkOct 22, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.