mirror of
https://github.com/git/git
synced 2024-08-24 18:26:02 +00:00
![Jeff King](/assets/img/avatar_default.png)
A negative delta depth makes no sense, and the code is not prepared to handle it. If passed "--depth=-1" on the command line, then this line from break_delta_chains(): cur->depth = (total_depth--) % (depth + 1); triggers a divide-by-zero. This is undefined behavior according to the C standard, but on POSIX systems results in SIGFPE killing the process. This is certainly one way to inform the use that the command was invalid, but it's a bit friendlier to just treat it as "don't allow any deltas", which we already do for --depth=0. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
113 lines
3.5 KiB
Bash
Executable file
113 lines
3.5 KiB
Bash
Executable file
#!/bin/sh
|
|
|
|
test_description='pack-objects breaks long cross-pack delta chains'
|
|
. ./test-lib.sh
|
|
|
|
# This mirrors a repeated push setup:
|
|
#
|
|
# 1. A client repeatedly modifies some files, makes a
|
|
# commit, and pushes the result. It does this N times
|
|
# before we get around to repacking.
|
|
#
|
|
# 2. Each push generates a thin pack with the new version of
|
|
# various objects. Let's consider some file in the root tree
|
|
# which is updated in each commit.
|
|
#
|
|
# When generating push number X, we feed commit X-1 (and
|
|
# thus blob X-1) as a preferred base. The resulting pack has
|
|
# blob X as a thin delta against blob X-1.
|
|
#
|
|
# On the receiving end, "index-pack --fix-thin" will
|
|
# complete the pack with a base copy of blob X-1.
|
|
#
|
|
# 3. In older versions of git, if we used the delta from
|
|
# pack X, then we'd always find blob X-1 as a base in the
|
|
# same pack (and generate a fresh delta).
|
|
#
|
|
# But with the pack mru, we jump from delta to delta
|
|
# following the traversal order:
|
|
#
|
|
# a. We grab blob X from pack X as a delta, putting it at
|
|
# the tip of our mru list.
|
|
#
|
|
# b. Eventually we move onto commit X-1. We need other
|
|
# objects which are only in pack X-1 (in the test code
|
|
# below, it's the containing tree). That puts pack X-1
|
|
# at the tip of our mru list.
|
|
#
|
|
# c. Eventually we look for blob X-1, and we find the
|
|
# version in pack X-1 (because it's the mru tip).
|
|
#
|
|
# Now we have blob X as a delta against X-1, which is a delta
|
|
# against X-2, and so forth.
|
|
#
|
|
# In the real world, these small pushes would get exploded by
|
|
# unpack-objects rather than "index-pack --fix-thin", but the
|
|
# same principle applies to larger pushes (they only need one
|
|
# repeatedly-modified file to generate the delta chain).
|
|
|
|
test_expect_success 'create series of packs' '
|
|
test-tool genrandom foo 4096 >content &&
|
|
prev= &&
|
|
for i in $(test_seq 1 10)
|
|
do
|
|
cat content >file &&
|
|
echo $i >>file &&
|
|
git add file &&
|
|
git commit -m $i &&
|
|
cur=$(git rev-parse HEAD^{tree}) &&
|
|
{
|
|
test -n "$prev" && echo "-$prev"
|
|
echo $cur
|
|
echo "$(git rev-parse :file) file"
|
|
} | git pack-objects --stdout >tmp &&
|
|
git index-pack --stdin --fix-thin <tmp || return 1
|
|
prev=$cur
|
|
done
|
|
'
|
|
|
|
max_chain() {
|
|
git index-pack --verify-stat-only "$1" >output &&
|
|
perl -lne '
|
|
BEGIN { $len = 0 }
|
|
/chain length = (\d+)/ and $len = $1;
|
|
END { print $len }
|
|
' output
|
|
}
|
|
|
|
# Note that this whole setup is pretty reliant on the current
|
|
# packing heuristics. We double-check that our test case
|
|
# actually produces a long chain. If it doesn't, it should be
|
|
# adjusted (or scrapped if the heuristics have become too unreliable)
|
|
test_expect_success 'packing produces a long delta' '
|
|
# Use --window=0 to make sure we are seeing reused deltas,
|
|
# not computing a new long chain.
|
|
pack=$(git pack-objects --all --window=0 </dev/null pack) &&
|
|
echo 9 >expect &&
|
|
max_chain pack-$pack.pack >actual &&
|
|
test_cmp expect actual
|
|
'
|
|
|
|
test_expect_success '--depth limits depth' '
|
|
pack=$(git pack-objects --all --depth=5 </dev/null pack) &&
|
|
echo 5 >expect &&
|
|
max_chain pack-$pack.pack >actual &&
|
|
test_cmp expect actual
|
|
'
|
|
|
|
test_expect_success '--depth=0 disables deltas' '
|
|
pack=$(git pack-objects --all --depth=0 </dev/null pack) &&
|
|
echo 0 >expect &&
|
|
max_chain pack-$pack.pack >actual &&
|
|
test_cmp expect actual
|
|
'
|
|
|
|
test_expect_success 'negative depth disables deltas' '
|
|
pack=$(git pack-objects --all --depth=-1 </dev/null pack) &&
|
|
echo 0 >expect &&
|
|
max_chain pack-$pack.pack >actual &&
|
|
test_cmp expect actual
|
|
'
|
|
|
|
test_done
|