Commit | Line | Data |
---|---|---|
7dbabbbe JK |
1 | #!/bin/sh |
2 | ||
3 | test_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 | ||
49 | test_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 | ||
69 | max_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) | |
81 | test_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) && | |
0d75bfe6 ÆAB |
85 | echo 9 >expect && |
86 | max_chain pack-$pack.pack >actual && | |
87 | test_i18ncmp expect actual | |
7dbabbbe JK |
88 | ' |
89 | ||
90 | test_expect_success '--depth limits depth' ' | |
91 | pack=$(git pack-objects --all --depth=5 </dev/null pack) && | |
0d75bfe6 ÆAB |
92 | echo 5 >expect && |
93 | max_chain pack-$pack.pack >actual && | |
94 | test_i18ncmp expect actual | |
7dbabbbe JK |
95 | ' |
96 | ||
97 | test_done |