Git development
 help / color / mirror / Atom feed
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(&current_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(&current_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(&current_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


  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