From: Jasper Mayone <me@jaspermayone.com>
To: git@vger.kernel.org
Cc: gitster@pobox.com, phillip.wood123@gmail.com,
sunshine@sunshineco.com, kristofferhaugsbakk@fastmail.com,
ben.knoble@gmail.com, haraldnordgren@gmail.com,
Jasper Mayone <me@jaspermayone.com>
Subject: [PATCH v5 4/5] ref-filter: add %(currentworktree)
Date: Wed, 11 Nov 2026 10:28:09 -0500 [thread overview]
Message-ID: <20261111152811.99986-5-me@jaspermayone.com> (raw)
In-Reply-To: <20261111152811.99986-1-me@jaspermayone.com>
%(worktreepath) names the worktree that has a branch checked out, or
is rebasing or bisecting it, but a format cannot tell if that worktree
is the current one. Comparing %(worktreepath) with a fixed path in
%(if:equals=...) does not work for every path, because a ")" ends the
atom.
Add %(currentworktree), which gives the path of the current worktree
when that worktree has the branch, and an empty string otherwise.
branch.c records these branches when it reads the worktrees, in a
second map next to the one that %(worktreepath) uses, so the lookup is
one map lookup per ref.
The next commit uses it in "git branch".
Suggested-by: Phillip Wood <phillip.wood123@gmail.com>
Signed-off-by: Jasper Mayone <me@jaspermayone.com>
---
Documentation/git-for-each-ref.adoc | 7 +++++++
branch.c | 25 ++++++++++++++++++-------
branch.h | 7 +++++++
ref-filter.c | 10 ++++++++++
t/t6302-for-each-ref-filter.sh | 21 +++++++++++++++++++++
5 files changed, 63 insertions(+), 7 deletions(-)
diff --git a/Documentation/git-for-each-ref.adoc b/Documentation/git-for-each-ref.adoc
index 4456b4809a..5e2da92ee2 100644
--- a/Documentation/git-for-each-ref.adoc
+++ b/Documentation/git-for-each-ref.adoc
@@ -193,6 +193,13 @@ but if used together the last option is selected.
the `NUL` after the path and then for the `LF` that ends each
record.
+`currentworktree`::
+ The absolute path to the current worktree, if the ref is checked
+ out there, in the same sense as for `worktreepath`. Empty string
+ otherwise, also when the ref is checked out only in other
+ worktrees. Use it with `%(if)` to treat the current worktree
+ differently from the others.
+
`ahead-behind:<commit-ish>`::
Two integers, separated by a space, demonstrating the number of
commits ahead and behind, respectively, when comparing the output
diff --git a/branch.c b/branch.c
index 87f3ffc35f..4de789b7ae 100644
--- a/branch.c
+++ b/branch.c
@@ -386,6 +386,8 @@ static int initialized_checked_out_branches;
static struct strmap current_checked_out_branches = STRMAP_INIT;
/* Like current_checked_out_branches, without the "update-ref" branches. */
static struct strmap checked_out_worktrees = STRMAP_INIT;
+/* The subset of checked_out_worktrees that the current worktree has. */
+static struct strmap current_worktree_branches = STRMAP_INIT;
enum branch_checkout_kind {
BRANCH_CHECKOUT_KIND_CHECKOUT,
@@ -404,11 +406,11 @@ static struct checked_out_branch *checked_out_branches;
static size_t checked_out_branches_alloc, checked_out_branches_nr;
static void register_checked_out_branch(const char *prefix, const char *name,
- const char *path,
+ const struct worktree *wt,
enum branch_checkout_kind kind)
{
char *refname = xstrfmt("%s%s", prefix, name);
- char *path_copy = xstrdup(path);
+ char *path_copy = xstrdup(wt->path);
ALLOC_GROW(checked_out_branches, checked_out_branches_nr + 1,
checked_out_branches_alloc);
@@ -418,8 +420,11 @@ static void register_checked_out_branch(const char *prefix, const char *name,
checked_out_branches_nr++;
strmap_put(¤t_checked_out_branches, refname, path_copy);
- if (kind != BRANCH_CHECKOUT_KIND_UPDATE_REF)
+ if (kind != BRANCH_CHECKOUT_KIND_UPDATE_REF) {
strmap_put(&checked_out_worktrees, refname, path_copy);
+ if (wt->is_current)
+ strmap_put(¤t_worktree_branches, refname, path_copy);
+ }
}
static void prepare_checked_out_branches(void)
@@ -443,7 +448,7 @@ static void prepare_checked_out_branches(void)
continue;
if (wt->head_ref) {
- register_checked_out_branch("", wt->head_ref, wt->path,
+ register_checked_out_branch("", wt->head_ref, wt,
BRANCH_CHECKOUT_KIND_CHECKOUT);
}
@@ -451,7 +456,7 @@ static void prepare_checked_out_branches(void)
(state.rebase_in_progress || state.rebase_interactive_in_progress) &&
state.branch) {
register_checked_out_branch("refs/heads/", state.branch,
- wt->path,
+ wt,
BRANCH_CHECKOUT_KIND_REBASE);
}
wt_status_state_free_buffers(&state);
@@ -460,7 +465,7 @@ static void prepare_checked_out_branches(void)
state.bisecting_from) {
register_checked_out_branch("refs/heads/",
state.bisecting_from,
- wt->path,
+ wt,
BRANCH_CHECKOUT_KIND_BISECT);
}
wt_status_state_free_buffers(&state);
@@ -471,7 +476,7 @@ static void prepare_checked_out_branches(void)
struct string_list_item *item;
for_each_string_list_item(item, &update_refs) {
register_checked_out_branch("", item->string,
- wt->path,
+ wt,
BRANCH_CHECKOUT_KIND_UPDATE_REF);
}
string_list_clear(&update_refs, 1);
@@ -495,6 +500,12 @@ const char *branch_checked_out_worktree(const char *refname)
return strmap_get(&checked_out_worktrees, refname);
}
+const char *branch_checked_out_current_worktree(const char *refname)
+{
+ prepare_checked_out_branches();
+ return strmap_get(¤t_worktree_branches, refname);
+}
+
const char *branch_bisecting(const char *refname)
{
prepare_checked_out_branches();
diff --git a/branch.h b/branch.h
index 60cb92a3e4..744e1eec1d 100644
--- a/branch.h
+++ b/branch.h
@@ -115,6 +115,13 @@ const char *branch_checked_out(const char *refname);
*/
const char *branch_checked_out_worktree(const char *refname);
+/*
+ * Like branch_checked_out_worktree(), but only for the current
+ * worktree: return its path if it has the branch 'refname' checked
+ * out, or is rebasing or bisecting it. Otherwise return NULL.
+ */
+const char *branch_checked_out_current_worktree(const char *refname);
+
/*
* If the branch at 'refname' is currently used for bisecting in a
* worktree, then return the path to that worktree.
diff --git a/ref-filter.c b/ref-filter.c
index b636e56199..498d09da8f 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -142,6 +142,7 @@ enum atom_type {
ATOM_HEAD,
ATOM_COLOR,
ATOM_WORKTREEPATH,
+ ATOM_CURRENTWORKTREE,
ATOM_ALIGN,
ATOM_END,
ATOM_IF,
@@ -960,6 +961,7 @@ static struct {
[ATOM_HEAD] = { "HEAD", SOURCE_NONE, FIELD_STR, head_atom_parser },
[ATOM_COLOR] = { "color", SOURCE_NONE, FIELD_STR, color_atom_parser },
[ATOM_WORKTREEPATH] = { "worktreepath", SOURCE_NONE },
+ [ATOM_CURRENTWORKTREE] = { "currentworktree", SOURCE_NONE },
[ATOM_ALIGN] = { "align", SOURCE_NONE, FIELD_STR, align_atom_parser },
[ATOM_END] = { "end", SOURCE_NONE },
[ATOM_IF] = { "if", SOURCE_NONE, FIELD_STR, if_atom_parser },
@@ -2420,6 +2422,14 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
v->s = xstrdup("");
continue;
}
+ else if (atom_type == ATOM_CURRENTWORKTREE) {
+ const char *path = NULL;
+
+ if (ref->kind == FILTER_REFS_BRANCHES)
+ path = branch_checked_out_current_worktree(ref->refname);
+ v->s = xstrdup(path ? path : "");
+ continue;
+ }
else if (atom_type == ATOM_SYMREF)
refname = get_symref(atom, ref);
else if (atom_type == ATOM_UPSTREAM) {
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index 317ed6f6cd..32522f1ff3 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -617,6 +617,27 @@ test_expect_success 'worktree atom ignores the HEAD of a bare repository' '
test_cmp expect actual
'
+test_expect_success 'currentworktree atom' '
+ test_when_finished "git -C current rebase --abort; rm -rf current; git worktree prune; git branch -D current" &&
+ git worktree add -b current current main &&
+ git -C current commit --allow-empty -m rebase-me &&
+ test_must_fail git -C current rebase -f -x false main &&
+ git for-each-ref --format="%(refname:short) [%(currentworktree)]" \
+ refs/heads/main refs/heads/current >actual &&
+ cat >expect <<-EOF &&
+ current []
+ main [$(pwd)]
+ EOF
+ test_cmp expect actual &&
+ git -C current for-each-ref --format="%(refname:short) [%(currentworktree)]" \
+ refs/heads/main refs/heads/current >actual &&
+ cat >expect <<-EOF &&
+ current [$(pwd)/current]
+ main []
+ EOF
+ test_cmp expect actual
+'
+
test_expect_success 'start after with empty value' '
cat >expect <<-\EOF &&
refs/heads/main
--
2.56.0
next prev parent reply other threads:[~2026-11-11 15:28 UTC|newest]
Thread overview: 50+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-21 17:33 [RFC PATCH 0/1] worktree list: add --merged and --no-merged Jasper Mayone
2026-10-21 17:33 ` [RFC PATCH 1/1] " Jasper Mayone
2026-10-23 18:30 ` Junio C Hamano
2026-10-24 6:25 ` Eric Sunshine
2026-10-24 16:53 ` [PATCH v2] worktree list: add --branch to select worktrees by branch Jasper Mayone
2026-10-25 14:47 ` Phillip Wood
2026-10-26 11:02 ` Phillip Wood
2026-10-28 6:02 ` Eric Sunshine
2026-10-28 15:27 ` Junio C Hamano
2026-10-28 11:32 ` Kristoffer Haugsbakk
2026-10-29 4:46 ` Jasper Mayone
2026-10-29 5:01 ` Eric Sunshine
2026-10-29 11:14 ` Phillip Wood
2026-10-29 14:23 ` Ben Knoble
2026-10-29 16:10 ` Phillip Wood
2026-10-30 14:21 ` [PATCH 0/2] worktree: treat a branch being rebased or bisected as checked out Jasper Mayone
2026-10-30 14:21 ` [PATCH 1/2] worktree remove: refuse a worktree in the middle of a rebase or bisect Jasper Mayone
2026-11-02 14:07 ` Phillip Wood
2026-11-02 17:57 ` Jasper Mayone
2026-10-30 14:21 ` [PATCH 2/2] ref-filter: name the worktree of a branch being rebased or bisected Jasper Mayone
2026-11-02 14:06 ` Phillip Wood
2026-11-02 17:57 ` Jasper Mayone
2026-10-30 22:55 ` [PATCH 0/2] worktree: treat a branch being rebased or bisected as checked out Junio C Hamano
2026-10-30 23:06 ` Jasper Mayone
2026-11-02 18:29 ` [PATCH v4 0/4] " Jasper Mayone
2026-11-02 18:29 ` [PATCH v4 1/4] worktree remove: refuse a worktree in the middle of an operation Jasper Mayone
2026-11-10 16:47 ` Phillip Wood
2026-11-10 17:09 ` Ben Knoble
2026-11-02 18:29 ` [PATCH v4 2/4] doc: for-each-ref: say how to read %(worktreepath) safely Jasper Mayone
2026-11-09 12:36 ` D. Ben Knoble
2026-11-09 15:10 ` Phillip Wood
2026-11-09 17:27 ` Ben Knoble
2026-11-09 20:17 ` Junio C Hamano
2026-11-10 16:47 ` Phillip Wood
2026-11-02 18:29 ` [PATCH v4 3/4] ref-filter: name the worktree of a branch being rebased or bisected Jasper Mayone
2026-11-10 16:47 ` Phillip Wood
2026-11-02 18:29 ` [PATCH v4 4/4] branch: do not mark the branch the current worktree is rebasing Jasper Mayone
2026-11-10 16:45 ` Phillip Wood
2026-11-10 16:49 ` [PATCH v4 0/4] worktree: treat a branch being rebased or bisected as checked out Phillip Wood
2026-11-11 15:28 ` [PATCH v5 0/5] " Jasper Mayone
2026-11-11 15:28 ` [PATCH v5 1/5] worktree remove: refuse a worktree in the middle of an operation Jasper Mayone
2026-11-11 15:28 ` [PATCH v5 2/5] doc: for-each-ref: say how to read %(worktreepath) safely Jasper Mayone
2026-11-11 15:28 ` [PATCH v5 3/5] ref-filter: name the worktree of a branch being rebased or bisected Jasper Mayone
2026-11-11 15:28 ` Jasper Mayone [this message]
2026-11-11 15:28 ` [PATCH v5 5/5] branch: do not mark the branch the current worktree is rebasing Jasper Mayone
2026-11-11 15:42 ` [PATCH v5 0/5] worktree: treat a branch being rebased or bisected as checked out Ben Knoble
2026-10-21 21:36 ` [RFC PATCH 0/1] worktree list: add --merged and --no-merged Harald Nordgren
2026-10-21 22:12 ` Junio C Hamano
2026-10-22 7:21 ` Harald Nordgren
2026-10-22 17:58 ` Kristoffer Haugsbakk
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261111152811.99986-5-me@jaspermayone.com \
--to=me@jaspermayone.com \
--cc=ben.knoble@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=haraldnordgren@gmail.com \
--cc=kristofferhaugsbakk@fastmail.com \
--cc=phillip.wood123@gmail.com \
--cc=sunshine@sunshineco.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox