| #!/bin/sh | 
 |  | 
 | test_description='pack-objects breaks long cross-pack delta chains' | 
 |  | 
 | TEST_PASSES_SANITIZE_LEAK=true | 
 | . ./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}) && | 
 | 		{ | 
 | 			if test -n "$prev" | 
 | 			then | 
 | 				echo "-$prev" | 
 | 			fi && | 
 | 			echo $cur && | 
 | 			echo "$(git rev-parse :file) file" | 
 | 		} | git pack-objects --stdout >tmp && | 
 | 		GIT_TRACE2_EVENT=$PWD/trace \ | 
 | 		git index-pack -v --stdin --fix-thin <tmp || return 1 && | 
 | 		grep -c region_enter.*progress trace >enter && | 
 | 		grep -c region_leave.*progress trace >leave && | 
 | 		test_cmp enter leave && | 
 | 		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 |