1#!/bin/sh 2 3test_description='pack-objects breaks long cross-pack delta chains' 4. ./test-lib.sh 5 6# This mirrors a repeated push setup: 7# 8# 1. A client repeatedly modifies some files, makes a 9# commit, and pushes the result. It does this N times 10# before we get around to repacking. 11# 12# 2. Each push generates a thin pack with the new version of 13# various objects. Let's consider some file in the root tree 14# which is updated in each commit. 15# 16# When generating push number X, we feed commit X-1 (and 17# thus blob X-1) as a preferred base. The resulting pack has 18# blob X as a thin delta against blob X-1. 19# 20# On the receiving end, "index-pack --fix-thin" will 21# complete the pack with a base copy of blob X-1. 22# 23# 3. In older versions of git, if we used the delta from 24# pack X, then we'd always find blob X-1 as a base in the 25# same pack (and generate a fresh delta). 26# 27# But with the pack mru, we jump from delta to delta 28# following the traversal order: 29# 30# a. We grab blob X from pack X as a delta, putting it at 31# the tip of our mru list. 32# 33# b. Eventually we move onto commit X-1. We need other 34# objects which are only in pack X-1 (in the test code 35# below, it's the containing tree). That puts pack X-1 36# at the tip of our mru list. 37# 38# c. Eventually we look for blob X-1, and we find the 39# version in pack X-1 (because it's the mru tip). 40# 41# Now we have blob X as a delta against X-1, which is a delta 42# against X-2, and so forth. 43# 44# In the real world, these small pushes would get exploded by 45# unpack-objects rather than "index-pack --fix-thin", but the 46# same principle applies to larger pushes (they only need one 47# repeatedly-modified file to generate the delta chain). 48 49test_expect_success 'create series of packs'' 50 test-genrandom foo 4096 >content && 51 prev= && 52 for i in$(test_seq 1 10) 53 do 54 cat content >file && 55 echo$i>>file && 56 git add file && 57 git commit -m$i&& 58 cur=$(git rev-parse HEAD^{tree})&& 59 { 60 test -n "$prev" && echo "-$prev" 61 echo$cur 62 echo "$(git rev-parse :file)file" 63 } | git pack-objects --stdout >tmp && 64 git index-pack --stdin --fix-thin <tmp || return 1 65 prev=$cur 66 done 67' 68 69max_chain() { 70 git index-pack --verify-stat-only"$1">output && 71 perl -lne' 72 /chain length = (\d+)/ and$len=$1; 73 END { print$len} 74 ' output 75} 76 77# Note that this whole setup is pretty reliant on the current 78# packing heuristics. We double-check that our test case 79# actually produces a long chain. If it doesn't, it should be 80# adjusted (or scrapped if the heuristics have become too unreliable) 81test_expect_success 'packing produces a long delta'' 82 # Use --window=0 to make sure we are seeing reused deltas, 83 # not computing a new long chain. 84 pack=$(git pack-objects --all --window=0 </dev/null pack)&& 85 test 9 = "$(max_chain pack-$pack.pack)" 86' 87 88test_expect_success '--depth limits depth'' 89 pack=$(git pack-objects --all --depth=5 </dev/null pack)&& 90 test 5 = "$(max_chain pack-$pack.pack)" 91' 92 93test_done