summaryrefslogtreecommitdiffstats
path: root/t/t7703-repack-geometric.sh
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xt/t7703-repack-geometric.sh448
1 files changed, 448 insertions, 0 deletions
diff --git a/t/t7703-repack-geometric.sh b/t/t7703-repack-geometric.sh
new file mode 100755
index 0000000..9fc1626
--- /dev/null
+++ b/t/t7703-repack-geometric.sh
@@ -0,0 +1,448 @@
+#!/bin/sh
+
+test_description='git repack --geometric works correctly'
+
+. ./test-lib.sh
+
+GIT_TEST_MULTI_PACK_INDEX=0
+
+objdir=.git/objects
+packdir=$objdir/pack
+midx=$objdir/pack/multi-pack-index
+
+packed_objects () {
+ git show-index <"$1" >tmp-object-list &&
+ cut -d' ' -f2 tmp-object-list | sort &&
+ rm tmp-object-list
+ }
+
+test_expect_success '--geometric with no packs' '
+ git init geometric &&
+ test_when_finished "rm -fr geometric" &&
+ (
+ cd geometric &&
+
+ git repack --write-midx --geometric 2 >out &&
+ test_grep "Nothing new to pack" out
+ )
+'
+
+test_expect_success '--geometric with one pack' '
+ git init geometric &&
+ test_when_finished "rm -fr geometric" &&
+ (
+ cd geometric &&
+
+ test_commit "base" &&
+ git repack -d &&
+
+ git repack --geometric 2 >out &&
+
+ test_grep "Nothing new to pack" out
+ )
+'
+
+test_expect_success '--geometric with an intact progression' '
+ git init geometric &&
+ test_when_finished "rm -fr geometric" &&
+ (
+ cd geometric &&
+
+ # These packs already form a geometric progression.
+ test_commit_bulk --start=1 1 && # 3 objects
+ test_commit_bulk --start=2 2 && # 6 objects
+ test_commit_bulk --start=4 4 && # 12 objects
+
+ find $objdir/pack -name "*.pack" | sort >expect &&
+ git repack --geometric 2 -d &&
+ find $objdir/pack -name "*.pack" | sort >actual &&
+
+ test_cmp expect actual
+ )
+'
+
+test_expect_success '--geometric with loose objects' '
+ git init geometric &&
+ test_when_finished "rm -fr geometric" &&
+ (
+ cd geometric &&
+
+ # These packs already form a geometric progression.
+ test_commit_bulk --start=1 1 && # 3 objects
+ test_commit_bulk --start=2 2 && # 6 objects
+ # The loose objects are packed together, breaking the
+ # progression.
+ test_commit loose && # 3 objects
+
+ find $objdir/pack -name "*.pack" | sort >before &&
+ git repack --geometric 2 -d &&
+ find $objdir/pack -name "*.pack" | sort >after &&
+
+ comm -13 before after >new &&
+ comm -23 before after >removed &&
+
+ test_line_count = 1 new &&
+ test_must_be_empty removed &&
+
+ git repack --geometric 2 -d &&
+ find $objdir/pack -name "*.pack" | sort >after &&
+
+ # The progression (3, 3, 6) is combined into one new pack.
+ test_line_count = 1 after
+ )
+'
+
+test_expect_success '--geometric with small-pack rollup' '
+ git init geometric &&
+ test_when_finished "rm -fr geometric" &&
+ (
+ cd geometric &&
+
+ test_commit_bulk --start=1 1 && # 3 objects
+ test_commit_bulk --start=2 1 && # 3 objects
+ find $objdir/pack -name "*.pack" | sort >small &&
+ test_commit_bulk --start=3 4 && # 12 objects
+ test_commit_bulk --start=7 8 && # 24 objects
+ find $objdir/pack -name "*.pack" | sort >before &&
+
+ git repack --geometric 2 -d &&
+
+ # Three packs in total; two of the existing large ones, and one
+ # new one.
+ find $objdir/pack -name "*.pack" | sort >after &&
+ test_line_count = 3 after &&
+ comm -3 small before | tr -d "\t" >large &&
+ grep -qFf large after
+ )
+'
+
+test_expect_success '--geometric with small- and large-pack rollup' '
+ git init geometric &&
+ test_when_finished "rm -fr geometric" &&
+ (
+ cd geometric &&
+
+ # size(small1) + size(small2) > size(medium) / 2
+ test_commit_bulk --start=1 1 && # 3 objects
+ test_commit_bulk --start=2 1 && # 3 objects
+ test_commit_bulk --start=2 3 && # 7 objects
+ test_commit_bulk --start=6 9 && # 27 objects &&
+
+ find $objdir/pack -name "*.pack" | sort >before &&
+
+ git repack --geometric 2 -d &&
+
+ find $objdir/pack -name "*.pack" | sort >after &&
+ comm -12 before after >untouched &&
+
+ # Two packs in total; the largest pack from before running "git
+ # repack", and one new one.
+ test_line_count = 1 untouched &&
+ test_line_count = 2 after
+ )
+'
+
+test_expect_success '--geometric ignores kept packs' '
+ git init geometric &&
+ test_when_finished "rm -fr geometric" &&
+ (
+ cd geometric &&
+
+ test_commit kept && # 3 objects
+ test_commit pack && # 3 objects
+
+ KEPT=$(git pack-objects --revs $objdir/pack/pack <<-EOF
+ refs/tags/kept
+ EOF
+ ) &&
+ PACK=$(git pack-objects --revs $objdir/pack/pack <<-EOF
+ refs/tags/pack
+ ^refs/tags/kept
+ EOF
+ ) &&
+
+ # neither pack contains more than twice the number of objects in
+ # the other, so they should be combined. but, marking one as
+ # .kept on disk will "freeze" it, so the pack structure should
+ # remain unchanged.
+ touch $objdir/pack/pack-$KEPT.keep &&
+
+ find $objdir/pack -name "*.pack" | sort >before &&
+ git repack --geometric 2 -d &&
+ find $objdir/pack -name "*.pack" | sort >after &&
+
+ # both packs should still exist
+ test_path_is_file $objdir/pack/pack-$KEPT.pack &&
+ test_path_is_file $objdir/pack/pack-$PACK.pack &&
+
+ # and no new packs should be created
+ test_cmp before after &&
+
+ # Passing --pack-kept-objects causes packs with a .keep file to
+ # be repacked, too.
+ git repack --geometric 2 -d --pack-kept-objects &&
+
+ # After repacking, two packs remain: one new one (containing the
+ # objects in both the .keep and non-kept pack), and the .keep
+ # pack (since `--pack-kept-objects -d` does not actually delete
+ # the kept pack).
+ find $objdir/pack -name "*.pack" >after &&
+ test_line_count = 2 after
+ )
+'
+
+test_expect_success '--geometric ignores --keep-pack packs' '
+ git init geometric &&
+ test_when_finished "rm -fr geometric" &&
+ (
+ cd geometric &&
+
+ # Create two equal-sized packs
+ test_commit kept && # 3 objects
+ git repack -d &&
+ test_commit pack && # 3 objects
+ git repack -d &&
+
+ find $objdir/pack -type f -name "*.pack" | sort >packs.before &&
+ git repack --geometric 2 -dm \
+ --keep-pack="$(basename "$(head -n 1 packs.before)")" >out &&
+ find $objdir/pack -type f -name "*.pack" | sort >packs.after &&
+
+ # Packs should not have changed (only one non-kept pack, no
+ # loose objects), but $midx should now exist.
+ grep "Nothing new to pack" out &&
+ test_path_is_file $midx &&
+
+ test_cmp packs.before packs.after &&
+
+ git fsck
+ )
+'
+
+test_expect_success '--geometric chooses largest MIDX preferred pack' '
+ git init geometric &&
+ test_when_finished "rm -fr geometric" &&
+ (
+ cd geometric &&
+
+ # These packs already form a geometric progression.
+ test_commit_bulk --start=1 1 && # 3 objects
+ test_commit_bulk --start=2 2 && # 6 objects
+ ls $objdir/pack/pack-*.idx >before &&
+ test_commit_bulk --start=4 4 && # 12 objects
+ ls $objdir/pack/pack-*.idx >after &&
+
+ git repack --geometric 2 -dbm &&
+
+ comm -3 before after | xargs -n 1 basename >expect &&
+ test-tool read-midx --preferred-pack $objdir >actual &&
+
+ test_cmp expect actual
+ )
+'
+
+test_expect_success '--geometric with pack.packSizeLimit' '
+ git init pack-rewrite &&
+ test_when_finished "rm -fr pack-rewrite" &&
+ (
+ cd pack-rewrite &&
+
+ test-tool genrandom foo 1048576 >foo &&
+ test-tool genrandom bar 1048576 >bar &&
+
+ git add foo bar &&
+ test_tick &&
+ git commit -m base &&
+
+ git rev-parse HEAD:foo HEAD:bar >p1.objects &&
+ git rev-parse HEAD HEAD^{tree} >p2.objects &&
+
+ # These two packs each contain two objects, so the following
+ # `--geometric` repack will try to combine them.
+ p1="$(git pack-objects $packdir/pack <p1.objects)" &&
+ p2="$(git pack-objects $packdir/pack <p2.objects)" &&
+
+ # Remove any loose objects in packs, since we do not want extra
+ # copies around (which would mask over potential object
+ # corruption issues).
+ git prune-packed &&
+
+ # Both p1 and p2 will be rolled up, but pack-objects will write
+ # three packs:
+ #
+ # - one containing object "foo",
+ # - another containing object "bar",
+ # - a final pack containing the commit and tree objects
+ # (identical to p2 above)
+ git repack --geometric 2 -d --max-pack-size=1048576 &&
+
+ # Ensure `repack` can detect that the third pack it wrote
+ # (containing just the tree and commit objects) was identical to
+ # one that was below the geometric split, so that we can save it
+ # from deletion.
+ #
+ # If `repack` fails to do that, we will incorrectly delete p2,
+ # causing object corruption.
+ git fsck
+ )
+'
+
+test_expect_success '--geometric --write-midx with packfiles in main and alternate ODB' '
+ test_when_finished "rm -fr shared member" &&
+
+ # Create a shared repository that will serve as the alternate object
+ # database for the member linked to it. It has got some objects on its
+ # own that are packed into a single packfile.
+ git init shared &&
+ test_commit -C shared common-object &&
+ git -C shared repack -ad &&
+
+ # We create member so that its alternates file points to the shared
+ # repository. We then create a commit in it so that git-repack(1) has
+ # something to repack.
+ # of the shared object database.
+ git clone --shared shared member &&
+ test_commit -C member unique-object &&
+ git -C member repack --geometric=2 --write-midx 2>err &&
+ test_must_be_empty err &&
+
+ # We should see that a new packfile was generated.
+ find shared/.git/objects/pack -type f -name "*.pack" >packs &&
+ test_line_count = 1 packs &&
+
+ # We should also see a multi-pack-index. This multi-pack-index should
+ # never refer to any packfiles in the alternate object database.
+ test_path_is_file member/.git/objects/pack/multi-pack-index &&
+ test-tool read-midx member/.git/objects >packs.midx &&
+ grep "^pack-.*\.idx$" packs.midx | sort >actual &&
+ basename member/.git/objects/pack/pack-*.idx >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success '--geometric --with-midx with no local objects' '
+ test_when_finished "rm -fr shared member" &&
+
+ # Create a repository with a single packfile that acts as alternate
+ # object database.
+ git init shared &&
+ test_commit -C shared "shared-objects" &&
+ git -C shared repack -ad &&
+
+ # Create a second repository linked to the first one and perform a
+ # geometric repack on it.
+ git clone --shared shared member &&
+ git -C member repack --geometric 2 --write-midx 2>err &&
+ test_must_be_empty err &&
+
+ # Assert that we wrote neither a new packfile nor a multi-pack-index.
+ # We should not have a packfile because the single packfile in the
+ # alternate object database does not invalidate the geometric sequence.
+ # And we should not have a multi-pack-index because these only index
+ # local packfiles, and there are none.
+ test_dir_is_empty member/$packdir
+'
+
+test_expect_success '--geometric with same pack in main and alternate ODB' '
+ test_when_finished "rm -fr shared member" &&
+
+ # Create a repository with a single packfile that acts as alternate
+ # object database.
+ git init shared &&
+ test_commit -C shared "shared-objects" &&
+ git -C shared repack -ad &&
+
+ # We create the member repository as an exact copy so that it has the
+ # same packfile.
+ cp -r shared member &&
+ test-tool path-utils real_path shared/.git/objects >member/.git/objects/info/alternates &&
+ find shared/.git/objects -type f >expected-files &&
+
+ # Verify that we can repack objects as expected without observing any
+ # error. Having the same packfile in both ODBs used to cause an error
+ # in git-pack-objects(1).
+ git -C member repack --geometric 2 2>err &&
+ test_must_be_empty err &&
+ # Nothing should have changed.
+ find shared/.git/objects -type f >actual-files &&
+ test_cmp expected-files actual-files
+'
+
+test_expect_success '--geometric -l with non-intact geometric sequence across ODBs' '
+ test_when_finished "rm -fr shared member" &&
+
+ git init shared &&
+ test_commit_bulk -C shared --start=1 1 &&
+
+ git clone --shared shared member &&
+ test_commit_bulk -C member --start=2 1 &&
+
+ # Verify that our assumptions actually hold: both generated packfiles
+ # should have three objects and should be non-equal.
+ packed_objects shared/.git/objects/pack/pack-*.idx >shared-objects &&
+ packed_objects member/.git/objects/pack/pack-*.idx >member-objects &&
+ test_line_count = 3 shared-objects &&
+ test_line_count = 3 member-objects &&
+ ! test_cmp shared-objects member-objects &&
+
+ # Perform the geometric repack. With `-l`, we should only see the local
+ # packfile and thus arrive at the conclusion that the geometric
+ # sequence is intact. We thus expect no changes.
+ #
+ # Note that we are tweaking mtimes of the packfiles so that we can
+ # verify they did not change. This is done in order to detect the case
+ # where we do repack objects, but the resulting packfile is the same.
+ test-tool chmtime --verbose =0 member/.git/objects/pack/* >expected-member-packs &&
+ git -C member repack --geometric=2 -l -d &&
+ test-tool chmtime --verbose member/.git/objects/pack/* >actual-member-packs &&
+ test_cmp expected-member-packs actual-member-packs &&
+
+ {
+ packed_objects shared/.git/objects/pack/pack-*.idx &&
+ packed_objects member/.git/objects/pack/pack-*.idx
+ } | sort >expected-objects &&
+
+ # On the other hand, when doing a non-local geometric repack we should
+ # see both packfiles and thus repack them. We expect that the shared
+ # object database was not changed.
+ test-tool chmtime --verbose =0 shared/.git/objects/pack/* >expected-shared-packs &&
+ git -C member repack --geometric=2 -d &&
+ test-tool chmtime --verbose shared/.git/objects/pack/* >actual-shared-packs &&
+ test_cmp expected-shared-packs actual-shared-packs &&
+
+ # Furthermore, we expect that the member repository now has a single
+ # packfile that contains the combined shared and non-shared objects.
+ ls member/.git/objects/pack/pack-*.idx >actual &&
+ test_line_count = 1 actual &&
+ packed_objects member/.git/objects/pack/pack-*.idx >actual-objects &&
+ test_line_count = 6 actual-objects &&
+ test_cmp expected-objects actual-objects
+'
+
+test_expect_success '--geometric -l disables writing bitmaps with non-local packfiles' '
+ test_when_finished "rm -fr shared member" &&
+
+ git init shared &&
+ test_commit_bulk -C shared --start=1 1 &&
+
+ git clone --shared shared member &&
+ test_commit_bulk -C member --start=2 1 &&
+
+ # When performing a geometric repack with `-l` while connected to an
+ # alternate object database that has a packfile we do not have full
+ # coverage of objects. As a result, we expect that writing the bitmap
+ # will be disabled.
+ git -C member repack -l --geometric=2 --write-midx --write-bitmap-index 2>err &&
+ cat >expect <<-EOF &&
+ warning: disabling bitmap writing, as some objects are not being packed
+ EOF
+ test_cmp expect err &&
+ test_path_is_missing member/.git/objects/pack/multi-pack-index-*.bitmap &&
+
+ # On the other hand, when we repack without `-l`, we should see that
+ # the bitmap gets created.
+ git -C member repack --geometric=2 --write-midx --write-bitmap-index 2>err &&
+ test_must_be_empty err &&
+ test_path_is_file member/.git/objects/pack/multi-pack-index-*.bitmap
+'
+
+test_done