Skip to content

Commit 2582083

Browse files
nbelakovskigitster
authored andcommitted
ref-filter: add worktreepath atom
Add an atom providing the path of the linked worktree where this ref is checked out, if it is checked out in any linked worktrees, and empty string otherwise. Signed-off-by: Nickolai Belakovski <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 0e94f7a commit 2582083

File tree

3 files changed

+96
-0
lines changed

3 files changed

+96
-0
lines changed

Documentation/git-for-each-ref.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,11 @@ symref::
214214
`:lstrip` and `:rstrip` options in the same way as `refname`
215215
above.
216216

217+
worktreepath::
218+
The absolute path to the worktree in which the ref is checked
219+
out, if it is checked out in any linked worktree. Empty string
220+
otherwise.
221+
217222
In addition to the above, for commit and tag objects, the header
218223
field names (`tree`, `parent`, `object`, `type`, and `tag`) can
219224
be used to specify the value in the header field.

ref-filter.c

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#include "commit-slab.h"
2121
#include "commit-graph.h"
2222
#include "commit-reach.h"
23+
#include "worktree.h"
24+
#include "hashmap.h"
2325

2426
static struct ref_msg {
2527
const char *gone;
@@ -75,6 +77,27 @@ static struct expand_data {
7577
struct object_info info;
7678
} oi, oi_deref;
7779

80+
struct ref_to_worktree_entry {
81+
struct hashmap_entry ent; /* must be the first member! */
82+
struct worktree *wt; /* key is wt->head_ref */
83+
};
84+
85+
static int ref_to_worktree_map_cmpfnc(const void *unused_lookupdata,
86+
const void *existing_hashmap_entry_to_test,
87+
const void *key,
88+
const void *keydata_aka_refname)
89+
{
90+
const struct ref_to_worktree_entry *e = existing_hashmap_entry_to_test;
91+
const struct ref_to_worktree_entry *k = key;
92+
return strcmp(e->wt->head_ref,
93+
keydata_aka_refname ? keydata_aka_refname : k->wt->head_ref);
94+
}
95+
96+
static struct ref_to_worktree_map {
97+
struct hashmap map;
98+
struct worktree **worktrees;
99+
} ref_to_worktree_map;
100+
78101
/*
79102
* An atom is a valid field atom listed below, possibly prefixed with
80103
* a "*" to denote deref_tag().
@@ -480,6 +503,7 @@ static struct {
480503
{ "flag", SOURCE_NONE },
481504
{ "HEAD", SOURCE_NONE, FIELD_STR, head_atom_parser },
482505
{ "color", SOURCE_NONE, FIELD_STR, color_atom_parser },
506+
{ "worktreepath", SOURCE_NONE },
483507
{ "align", SOURCE_NONE, FIELD_STR, align_atom_parser },
484508
{ "end", SOURCE_NONE },
485509
{ "if", SOURCE_NONE, FIELD_STR, if_atom_parser },
@@ -1529,6 +1553,48 @@ static int get_object(struct ref_array_item *ref, int deref, struct object **obj
15291553
return 0;
15301554
}
15311555

1556+
static void populate_worktree_map(struct hashmap *map, struct worktree **worktrees)
1557+
{
1558+
int i;
1559+
1560+
for (i = 0; worktrees[i]; i++) {
1561+
if (worktrees[i]->head_ref) {
1562+
struct ref_to_worktree_entry *entry;
1563+
entry = xmalloc(sizeof(*entry));
1564+
entry->wt = worktrees[i];
1565+
hashmap_entry_init(entry, strhash(worktrees[i]->head_ref));
1566+
1567+
hashmap_add(map, entry);
1568+
}
1569+
}
1570+
}
1571+
1572+
static void lazy_init_worktree_map(void)
1573+
{
1574+
if (ref_to_worktree_map.worktrees)
1575+
return;
1576+
1577+
ref_to_worktree_map.worktrees = get_worktrees(0);
1578+
hashmap_init(&(ref_to_worktree_map.map), ref_to_worktree_map_cmpfnc, NULL, 0);
1579+
populate_worktree_map(&(ref_to_worktree_map.map), ref_to_worktree_map.worktrees);
1580+
}
1581+
1582+
static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)
1583+
{
1584+
struct hashmap_entry entry;
1585+
struct ref_to_worktree_entry *lookup_result;
1586+
1587+
lazy_init_worktree_map();
1588+
1589+
hashmap_entry_init(&entry, strhash(ref->refname));
1590+
lookup_result = hashmap_get(&(ref_to_worktree_map.map), &entry, ref->refname);
1591+
1592+
if (lookup_result)
1593+
return xstrdup(lookup_result->wt->path);
1594+
else
1595+
return xstrdup("");
1596+
}
1597+
15321598
/*
15331599
* Parse the object referred by ref, and grab needed value.
15341600
*/
@@ -1566,6 +1632,13 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
15661632

15671633
if (starts_with(name, "refname"))
15681634
refname = get_refname(atom, ref);
1635+
else if (!strcmp(name, "worktreepath")) {
1636+
if (ref->kind == FILTER_REFS_BRANCHES)
1637+
v->s = get_worktree_path(atom, ref);
1638+
else
1639+
v->s = xstrdup("");
1640+
continue;
1641+
}
15691642
else if (starts_with(name, "symref"))
15701643
refname = get_symref(atom, ref);
15711644
else if (starts_with(name, "upstream")) {
@@ -2049,6 +2122,11 @@ void ref_array_clear(struct ref_array *array)
20492122
free_array_item(array->items[i]);
20502123
FREE_AND_NULL(array->items);
20512124
array->nr = array->alloc = 0;
2125+
if (ref_to_worktree_map.worktrees) {
2126+
hashmap_free(&(ref_to_worktree_map.map), 1);
2127+
free_worktrees(ref_to_worktree_map.worktrees);
2128+
ref_to_worktree_map.worktrees = NULL;
2129+
}
20522130
}
20532131

20542132
static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)

t/t6302-for-each-ref-filter.sh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,4 +441,17 @@ test_expect_success '--merged is incompatible with --no-merged' '
441441
test_must_fail git for-each-ref --merged HEAD --no-merged HEAD
442442
'
443443

444+
test_expect_success 'validate worktree atom' '
445+
cat >expect <<-EOF &&
446+
master: $(pwd)
447+
master_worktree: $(pwd)/worktree_dir
448+
side: not checked out
449+
EOF
450+
git worktree add -b master_worktree worktree_dir master &&
451+
git for-each-ref --format="%(refname:short): %(if)%(worktreepath)%(then)%(worktreepath)%(else)not checked out%(end)" refs/heads/ >actual &&
452+
rm -r worktree_dir &&
453+
git worktree prune &&
454+
test_cmp expect actual
455+
'
456+
444457
test_done

0 commit comments

Comments
 (0)