The revision backend is used by multiple porcelain commands such as git-rev-list(1) and git-log(1). The backend currently supports ignoring missing links by setting the `ignore_missing_links` bit. This allows the revision walk to skip any objects links which are missing. Currently there is no way to use git-rev-list(1) to traverse the objects of the main object directory (GIT_OBJECT_DIRECTORY) and print the boundary objects when moving from the main object directory to the alternate object directories (GIT_ALTERNATE_OBJECT_DIRECTORIES). By exposing this new flag `--ignore-missing-links`, users can set the required env variables (GIT_OBJECT_DIRECTORY and GIT_ALTERNATE_OBJECT_DIRECTORIES) along with the `--boundary` flag to find the boundary objects between object directories. Signed-off-by: Karthik Nayak <karthik.188@xxxxxxxxx> --- Documentation/rev-list-options.txt | 5 ++++ revision.c | 2 ++ t/t6022-rev-list-alternates.sh | 43 ++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100755 t/t6022-rev-list-alternates.sh diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index a4a0cb93b2..a0b48db8a8 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -227,6 +227,11 @@ explicitly. Upon seeing an invalid object name in the input, pretend as if the bad input was not given. +--ignore-missing-links:: + When an object points to another object that is missing, pretend as if the + link did not exist. These missing links are not written to stdout unless + the --boundary flag is passed. + ifndef::git-rev-list[] --bisect:: Pretend as if the bad bisection ref `refs/bisect/bad` diff --git a/revision.c b/revision.c index 2f4c53ea20..cbfcbf6e28 100644 --- a/revision.c +++ b/revision.c @@ -2595,6 +2595,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg revs->limited = 1; } else if (!strcmp(arg, "--ignore-missing")) { revs->ignore_missing = 1; + } else if (!strcmp(arg, "--ignore-missing-links")) { + revs->ignore_missing_links = 1; } else if (opt && opt->allow_exclude_promisor_objects && !strcmp(arg, "--exclude-promisor-objects")) { if (fetch_if_missing) diff --git a/t/t6022-rev-list-alternates.sh b/t/t6022-rev-list-alternates.sh new file mode 100755 index 0000000000..626ebb2dce --- /dev/null +++ b/t/t6022-rev-list-alternates.sh @@ -0,0 +1,43 @@ +#!/bin/sh + +test_description='handling of alternates in rev-list' + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +# We create 5 commits and move them to the alt directory and +# create 5 more commits which will stay in the main odb. +test_expect_success 'create repository and alternate directory' ' + git init main && + test_commit_bulk -C main 5 && + mkdir alt && + mv main/.git/objects/* alt && + GIT_ALTERNATE_OBJECT_DIRECTORIES=$PWD/alt test_commit_bulk --start=6 -C main 5 +' + +# When the alternate odb is provided, all commits are listed. +test_expect_success 'rev-list passes with alternate object directory' ' + GIT_ALTERNATE_OBJECT_DIRECTORIES=$PWD/alt test_stdout_line_count = 10 git -C main rev-list HEAD +' + +# When the alternate odb is not provided, rev-list fails since the 5th commit's +# parent is not present in the main odb. +test_expect_success 'rev-list fails without alternate object directory' ' + test_must_fail git -C main rev-list HEAD +' + +# With `--ignore-missing-links`, we stop the traversal when we encounter a +# missing link. +test_expect_success 'rev-list only prints main odb commits with --ignore-missing-links' ' + test_stdout_line_count = 5 git -C main rev-list --ignore-missing-links HEAD +' + +# With `--ignore-missing-links` and `--boundary`, we can even print those boundary +# commits. +test_expect_success 'rev-list prints boundary commit with --ignore-missing-links' ' + git -C main rev-list --ignore-missing-links --boundary HEAD >list-output && + test_stdout_line_count = 6 cat list-output && + test_stdout_line_count = 1 cat list-output | grep "^-" +' + +test_done -- 2.41.0