|
| 1 | +#!/bin/sh |
| 2 | + |
| 3 | +test_description='verify that push respects `pack.usePathWalk`' |
| 4 | + |
| 5 | +TEST_PASSES_SANITIZE_LEAK=true |
| 6 | +. ./test-lib.sh |
| 7 | +. "$TEST_DIRECTORY"/lib-pack.sh |
| 8 | + |
| 9 | +test_expect_success 'setup bare repository and clone' ' |
| 10 | + git init --bare -b main bare.git && |
| 11 | + git --git-dir=bare.git config receive.unpackLimit 0 && |
| 12 | + git --git-dir bare.git commit-tree -m initial $EMPTY_TREE >head_oid && |
| 13 | + git --git-dir bare.git update-ref refs/heads/main $(cat head_oid) && |
| 14 | + git clone --bare bare.git clone.git |
| 15 | +' |
| 16 | +test_expect_success 'avoid reusing deltified objects' ' |
| 17 | + # construct two commits, one containing a file with the hex digits |
| 18 | + # repeated 16 times, the next reducing that to 8 times. The crucial |
| 19 | + # part is that the blob of the second commit is deltified _really_ |
| 20 | + # badly and it is therefore easy to detect if a `git push` reused that |
| 21 | + # delta. |
| 22 | + x="0123456789abcdef" && |
| 23 | + printf "$x$x$x$x$x$x$x$x" >x128 && |
| 24 | + printf "$x$x$x$x$x$x$x$x$x$x$x$x$x$x$x$x" >x256 && |
| 25 | +
|
| 26 | + pack=clone.git/objects/pack/pack-tmp.pack && |
| 27 | + pack_header 2 >$pack && |
| 28 | +
|
| 29 | + # add x256 as a non-deltified object, using an uncompressed zlib stream |
| 30 | + # for simplicity |
| 31 | + # 060 = OBJ_BLOB << 4, 0200 = size larger than 15, |
| 32 | + # 0 = lower 4 bits of size, 020 = bits 5-9 of size (size = 256) |
| 33 | + printf "\260\020" >>$pack && |
| 34 | + # Uncompressed zlib stream always starts with 0170 1 1, followed |
| 35 | + # by two bytes encoding the size, little endian, then two bytes with |
| 36 | + # the bitwise-complement of that size, then the payload, and then the |
| 37 | + # Adler32 checksum. For some reason, the checksum is in big-endian |
| 38 | + # format. |
| 39 | + printf "\170\001\001\0\001\377\376" >>$pack && |
| 40 | + cat x256 >>$pack && |
| 41 | + # Manually-computed Adler32 checksum: 0xd7ae4621 |
| 42 | + printf "\327\256\106\041" >>$pack && |
| 43 | +
|
| 44 | + # add x128 as a very badly deltified object |
| 45 | + # 0120 = OBJ_OFS_DELTA << 4, 0200 = total size larger than 15, |
| 46 | + # 4 = lower 4 bits of size, 030 = bits 5-9 of size |
| 47 | + # (size = 128 * 3 + 2 + 2) |
| 48 | + printf "\344\030" >>$pack && |
| 49 | + # 0415 = size (i.e. the relative negative offset) of the previous |
| 50 | + # object (x256, used as base object) |
| 51 | + # encoded as 0200 | ((0415 >> 7) - 1), 0415 & 0177 |
| 52 | + printf "\201\015" >>$pack && |
| 53 | + # Uncompressed zlib stream, as before, size = 2 + 2 + 128 * 3 (i.e. |
| 54 | + # 0604) |
| 55 | + printf "\170\001\001\204\001\173\376" >>$pack && |
| 56 | + # base object size = 0400 (encoded as 0200 | (0400 & 0177), |
| 57 | + # 0400 >> 7) |
| 58 | + printf "\200\002" >>$pack && |
| 59 | + # object size = 0200 (encoded as 0200 | (0200 & 0177), 0200 >> 7 |
| 60 | + printf "\200\001" >>$pack && |
| 61 | + # massively badly-deltified object: copy every single byte individually |
| 62 | + # 0200 = copy, 1 = use 1 byte to encode the offset (counter), |
| 63 | + # 020 = use 1 byte to encode the size (1) |
| 64 | + printf "$(printf "\\\\221\\\\%03o\\\\001" $(test_seq 0 127))" >>$pack && |
| 65 | + # Manually-computed Adler32 checksum: 0x99c369c4 |
| 66 | + printf "\231\303\151\304" >>$pack && |
| 67 | +
|
| 68 | + pack_trailer $pack && |
| 69 | + git index-pack -v $pack && |
| 70 | +
|
| 71 | + oid256=$(git hash-object x256) && |
| 72 | + printf "100755 blob $oid256\thex\n" >tree && |
| 73 | + tree_oid="$(git --git-dir=clone.git mktree <tree)" && |
| 74 | + commit_oid=$(git --git-dir=clone.git commit-tree \ |
| 75 | + -p $(git --git-dir=clone.git rev-parse main) \ |
| 76 | + -m 256 $tree_oid) && |
| 77 | +
|
| 78 | + oid128=$(git hash-object x128) && |
| 79 | + printf "100755 blob $oid128\thex\n" >tree && |
| 80 | + tree_oid="$(git --git-dir=clone.git mktree <tree)" && |
| 81 | + commit_oid=$(git --git-dir=clone.git commit-tree \ |
| 82 | + -p $commit_oid \ |
| 83 | + -m 128 $tree_oid) && |
| 84 | +
|
| 85 | + # Verify that the on-disk size of the delta object is suboptimal in the |
| 86 | + # clone (see below why 18 bytes or smaller is the optimal size): |
| 87 | + git index-pack --verify-stat clone.git/objects/pack/pack-*.pack >verify && |
| 88 | + size="$(sed -n "s/^$oid128 blob *\([^ ]*\).*/\1/p" <verify)" && |
| 89 | + test $size -gt 18 && |
| 90 | +
|
| 91 | + git --git-dir=clone.git update-ref refs/heads/main $commit_oid && |
| 92 | + git --git-dir=clone.git -c pack.usePathWalk=true push origin main && |
| 93 | + git index-pack --verify-stat bare.git/objects/pack/pack-*.pack >verify && |
| 94 | + size="$(sed -n "s/^$oid128 blob *\([^ ]*\).*/\1/p" <verify)" && |
| 95 | + # The on-disk size of the delta object should be smaller than, or equal |
| 96 | + # to, 18 bytes, as that would be the size if storing the payload |
| 97 | + # uncompressed: |
| 98 | + # 3 bytes: 0170 01 01 |
| 99 | + # + 2 bytes: zlib stream size |
| 100 | + # + 2 bytes: but-wise complement of the zlib stream size |
| 101 | + # + 7 bytes: payload |
| 102 | + # (= 2 bytes for the size of tbe base object |
| 103 | + # + 2 bytes for the size of the delta command |
| 104 | + # + 3 bytes for the copy command) |
| 105 | + # + 2 + 2 bytes: Adler32 checksum |
| 106 | + test $size -le 18 |
| 107 | +' |
| 108 | + |
| 109 | +test_done |
0 commit comments