Skip to content

Commit 188782e

Browse files
vdyegitster
authored andcommitted
ref-filter.c: use peeled tag for '*' format fields
In most builtins ('rev-parse <revision>^{}', 'show-ref --dereference'), "dereferencing" a tag refers to a recursive peel of the tag object. Unlike these cases, the dereferencing prefix ('*') in 'for-each-ref' format specifiers triggers only a single, non-recursive dereference of a given tag object. For most annotated tags, a single dereference is all that is needed to access the tag's associated commit or tree; "recursive" and "non-recursive" dereferencing are functionally equivalent in these cases. However, nested tags (annotated tags whose target is another annotated tag) dereferenced once return another tag, where a recursive dereference would return the commit or tree. Currently, if a user wants to filter & format refs and include information about a recursively-dereferenced tag, they can do so with something like 'cat-file --batch-check': git for-each-ref --format="%(objectname)^{} %(refname)" <pattern> | git cat-file --batch-check="%(objectname) %(rest)" But the combination of commands is inefficient. So, to improve the performance of this use case and align the defererencing behavior of 'for-each-ref' with that of other commands, update the ref formatting code to use the peeled tag (from 'peel_iterated_oid()') to populate '*' fields rather than the tag's immediate target object (from 'get_tagged_oid()'). Additionally, add a test to 't6300-for-each-ref' to verify new nested tag behavior and update 't6302-for-each-ref-filter.sh' to print the correct value for nested dereferenced fields. Signed-off-by: Victoria Dye <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent d1dfe6e commit 188782e

File tree

4 files changed

+30
-13
lines changed

4 files changed

+30
-13
lines changed

Documentation/git-for-each-ref.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,8 +296,8 @@ from the `committer` or `tagger` fields depending on the object type.
296296
These are intended for working on a mix of annotated and lightweight tags.
297297

298298
For tag objects, a `fieldname` prefixed with an asterisk (`*`) expands to
299-
the `fieldname` value of object the tag points at, rather than that of the
300-
tag object itself.
299+
the `fieldname` value of the peeled object, rather than that of the tag
300+
object itself.
301301

302302
Fields that have name-email-date tuple as its value (`author`,
303303
`committer`, and `tagger`) can be suffixed with `name`, `email`,

ref-filter.c

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2424,17 +2424,12 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
24242424
return 0;
24252425

24262426
/*
2427-
* If it is a tag object, see if we use a value that derefs
2428-
* the object, and if we do grab the object it refers to.
2427+
* If it is a tag object, see if we use the peeled value. If we do,
2428+
* grab the peeled OID.
24292429
*/
2430-
oi_deref.oid = *get_tagged_oid((struct tag *)obj);
2430+
if (need_tagged && peel_iterated_oid(&obj->oid, &oi_deref.oid))
2431+
die("bad tag");
24312432

2432-
/*
2433-
* NEEDSWORK: This derefs tag only once, which
2434-
* is good to deal with chains of trust, but
2435-
* is not consistent with what deref_tag() does
2436-
* which peels the onion to the core.
2437-
*/
24382433
return get_object(ref, 1, &obj, &oi_deref, err);
24392434
}
24402435

t/t6300-for-each-ref.sh

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1728,6 +1728,28 @@ test_expect_success 'git for-each-ref with non-existing refs' '
17281728
test_must_be_empty actual
17291729
'
17301730

1731+
test_expect_success 'git for-each-ref with nested tags' '
1732+
git tag -am "Normal tag" nested/base HEAD &&
1733+
git tag -am "Nested tag" nested/nest1 refs/tags/nested/base &&
1734+
git tag -am "Double nested tag" nested/nest2 refs/tags/nested/nest1 &&
1735+
1736+
head_oid="$(git rev-parse HEAD)" &&
1737+
base_tag_oid="$(git rev-parse refs/tags/nested/base)" &&
1738+
nest1_tag_oid="$(git rev-parse refs/tags/nested/nest1)" &&
1739+
nest2_tag_oid="$(git rev-parse refs/tags/nested/nest2)" &&
1740+
1741+
cat >expect <<-EOF &&
1742+
refs/tags/nested/base $base_tag_oid tag $head_oid commit
1743+
refs/tags/nested/nest1 $nest1_tag_oid tag $head_oid commit
1744+
refs/tags/nested/nest2 $nest2_tag_oid tag $head_oid commit
1745+
EOF
1746+
1747+
git for-each-ref \
1748+
--format="%(refname) %(objectname) %(objecttype) %(*objectname) %(*objecttype)" \
1749+
refs/tags/nested/ >actual &&
1750+
test_cmp expect actual
1751+
'
1752+
17311753
GRADE_FORMAT="%(signature:grade)%0a%(signature:key)%0a%(signature:signer)%0a%(signature:fingerprint)%0a%(signature:primarykeyfingerprint)"
17321754
TRUSTLEVEL_FORMAT="%(signature:trustlevel)%0a%(signature:key)%0a%(signature:signer)%0a%(signature:fingerprint)%0a%(signature:primarykeyfingerprint)"
17331755

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ test_expect_success 'check signed tags with --points-at' '
4545
sed -e "s/Z$//" >expect <<-\EOF &&
4646
refs/heads/side Z
4747
refs/tags/annotated-tag four
48-
refs/tags/doubly-annotated-tag An annotated tag
49-
refs/tags/doubly-signed-tag A signed tag
48+
refs/tags/doubly-annotated-tag four
49+
refs/tags/doubly-signed-tag four
5050
refs/tags/four Z
5151
refs/tags/signed-tag four
5252
EOF

0 commit comments

Comments
 (0)