rev-list: add commit object support in `--missing` option
The `--missing` object option in rev-list currently works only with
missing blobs/trees. For missing commits the revision walker fails with
a fatal error.
Let's extend the functionality of `--missing` option to also support
commit objects. This is done by adding a `missing_objects` field to
`rev_info`. This field is an `oidset` to which we'll add the missing
commits as we encounter them. The revision walker will now continue the
traversal and call `show_commit()` even for missing commits. In rev-list
we can then check if the commit is a missing commit and call the
existing code for parsing `--missing` objects.
A scenario where this option would be used is to find the boundary
objects between different object directories. Consider a repository with
a main object directory (GIT_OBJECT_DIRECTORY) and one or more alternate
object directories (GIT_ALTERNATE_OBJECT_DIRECTORIES). In such a
repository, using the `--missing=print` option while disabling the
alternate object directory allows us to find the boundary objects
between the main and alternate object directory.
Helped-by: Patrick Steinhardt <ps@pks.im>
Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Karthik Nayak committedOct 27, 2023 at 09:59 UTC9830926c7db626e374b887eeecb96515e2956638
index c73c92ef40..94c43138bc 100644--- a/revision.h+++ b/revision.h@@ -4,6 +4,7 @@ #include "commit.h" #include "grep.h" #include "notes.h"+#include "oidset.h" #include "pretty.h" #include "diff.h" #include "commit-slab-decl.h"@@ -373,6 +374,9 @@ struct rev_info { /* Location where temporary objects for remerge-diff are written. */ struct tmp_objdir *remerge_objdir;++ /* Missing commits to be tracked without failing traversal. */+ struct oidset missing_commits; }; /**
t/t6022-rev-list-missing.sh
+74
new file mode 100755index 0000000000..40265a4f66--- /dev/null+++ b/t/t6022-rev-list-missing.sh@@ -0,0 +1,74 @@+#!/bin/sh++test_description='handling of missing objects in rev-list'++TEST_PASSES_SANITIZE_LEAK=true+. ./test-lib.sh++# We setup the repository with two commits, this way HEAD is always+# available and we can hide commit 1.+test_expect_success 'create repository and alternate directory' '+ test_commit 1 &&+ test_commit 2 &&+ test_commit 3+'++for obj in "HEAD~1" "HEAD~1^{tree}" "HEAD:1.t"+do+ test_expect_success "rev-list --missing=error fails with missing object $obj" '+ oid="$(git rev-parse $obj)" &&+ path=".git/objects/$(test_oid_to_path $oid)" &&++ mv "$path" "$path.hidden" &&+ test_when_finished "mv $path.hidden $path" &&++ test_must_fail git rev-list --missing=error --objects \+ --no-object-names HEAD+ '+done++for obj in "HEAD~1" "HEAD~1^{tree}" "HEAD:1.t"+do+ for action in "allow-any" "print"+ do+ test_expect_success "rev-list --missing=$action with missing $obj" '+ oid="$(git rev-parse $obj)" &&+ path=".git/objects/$(test_oid_to_path $oid)" &&++ # Before the object is made missing, we use rev-list to+ # get the expected oids.+ git rev-list --objects --no-object-names \+ HEAD ^$obj >expect.raw &&++ # Blobs are shared by all commits, so evethough a commit/tree+ # might be skipped, its blob must be accounted for.+ if [ $obj != "HEAD:1.t" ]; then+ echo $(git rev-parse HEAD:1.t) >>expect.raw &&+ echo $(git rev-parse HEAD:2.t) >>expect.raw+ fi &&++ mv "$path" "$path.hidden" &&+ test_when_finished "mv $path.hidden $path" &&++ git rev-list --missing=$action --objects --no-object-names \+ HEAD >actual.raw &&++ # When the action is to print, we should also add the missing+ # oid to the expect list.+ case $action in+ allow-any)+ ;;+ print)+ grep ?$oid actual.raw &&+ echo ?$oid >>expect.raw+ ;;+ esac &&++ sort actual.raw >actual &&+ sort expect.raw >expect &&+ test_cmp expect actual+ '+ done+done++test_done