| 1 | #!/bin/sh |
| 2 | |
| 3 | test_description='exercise delta islands' |
| 4 | |
| 5 | . ./test-lib.sh |
| 6 | |
| 7 | # returns true iff $1 is a delta based on $2 |
| 8 | is_delta_base () { |
| 9 | delta_base=$(echo "$1" | git cat-file --batch-check='%(deltabase)') && |
| 10 | echo >&2 "$1 has base $delta_base" && |
| 11 | test "$delta_base" = "$2" |
| 12 | } |
| 13 | |
| 14 | # generate a commit on branch $1 with a single file, "file", whose |
| 15 | # content is mostly based on the seed $2, but with a unique bit |
| 16 | # of content $3 appended. This should allow us to see whether |
| 17 | # blobs of different refs delta against each other. |
| 18 | commit() { |
| 19 | blob=$({ test-tool genrandom "$2" 10240 && echo "$3"; } | |
| 20 | git hash-object -w --stdin) && |
| 21 | tree=$(printf '100644 blob %s\tfile\n' "$blob" | git mktree) && |
| 22 | commit=$(echo "$2-$3" | git commit-tree "$tree" ${4:+-p "$4"}) && |
| 23 | git update-ref "refs/heads/$1" "$commit" && |
| 24 | eval "$1"'=$(git rev-parse $1:file)' && |
| 25 | eval "echo >&2 $1=\$$1" |
| 26 | } |
| 27 | |
| 28 | test_expect_success 'setup commits' ' |
| 29 | commit one seed 1 && |
| 30 | commit two seed 12 |
| 31 | ' |
| 32 | |
| 33 | # Note: This is heavily dependent on the "prefer larger objects as base" |
| 34 | # heuristic. |
| 35 | test_expect_success 'vanilla repack deltas one against two' ' |
| 36 | git repack -adf && |
| 37 | is_delta_base $one $two |
| 38 | ' |
| 39 | |
| 40 | test_expect_success 'island repack with no island definition is vanilla' ' |
| 41 | git repack -adfi && |
| 42 | is_delta_base $one $two |
| 43 | ' |
| 44 | |
| 45 | test_expect_success 'island repack with no matches is vanilla' ' |
| 46 | git -c "pack.island=refs/foo" repack -adfi && |
| 47 | is_delta_base $one $two |
| 48 | ' |
| 49 | |
| 50 | test_expect_success 'separate islands disallows delta' ' |
| 51 | git -c "pack.island=refs/heads/(.*)" repack -adfi && |
| 52 | ! is_delta_base $one $two && |
| 53 | ! is_delta_base $two $one |
| 54 | ' |
| 55 | |
| 56 | test_expect_success 'same island allows delta' ' |
| 57 | git -c "pack.island=refs/heads" repack -adfi && |
| 58 | is_delta_base $one $two |
| 59 | ' |
| 60 | |
| 61 | test_expect_success 'coalesce same-named islands' ' |
| 62 | git \ |
| 63 | -c "pack.island=refs/(.*)/one" \ |
| 64 | -c "pack.island=refs/(.*)/two" \ |
| 65 | repack -adfi && |
| 66 | is_delta_base $one $two |
| 67 | ' |
| 68 | |
| 69 | test_expect_success 'island restrictions drop reused deltas' ' |
| 70 | git repack -adfi && |
| 71 | is_delta_base $one $two && |
| 72 | git -c "pack.island=refs/heads/(.*)" repack -adi && |
| 73 | ! is_delta_base $one $two && |
| 74 | ! is_delta_base $two $one |
| 75 | ' |
| 76 | |
| 77 | test_expect_success 'island regexes are left-anchored' ' |
| 78 | git -c "pack.island=heads/(.*)" repack -adfi && |
| 79 | is_delta_base $one $two |
| 80 | ' |
| 81 | |
| 82 | test_expect_success 'island regexes follow last-one-wins scheme' ' |
| 83 | git \ |
| 84 | -c "pack.island=refs/heads/(.*)" \ |
| 85 | -c "pack.island=refs/heads/" \ |
| 86 | repack -adfi && |
| 87 | is_delta_base $one $two |
| 88 | ' |
| 89 | |
| 90 | test_expect_success 'setup shared history' ' |
| 91 | commit root shared root && |
| 92 | commit one shared 1 root && |
| 93 | commit two shared 12-long root |
| 94 | ' |
| 95 | |
| 96 | # We know that $two will be preferred as a base from $one, |
| 97 | # because we can transform it with a pure deletion. |
| 98 | # |
| 99 | # We also expect $root as a delta against $two by the "longest is base" rule. |
| 100 | test_expect_success 'vanilla delta goes between branches' ' |
| 101 | git repack -adf && |
| 102 | is_delta_base $one $two && |
| 103 | is_delta_base $root $two |
| 104 | ' |
| 105 | |
| 106 | # Here we should allow $one to base itself on $root; even though |
| 107 | # they are in different islands, the objects in $root are in a superset |
| 108 | # of islands compared to those in $one. |
| 109 | # |
| 110 | # Similarly, $two can delta against $root by our rules. And unlike $one, |
| 111 | # in which we are just allowing it, the island rules actually put $root |
| 112 | # as a possible base for $two, which it would not otherwise be (due to the size |
| 113 | # sorting). |
| 114 | test_expect_success 'deltas allowed against superset islands' ' |
| 115 | git -c "pack.island=refs/heads/(.*)" repack -adfi && |
| 116 | is_delta_base $one $root && |
| 117 | is_delta_base $two $root |
| 118 | ' |
| 119 | |
| 120 | # We are going to test the packfile order here, so we again have to make some |
| 121 | # assumptions. We assume that "$root", as part of our core "one", must come |
| 122 | # before "$two". This should be guaranteed by the island code. However, for |
| 123 | # this test to fail without islands, we are also assuming that it would not |
| 124 | # otherwise do so. This is true by the current write order, which will put |
| 125 | # commits (and their contents) before their parents. |
| 126 | test_expect_success 'island core places core objects first' ' |
| 127 | cat >expect <<-EOF && |
| 128 | $root |
| 129 | $two |
| 130 | EOF |
| 131 | git -c "pack.island=refs/heads/(.*)" \ |
| 132 | -c "pack.islandcore=one" \ |
| 133 | repack -adfi && |
| 134 | git verify-pack -v .git/objects/pack/*.pack | |
| 135 | cut -d" " -f1 | |
| 136 | grep -E "$root|$two" >actual && |
| 137 | test_cmp expect actual |
| 138 | ' |
| 139 | |
| 140 | test_expect_success 'unmatched island core is not fatal' ' |
| 141 | git -c "pack.islandcore=one" repack -adfi |
| 142 | ' |
| 143 | |
| 144 | test_done |