ref-filter: handle nested tags in --points-at option

Tags are dereferenced until reaching a different object type to handle nested tags, e.g. on checkout. In contrast, "git tag --points-at=..." fails to list such nested tags because only one level of indirection is obtained in filter_refs(). Implement the recursive dereferencing for the "--points-at" option when filtering refs to unify the behaviour. Signed-off-by: Jan Klötzke <jan@kloetzke.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jan Klötzke committed Jul 1, 2023 at 22:57 UTC 468887f0f8a0a9e465737c3ad23cb40c8d690f2f
2 files changed +9 -9
ref-filter.c
+7 -9
@@ -2332,10 +2332,7 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
2332 * of oids. If the given ref is a tag, check if the given tag points
2333 * at one of the oids in the given oid array.
2334 * NEEDSWORK:
2335 - * 1. Only a single level of indirection is obtained, we might want to
2336 - * change this to account for multiple levels (e.g. annotated tags
2337 - * pointing to annotated tags pointing to a commit.)
2338 - * 2. As the refs are cached we might know what refname peels to without
2335 + * As the refs are cached we might know what refname peels to without
2336 * the need to parse the object via parse_object(). peel_ref() might be a
2337 * more efficient alternative to obtain the pointee.
2338 */
@@ -2343,18 +2340,19 @@ static const struct object_id *match_points_at(struct oid_array *points_at,
2340 const struct object_id *oid,
2341 const char *refname)
2342 {
2346 - const struct object_id *tagged_oid = NULL;
2343 struct object *obj;
2344
2345 if (oid_array_lookup(points_at, oid) >= 0)
2346 return oid;
2347 obj = parse_object(the_repository, oid);
2348 + while (obj && obj->type == OBJ_TAG) {
2349 + oid = get_tagged_oid((struct tag *)obj);
2350 + if (oid_array_lookup(points_at, oid) >= 0)
2351 + return oid;
2352 + obj = parse_object(the_repository, oid);
2353 + }
2354 if (!obj)
2355 die(_("malformed object at '%s'"), refname);
2354 - if (obj->type == OBJ_TAG)
2355 - tagged_oid = get_tagged_oid((struct tag *)obj);
2356 - if (tagged_oid && oid_array_lookup(points_at, tagged_oid) >= 0)
2357 - return tagged_oid;
2356 return NULL;
2357 }
2358
t/t6302-for-each-ref-filter.sh
+2
@@ -45,6 +45,8 @@ test_expect_success 'check signed tags with --points-at' '
45 sed -e "s/Z$//" >expect <<-\EOF &&
46 refs/heads/side Z
47 refs/tags/annotated-tag four
48 + refs/tags/doubly-annotated-tag An annotated tag
49 + refs/tags/doubly-signed-tag A signed tag
50 refs/tags/four Z
51 refs/tags/signed-tag four
52 EOF