Performing geometric repacking with repositories that have alternate object directories set up is causing errors in different scenarios. - Repacking fails when the repository linked to the object directory does not have any objects on its own. ``` $ git init shared $ git -C shared commit --allow-empty --message something $ git clone --shared shared member $ git -C member repack --geometric=2 --write-midx Nothing new to pack. warning: unknown preferred pack: 'pack-3e1a94a8dc9bb4defb0d98ce2ebf325312d76362.pack' error: multi-pack-index died of signal 7 ``` - Repacking fails when the repository linked to the object directory has the exact same packfile as the linked-to object directory. ``` $ git init shared $ git -C shared commit --allow-empty --message something $ git -C shared repack -Ad $ cp -r shared member $ realpath shared/.git/objects >member/.git/objects/info/alternates $ git -C member repack --geometric 2 --write-midx fatal: could not find pack 'pack-d404037a861afe456e07a1aefb3655150f1299f0.pack' ``` Both issues have the same underlying root cause, which is that geometric repacks don't honor whether packfiles are local or not. As a result, they will try to include packs part of the alternate object directory and then at a later point fail to locate them as they do not exist in the object directory of the repository we're about to repack. Skip over packfiles that aren't local. This will cause geometric repacks to never include packfiles of its alternates. Signed-off-by: Patrick Steinhardt --- builtin/repack.c | 6 ++++ t/t7703-repack-geometric.sh | 59 +++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/builtin/repack.c b/builtin/repack.c index 87f73c8923..c6d12fa4bd 100644 --- a/builtin/repack.c +++ b/builtin/repack.c @@ -333,6 +333,12 @@ static void init_pack_geometry(struct pack_geometry **geometry_p, geometry = *geometry_p; for (p = get_all_packs(the_repository); p; p = p->next) { + /* + * We don't want to repack packfiles which are not part of the + * primary object database. + */ + if (!p->pack_local) + continue; if (!pack_kept_objects) { /* * Any pack that has its pack_keep bit set will appear diff --git a/t/t7703-repack-geometric.sh b/t/t7703-repack-geometric.sh index 8821fbd2dd..9f8bc663e4 100755 --- a/t/t7703-repack-geometric.sh +++ b/t/t7703-repack-geometric.sh @@ -281,4 +281,63 @@ test_expect_success '--geometric with pack.packSizeLimit' ' ) ' +packed_objects() { + git verify-pack -v "$@" >tmp-object-list && + sed -n -e "s/^\([0-9a-f][0-9a-f]*\).*\(commit\|tree\|blob\|tag\).*/\1/p" actual && + test_must_be_empty actual +' + +test_expect_success '--geometric does not include shared packfiles' ' + git init shared && + test_when_finished "rm -fr shared" && + test_commit -C shared "shared" && + git -C shared repack -Ad && + + git clone --shared shared member && + test_when_finished "rm -fr member" && + git -C member commit --allow-empty --message "not-shared" && + git -C member repack --geometric 2 --write-midx && + + # We expect the created packfile to only contain the new commit. + packed_objects member/.git/objects/pack/pack-*.idx >actual && + git -C member rev-parse HEAD >expect && + test_cmp expect actual +' + +test_expect_success '--geometric with same packfile in shared repository' ' + git init shared && + test_when_finished "rm -fr shared" && + test_commit -C shared "shared" && + git -C shared repack -Ad && + + # Prepare the member repository so that it got the exact same packfile + # as the shared repository and set up gitalternates. + cp -r shared member && + test_when_finished "rm -fr member" && + test-tool path-utils real_path shared/.git/objects >member/.git/objects/info/alternates && + find shared/.git/objects -type f >expect && + + # After repacking, contents of the member repository should not have + # changed. + git -C member repack --geometric 2 --write-midx 2>error && + find shared/.git/objects -type f >actual && + test_cmp expect actual +' + test_done -- 2.40.0