From: Jasper Mayone Date: Mon, 02 Nov 2026 18:29:30 GMT Subject: [PATCH v4 4/4] branch: do not mark the branch the current worktree is rebasing 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 Signed-off-by: Jasper Mayone --- 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