summaryrefslogtreecommitdiff
path: root/t/t5329-pack-objects-cruft.sh
diff options
context:
space:
mode:
Diffstat (limited to 't/t5329-pack-objects-cruft.sh')
-rwxr-xr-xt/t5329-pack-objects-cruft.sh234
1 files changed, 220 insertions, 14 deletions
diff --git a/t/t5329-pack-objects-cruft.sh b/t/t5329-pack-objects-cruft.sh
index 8968f7a..fc5fedb 100755
--- a/t/t5329-pack-objects-cruft.sh
+++ b/t/t5329-pack-objects-cruft.sh
@@ -29,7 +29,8 @@ basic_cruft_pack_tests () {
while read oid
do
path="$objdir/$(test_oid_to_path "$oid")" &&
- printf "%s %d\n" "$oid" "$(test-tool chmtime --get "$path")"
+ printf "%s %d\n" "$oid" "$(test-tool chmtime --get "$path")" ||
+ echo "object list generation failed for $oid"
done |
sort -k1
) >expect &&
@@ -232,7 +233,7 @@ test_expect_success 'cruft tags rescue tagged objects' '
while read oid
do
test-tool chmtime -1000 \
- "$objdir/$(test_oid_to_path $oid)"
+ "$objdir/$(test_oid_to_path $oid)" || exit 1
done <objects &&
test-tool chmtime -500 \
@@ -272,7 +273,7 @@ test_expect_success 'cruft commits rescue parents, trees' '
while read object
do
test-tool chmtime -1000 \
- "$objdir/$(test_oid_to_path $object)"
+ "$objdir/$(test_oid_to_path $object)" || exit 1
done <objects &&
test-tool chmtime +500 "$objdir/$(test_oid_to_path \
$(git rev-parse HEAD))" &&
@@ -345,7 +346,7 @@ test_expect_success 'expired objects are pruned' '
while read object
do
test-tool chmtime -1000 \
- "$objdir/$(test_oid_to_path $object)"
+ "$objdir/$(test_oid_to_path $object)" || exit 1
done <objects &&
keep="$(basename "$(ls $packdir/pack-*.pack)")" &&
@@ -572,23 +573,54 @@ test_expect_success 'cruft repack with no reachable objects' '
)
'
-test_expect_success 'cruft repack ignores --max-pack-size' '
+write_blob () {
+ test-tool genrandom "$@" >in &&
+ git hash-object -w -t blob in
+}
+
+find_pack () {
+ for idx in $(ls $packdir/pack-*.idx)
+ do
+ git show-index <$idx >out &&
+ if grep -q "$1" out
+ then
+ echo $idx
+ fi || return 1
+ done
+}
+
+test_expect_success 'cruft repack with --max-pack-size' '
git init max-pack-size &&
(
cd max-pack-size &&
test_commit base &&
+
# two cruft objects which exceed the maximum pack size
- test-tool genrandom foo 1048576 | git hash-object --stdin -w &&
- test-tool genrandom bar 1048576 | git hash-object --stdin -w &&
+ foo=$(write_blob foo 1048576) &&
+ bar=$(write_blob bar 1048576) &&
+ test-tool chmtime --get -1000 \
+ "$objdir/$(test_oid_to_path $foo)" >foo.mtime &&
+ test-tool chmtime --get -2000 \
+ "$objdir/$(test_oid_to_path $bar)" >bar.mtime &&
git repack --cruft --max-pack-size=1M &&
find $packdir -name "*.mtimes" >cruft &&
- test_line_count = 1 cruft &&
- test-tool pack-mtimes "$(basename "$(cat cruft)")" >objects &&
- test_line_count = 2 objects
+ test_line_count = 2 cruft &&
+
+ foo_mtimes="$(basename $(find_pack $foo) .idx).mtimes" &&
+ bar_mtimes="$(basename $(find_pack $bar) .idx).mtimes" &&
+ test-tool pack-mtimes $foo_mtimes >foo.actual &&
+ test-tool pack-mtimes $bar_mtimes >bar.actual &&
+
+ echo "$foo $(cat foo.mtime)" >foo.expect &&
+ echo "$bar $(cat bar.mtime)" >bar.expect &&
+
+ test_cmp foo.expect foo.actual &&
+ test_cmp bar.expect bar.actual &&
+ test "$foo_mtimes" != "$bar_mtimes"
)
'
-test_expect_success 'cruft repack ignores pack.packSizeLimit' '
+test_expect_success 'cruft repack with pack.packSizeLimit' '
(
cd max-pack-size &&
# repack everything back together to remove the existing cruft
@@ -598,9 +630,12 @@ test_expect_success 'cruft repack ignores pack.packSizeLimit' '
# ensure the same post condition is met when --max-pack-size
# would otherwise be inferred from the configuration
find $packdir -name "*.mtimes" >cruft &&
- test_line_count = 1 cruft &&
- test-tool pack-mtimes "$(basename "$(cat cruft)")" >objects &&
- test_line_count = 2 objects
+ test_line_count = 2 cruft &&
+ for pack in $(cat cruft)
+ do
+ test-tool pack-mtimes "$(basename $pack)" >objects &&
+ test_line_count = 1 objects || return 1
+ done
)
'
@@ -738,4 +773,175 @@ test_expect_success 'cruft objects are freshend via loose' '
)
'
+test_expect_success 'gc.recentObjectsHook' '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ # Create a handful of objects.
+ #
+ # - one reachable commit, "base", designated for the reachable
+ # pack
+ # - one unreachable commit, "cruft.discard", which is marked
+ # for deletion
+ # - one unreachable commit, "cruft.old", which would be marked
+ # for deletion, but is rescued as an extra cruft tip
+ # - one unreachable commit, "cruft.new", which is not marked
+ # for deletion
+ test_commit base &&
+ git branch -M main &&
+
+ git checkout --orphan discard &&
+ git rm -fr . &&
+ test_commit --no-tag cruft.discard &&
+
+ git checkout --orphan old &&
+ git rm -fr . &&
+ test_commit --no-tag cruft.old &&
+ cruft_old="$(git rev-parse HEAD)" &&
+
+ git checkout --orphan new &&
+ git rm -fr . &&
+ test_commit --no-tag cruft.new &&
+ cruft_new="$(git rev-parse HEAD)" &&
+
+ git checkout main &&
+ git branch -D discard old new &&
+ git reflog expire --all --expire=all &&
+
+ # mark cruft.old with an mtime that is many minutes
+ # older than the expiration period, and mark cruft.new
+ # with an mtime that is in the future (and thus not
+ # eligible for pruning).
+ test-tool chmtime -2000 "$objdir/$(test_oid_to_path $cruft_old)" &&
+ test-tool chmtime +1000 "$objdir/$(test_oid_to_path $cruft_new)" &&
+
+ # Write the list of cruft objects we expect to
+ # accumulate, which is comprised of everything reachable
+ # from cruft.old and cruft.new, but not cruft.discard.
+ git rev-list --objects --no-object-names \
+ $cruft_old $cruft_new >cruft.raw &&
+ sort cruft.raw >cruft.expect &&
+
+ # Write the script to list extra tips, which are limited
+ # to cruft.old, in this case.
+ write_script extra-tips <<-EOF &&
+ echo $cruft_old
+ EOF
+ git config gc.recentObjectsHook ./extra-tips &&
+
+ git repack --cruft --cruft-expiration=now -d &&
+
+ mtimes="$(ls .git/objects/pack/pack-*.mtimes)" &&
+ git show-index <${mtimes%.mtimes}.idx >cruft &&
+ cut -d" " -f2 cruft | sort >cruft.actual &&
+ test_cmp cruft.expect cruft.actual &&
+
+ # Ensure that the "old" objects are removed after
+ # dropping the gc.recentObjectsHook hook.
+ git config --unset gc.recentObjectsHook &&
+ git repack --cruft --cruft-expiration=now -d &&
+
+ mtimes="$(ls .git/objects/pack/pack-*.mtimes)" &&
+ git show-index <${mtimes%.mtimes}.idx >cruft &&
+ cut -d" " -f2 cruft | sort >cruft.actual &&
+
+ git rev-list --objects --no-object-names $cruft_new >cruft.raw &&
+ cp cruft.expect cruft.old &&
+ sort cruft.raw >cruft.expect &&
+ test_cmp cruft.expect cruft.actual &&
+
+ # ensure objects which are no longer in the cruft pack were
+ # removed from the repository
+ for object in $(comm -13 cruft.expect cruft.old)
+ do
+ test_must_fail git cat-file -t $object || return 1
+ done
+ )
+'
+
+test_expect_success 'multi-valued gc.recentObjectsHook' '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ test_commit base &&
+ git branch -M main &&
+
+ git checkout --orphan cruft.a &&
+ git rm -fr . &&
+ test_commit --no-tag cruft.a &&
+ cruft_a="$(git rev-parse HEAD)" &&
+
+ git checkout --orphan cruft.b &&
+ git rm -fr . &&
+ test_commit --no-tag cruft.b &&
+ cruft_b="$(git rev-parse HEAD)" &&
+
+ git checkout main &&
+ git branch -D cruft.a cruft.b &&
+ git reflog expire --all --expire=all &&
+
+ echo "echo $cruft_a" | write_script extra-tips.a &&
+ echo "echo $cruft_b" | write_script extra-tips.b &&
+ echo "false" | write_script extra-tips.c &&
+
+ git rev-list --objects --no-object-names $cruft_a $cruft_b \
+ >cruft.raw &&
+ sort cruft.raw >cruft.expect &&
+
+ # ensure that each extra cruft tip is saved by its
+ # respective hook
+ git config --add gc.recentObjectsHook ./extra-tips.a &&
+ git config --add gc.recentObjectsHook ./extra-tips.b &&
+ git repack --cruft --cruft-expiration=now -d &&
+
+ mtimes="$(ls .git/objects/pack/pack-*.mtimes)" &&
+ git show-index <${mtimes%.mtimes}.idx >cruft &&
+ cut -d" " -f2 cruft | sort >cruft.actual &&
+ test_cmp cruft.expect cruft.actual &&
+
+ # ensure that a dirty exit halts cruft pack generation
+ git config --add gc.recentObjectsHook ./extra-tips.c &&
+ test_must_fail git repack --cruft --cruft-expiration=now -d 2>err &&
+ grep "unable to enumerate additional recent objects" err &&
+
+ # and that the existing cruft pack is left alone
+ test_path_is_file "$mtimes"
+ )
+'
+
+test_expect_success 'additional cruft blobs via gc.recentObjectsHook' '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ test_commit base &&
+
+ blob=$(echo "unreachable" | git hash-object -w --stdin) &&
+
+ # mark the unreachable blob we wrote above as having
+ # aged out of the retention period
+ test-tool chmtime -2000 "$objdir/$(test_oid_to_path $blob)" &&
+
+ # Write the script to list extra tips, which is just the
+ # extra blob as above.
+ write_script extra-tips <<-EOF &&
+ echo $blob
+ EOF
+ git config gc.recentObjectsHook ./extra-tips &&
+
+ git repack --cruft --cruft-expiration=now -d &&
+
+ mtimes="$(ls .git/objects/pack/pack-*.mtimes)" &&
+ git show-index <${mtimes%.mtimes}.idx >cruft &&
+ cut -d" " -f2 cruft >actual &&
+ echo $blob >expect &&
+ test_cmp expect actual
+ )
+'
+
test_done