revision: fix --missing=[print|allow*] for annotated tags

In 9830926c7d (rev-list: add commit object support in `--missing` option, 2023-10-27) we fixed the `--missing` option in `git rev-list` so that it works with missing commits, not just blobs/trees. Unfortunately, such a command was still failing with a "fatal: bad object <oid>" if it was passed a missing commit, blob or tree as an argument (before the rev walking even begins). This was fixed in a recent commit. That fix still doesn't work when an argument passed to the command is an annotated tag pointing to a missing commit though. In that case `git rev-list --missing=...` still errors out with a "fatal: bad object <oid>" error where <oid> is the object ID of the missing commit. Let's fix this issue, and also, while at it, let's add tests not just for annotated tags but also for regular tags and branches. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Christian Couder committed Feb 28, 2024 at 10:10 UTC a4324babe679352a801310f8e30f3cbcd9c1f16b
2 files changed +25 -7
revision.c
+7 -1
@@ -419,15 +419,21 @@ static struct commit *handle_commit(struct rev_info *revs,
419 */
420 while (object->type == OBJ_TAG) {
421 struct tag *tag = (struct tag *) object;
422 + struct object_id *oid;
423 if (revs->tag_objects && !(flags & UNINTERESTING))
424 add_pending_object(revs, object, tag->tag);
424 - object = parse_object(revs->repo, get_tagged_oid(tag));
425 + oid = get_tagged_oid(tag);
426 + object = parse_object(revs->repo, oid);
427 if (!object) {
428 if (revs->ignore_missing_links || (flags & UNINTERESTING))
429 return NULL;
430 if (revs->exclude_promisor_objects &&
431 is_promisor_object(&tag->tagged->oid))
432 return NULL;
433 + if (revs->do_not_die_on_missing_objects && oid) {
434 + oidset_insert(&revs->missing_commits, oid);
435 + return NULL;
436 + }
437 die("bad object %s", oid_to_hex(&tag->tagged->oid));
438 }
439 object->flags |= flags;
t/t6022-rev-list-missing.sh
+18 -6
@@ -10,7 +10,10 @@ TEST_PASSES_SANITIZE_LEAK=true
10 test_expect_success 'create repository and alternate directory' '
11 test_commit 1 &&
12 test_commit 2 &&
13 - test_commit 3
13 + test_commit 3 &&
14 + git tag -m "tag message" annot_tag HEAD~1 &&
15 + git tag regul_tag HEAD~1 &&
16 + git branch a_branch HEAD~1
17 '
18
19 # We manually corrupt the repository, which means that the commit-graph may
@@ -78,7 +81,7 @@ do
81 done
82 done
83
81 -for missing_tip in "HEAD~1" "HEAD~1^{tree}" "HEAD:1.t"
84 +for missing_tip in "annot_tag" "regul_tag" "a_branch" "HEAD~1" "HEAD~1^{tree}" "HEAD:1.t"
85 do
86 # We want to check that things work when both
87 # - all the tips passed are missing (case existing_tip = ""), and
@@ -88,9 +91,6 @@ do
91 for action in "allow-any" "print"
92 do
93 test_expect_success "--missing=$action with tip '$missing_tip' missing and tip '$existing_tip'" '
91 - oid="$(git rev-parse $missing_tip)" &&
92 - path=".git/objects/$(test_oid_to_path $oid)" &&
93 -
94 # Before the object is made missing, we use rev-list to
95 # get the expected oids.
96 if test "$existing_tip" = "HEAD"
@@ -109,11 +109,23 @@ do
109 echo $(git rev-parse HEAD:2.t) >>expect.raw
110 fi &&
111
112 + missing_oid="$(git rev-parse $missing_tip)" &&
113 +
114 + if test "$missing_tip" = "annot_tag"
115 + then
116 + oid="$(git rev-parse $missing_tip^{commit})" &&
117 + echo "$missing_oid" >>expect.raw
118 + else
119 + oid="$missing_oid"
120 + fi &&
121 +
122 + path=".git/objects/$(test_oid_to_path $oid)" &&
123 +
124 mv "$path" "$path.hidden" &&
125 test_when_finished "mv $path.hidden $path" &&
126
127 git rev-list --missing=$action --objects --no-object-names \
116 - $oid $existing_tip >actual.raw &&
128 + $missing_oid $existing_tip >actual.raw &&
129
130 # When the action is to print, we should also add the missing
131 # oid to the expect list.