Jeff Hostetler | 35a7ae9 | 2017-12-08 15:58:49 +0000 | [diff] [blame] | 1 | #!/bin/sh |
| 2 | |
| 3 | test_description='git partial clone' |
| 4 | |
Johannes Schindelin | 95cf2c0 | 2020-11-18 23:44:35 +0000 | [diff] [blame] | 5 | GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main |
Johannes Schindelin | 334afbc | 2020-11-18 23:44:19 +0000 | [diff] [blame] | 6 | export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME |
| 7 | |
Jeff Hostetler | 35a7ae9 | 2017-12-08 15:58:49 +0000 | [diff] [blame] | 8 | . ./test-lib.sh |
| 9 | |
| 10 | # create a normal "src" repo where we can later create new commits. |
| 11 | # expect_1.oids will contain a list of the OIDs of all blobs. |
| 12 | test_expect_success 'setup normal src repo' ' |
| 13 | echo "{print \$1}" >print_1.awk && |
| 14 | echo "{print \$2}" >print_2.awk && |
| 15 | |
| 16 | git init src && |
| 17 | for n in 1 2 3 4 |
| 18 | do |
Eric Sunshine | 74d2f56 | 2021-12-09 00:11:06 -0500 | [diff] [blame] | 19 | echo "This is file: $n" > src/file.$n.txt && |
| 20 | git -C src add file.$n.txt && |
| 21 | git -C src commit -m "file $n" && |
Eric Sunshine | d0fd993 | 2021-12-09 00:11:14 -0500 | [diff] [blame] | 22 | git -C src ls-files -s file.$n.txt >>temp || return 1 |
Jeff Hostetler | 35a7ae9 | 2017-12-08 15:58:49 +0000 | [diff] [blame] | 23 | done && |
| 24 | awk -f print_2.awk <temp | sort >expect_1.oids && |
| 25 | test_line_count = 4 expect_1.oids |
| 26 | ' |
| 27 | |
| 28 | # bare clone "src" giving "srv.bare" for use as our server. |
| 29 | test_expect_success 'setup bare clone for server' ' |
| 30 | git clone --bare "file://$(pwd)/src" srv.bare && |
| 31 | git -C srv.bare config --local uploadpack.allowfilter 1 && |
| 32 | git -C srv.bare config --local uploadpack.allowanysha1inwant 1 |
| 33 | ' |
| 34 | |
| 35 | # do basic partial clone from "srv.bare" |
| 36 | # confirm we are missing all of the known blobs. |
| 37 | # confirm partial clone was registered in the local config. |
| 38 | test_expect_success 'do partial clone 1' ' |
| 39 | git clone --no-checkout --filter=blob:none "file://$(pwd)/srv.bare" pc1 && |
Matthew DeVore | bdbc17e | 2018-10-05 14:54:03 -0700 | [diff] [blame] | 40 | |
Matthew DeVore | 8d6ba49 | 2018-10-05 14:54:07 -0700 | [diff] [blame] | 41 | git -C pc1 rev-list --quiet --objects --missing=print HEAD >revs && |
Matthew DeVore | 61de0ff | 2018-10-05 14:54:05 -0700 | [diff] [blame] | 42 | awk -f print_1.awk revs | |
Matthew DeVore | bdbc17e | 2018-10-05 14:54:03 -0700 | [diff] [blame] | 43 | sed "s/?//" | |
| 44 | sort >observed.oids && |
| 45 | |
Jeff Hostetler | 35a7ae9 | 2017-12-08 15:58:49 +0000 | [diff] [blame] | 46 | test_cmp expect_1.oids observed.oids && |
| 47 | test "$(git -C pc1 config --local core.repositoryformatversion)" = "1" && |
Christian Couder | b14ed5a | 2019-06-25 15:40:31 +0200 | [diff] [blame] | 48 | test "$(git -C pc1 config --local remote.origin.promisor)" = "true" && |
Christian Couder | fa3d1b6 | 2019-06-25 15:40:32 +0200 | [diff] [blame] | 49 | test "$(git -C pc1 config --local remote.origin.partialclonefilter)" = "blob:none" |
Jeff Hostetler | 35a7ae9 | 2017-12-08 15:58:49 +0000 | [diff] [blame] | 50 | ' |
| 51 | |
Jonathan Tan | 5374a29 | 2019-10-14 17:12:31 -0700 | [diff] [blame] | 52 | test_expect_success 'verify that .promisor file contains refs fetched' ' |
| 53 | ls pc1/.git/objects/pack/pack-*.promisor >promisorlist && |
| 54 | test_line_count = 1 promisorlist && |
Đoàn Trần Công Danh | 6c28bef | 2020-03-25 22:06:18 +0700 | [diff] [blame] | 55 | git -C srv.bare rev-parse --verify HEAD >headhash && |
Jonathan Tan | 5374a29 | 2019-10-14 17:12:31 -0700 | [diff] [blame] | 56 | grep "$(cat headhash) HEAD" $(cat promisorlist) && |
Johannes Schindelin | 95cf2c0 | 2020-11-18 23:44:35 +0000 | [diff] [blame] | 57 | grep "$(cat headhash) refs/heads/main" $(cat promisorlist) |
Jonathan Tan | 5374a29 | 2019-10-14 17:12:31 -0700 | [diff] [blame] | 58 | ' |
| 59 | |
Johannes Schindelin | 95cf2c0 | 2020-11-18 23:44:35 +0000 | [diff] [blame] | 60 | # checkout main to force dynamic object fetch of blobs at HEAD. |
Jeff Hostetler | 35a7ae9 | 2017-12-08 15:58:49 +0000 | [diff] [blame] | 61 | test_expect_success 'verify checkout with dynamic object fetch' ' |
Matthew DeVore | 8d6ba49 | 2018-10-05 14:54:07 -0700 | [diff] [blame] | 62 | git -C pc1 rev-list --quiet --objects --missing=print HEAD >observed && |
Jeff Hostetler | 35a7ae9 | 2017-12-08 15:58:49 +0000 | [diff] [blame] | 63 | test_line_count = 4 observed && |
Johannes Schindelin | 95cf2c0 | 2020-11-18 23:44:35 +0000 | [diff] [blame] | 64 | git -C pc1 checkout main && |
Matthew DeVore | 8d6ba49 | 2018-10-05 14:54:07 -0700 | [diff] [blame] | 65 | git -C pc1 rev-list --quiet --objects --missing=print HEAD >observed && |
Jeff Hostetler | 35a7ae9 | 2017-12-08 15:58:49 +0000 | [diff] [blame] | 66 | test_line_count = 0 observed |
| 67 | ' |
| 68 | |
| 69 | # create new commits in "src" repo to establish a blame history on file.1.txt |
| 70 | # and push to "srv.bare". |
| 71 | test_expect_success 'push new commits to server' ' |
| 72 | git -C src remote add srv "file://$(pwd)/srv.bare" && |
| 73 | for x in a b c d e |
| 74 | do |
Eric Sunshine | 74d2f56 | 2021-12-09 00:11:06 -0500 | [diff] [blame] | 75 | echo "Mod file.1.txt $x" >>src/file.1.txt && |
| 76 | git -C src add file.1.txt && |
Eric Sunshine | d0fd993 | 2021-12-09 00:11:14 -0500 | [diff] [blame] | 77 | git -C src commit -m "mod $x" || return 1 |
Jeff Hostetler | 35a7ae9 | 2017-12-08 15:58:49 +0000 | [diff] [blame] | 78 | done && |
Johannes Schindelin | 95cf2c0 | 2020-11-18 23:44:35 +0000 | [diff] [blame] | 79 | git -C src blame main -- file.1.txt >expect.blame && |
| 80 | git -C src push -u srv main |
Jeff Hostetler | 35a7ae9 | 2017-12-08 15:58:49 +0000 | [diff] [blame] | 81 | ' |
| 82 | |
| 83 | # (partial) fetch in the partial clone repo from the promisor remote. |
| 84 | # verify that fetch inherited the filter-spec from the config and DOES NOT |
| 85 | # have the new blobs. |
| 86 | test_expect_success 'partial fetch inherits filter settings' ' |
| 87 | git -C pc1 fetch origin && |
Matthew DeVore | 8d6ba49 | 2018-10-05 14:54:07 -0700 | [diff] [blame] | 88 | git -C pc1 rev-list --quiet --objects --missing=print \ |
Johannes Schindelin | 95cf2c0 | 2020-11-18 23:44:35 +0000 | [diff] [blame] | 89 | main..origin/main >observed && |
Jeff Hostetler | 35a7ae9 | 2017-12-08 15:58:49 +0000 | [diff] [blame] | 90 | test_line_count = 5 observed |
| 91 | ' |
| 92 | |
| 93 | # force dynamic object fetch using diff. |
Johannes Schindelin | 95cf2c0 | 2020-11-18 23:44:35 +0000 | [diff] [blame] | 94 | # we should only get 1 new blob (for the file in origin/main). |
Jeff Hostetler | 35a7ae9 | 2017-12-08 15:58:49 +0000 | [diff] [blame] | 95 | test_expect_success 'verify diff causes dynamic object fetch' ' |
Johannes Schindelin | 95cf2c0 | 2020-11-18 23:44:35 +0000 | [diff] [blame] | 96 | git -C pc1 diff main..origin/main -- file.1.txt && |
Matthew DeVore | 8d6ba49 | 2018-10-05 14:54:07 -0700 | [diff] [blame] | 97 | git -C pc1 rev-list --quiet --objects --missing=print \ |
Johannes Schindelin | 95cf2c0 | 2020-11-18 23:44:35 +0000 | [diff] [blame] | 98 | main..origin/main >observed && |
Jeff Hostetler | 35a7ae9 | 2017-12-08 15:58:49 +0000 | [diff] [blame] | 99 | test_line_count = 4 observed |
| 100 | ' |
| 101 | |
| 102 | # force full dynamic object fetch of the file's history using blame. |
| 103 | # we should get the intermediate blobs for the file. |
| 104 | test_expect_success 'verify blame causes dynamic object fetch' ' |
Johannes Schindelin | 95cf2c0 | 2020-11-18 23:44:35 +0000 | [diff] [blame] | 105 | git -C pc1 blame origin/main -- file.1.txt >observed.blame && |
Jeff Hostetler | 35a7ae9 | 2017-12-08 15:58:49 +0000 | [diff] [blame] | 106 | test_cmp expect.blame observed.blame && |
Matthew DeVore | 8d6ba49 | 2018-10-05 14:54:07 -0700 | [diff] [blame] | 107 | git -C pc1 rev-list --quiet --objects --missing=print \ |
Johannes Schindelin | 95cf2c0 | 2020-11-18 23:44:35 +0000 | [diff] [blame] | 108 | main..origin/main >observed && |
Jeff Hostetler | 35a7ae9 | 2017-12-08 15:58:49 +0000 | [diff] [blame] | 109 | test_line_count = 0 observed |
| 110 | ' |
| 111 | |
Jeff Hostetler | aa57b87 | 2017-12-08 15:58:50 +0000 | [diff] [blame] | 112 | # create new commits in "src" repo to establish a history on file.2.txt |
| 113 | # and push to "srv.bare". |
| 114 | test_expect_success 'push new commits to server for file.2.txt' ' |
| 115 | for x in a b c d e f |
| 116 | do |
Eric Sunshine | 74d2f56 | 2021-12-09 00:11:06 -0500 | [diff] [blame] | 117 | echo "Mod file.2.txt $x" >>src/file.2.txt && |
| 118 | git -C src add file.2.txt && |
Eric Sunshine | d0fd993 | 2021-12-09 00:11:14 -0500 | [diff] [blame] | 119 | git -C src commit -m "mod $x" || return 1 |
Jeff Hostetler | aa57b87 | 2017-12-08 15:58:50 +0000 | [diff] [blame] | 120 | done && |
Johannes Schindelin | 95cf2c0 | 2020-11-18 23:44:35 +0000 | [diff] [blame] | 121 | git -C src push -u srv main |
Jeff Hostetler | aa57b87 | 2017-12-08 15:58:50 +0000 | [diff] [blame] | 122 | ' |
| 123 | |
Jeff Hostetler | 3aa6694 | 2017-12-08 15:58:51 +0000 | [diff] [blame] | 124 | # Do FULL fetch by disabling inherited filter-spec using --no-filter. |
Jeff Hostetler | aa57b87 | 2017-12-08 15:58:50 +0000 | [diff] [blame] | 125 | # Verify we have all the new blobs. |
| 126 | test_expect_success 'override inherited filter-spec using --no-filter' ' |
| 127 | git -C pc1 fetch --no-filter origin && |
Matthew DeVore | 8d6ba49 | 2018-10-05 14:54:07 -0700 | [diff] [blame] | 128 | git -C pc1 rev-list --quiet --objects --missing=print \ |
Johannes Schindelin | 95cf2c0 | 2020-11-18 23:44:35 +0000 | [diff] [blame] | 129 | main..origin/main >observed && |
Jeff Hostetler | aa57b87 | 2017-12-08 15:58:50 +0000 | [diff] [blame] | 130 | test_line_count = 0 observed |
| 131 | ' |
| 132 | |
Jeff Hostetler | 3aa6694 | 2017-12-08 15:58:51 +0000 | [diff] [blame] | 133 | # create new commits in "src" repo to establish a history on file.3.txt |
| 134 | # and push to "srv.bare". |
| 135 | test_expect_success 'push new commits to server for file.3.txt' ' |
| 136 | for x in a b c d e f |
| 137 | do |
Eric Sunshine | 74d2f56 | 2021-12-09 00:11:06 -0500 | [diff] [blame] | 138 | echo "Mod file.3.txt $x" >>src/file.3.txt && |
| 139 | git -C src add file.3.txt && |
Eric Sunshine | d0fd993 | 2021-12-09 00:11:14 -0500 | [diff] [blame] | 140 | git -C src commit -m "mod $x" || return 1 |
Jeff Hostetler | 3aa6694 | 2017-12-08 15:58:51 +0000 | [diff] [blame] | 141 | done && |
Johannes Schindelin | 95cf2c0 | 2020-11-18 23:44:35 +0000 | [diff] [blame] | 142 | git -C src push -u srv main |
Jeff Hostetler | 3aa6694 | 2017-12-08 15:58:51 +0000 | [diff] [blame] | 143 | ' |
| 144 | |
| 145 | # Do a partial fetch and then try to manually fetch the missing objects. |
| 146 | # This can be used as the basis of a pre-command hook to bulk fetch objects |
| 147 | # perhaps combined with a command in dry-run mode. |
| 148 | test_expect_success 'manual prefetch of missing objects' ' |
| 149 | git -C pc1 fetch --filter=blob:none origin && |
Matthew DeVore | bdbc17e | 2018-10-05 14:54:03 -0700 | [diff] [blame] | 150 | |
Matthew DeVore | 8d6ba49 | 2018-10-05 14:54:07 -0700 | [diff] [blame] | 151 | git -C pc1 rev-list --quiet --objects --missing=print \ |
Johannes Schindelin | 95cf2c0 | 2020-11-18 23:44:35 +0000 | [diff] [blame] | 152 | main..origin/main >revs && |
Matthew DeVore | 61de0ff | 2018-10-05 14:54:05 -0700 | [diff] [blame] | 153 | awk -f print_1.awk revs | |
Matthew DeVore | bdbc17e | 2018-10-05 14:54:03 -0700 | [diff] [blame] | 154 | sed "s/?//" | |
| 155 | sort >observed.oids && |
| 156 | |
Jeff Hostetler | 3aa6694 | 2017-12-08 15:58:51 +0000 | [diff] [blame] | 157 | test_line_count = 6 observed.oids && |
| 158 | git -C pc1 fetch-pack --stdin "file://$(pwd)/srv.bare" <observed.oids && |
Matthew DeVore | bdbc17e | 2018-10-05 14:54:03 -0700 | [diff] [blame] | 159 | |
Matthew DeVore | 8d6ba49 | 2018-10-05 14:54:07 -0700 | [diff] [blame] | 160 | git -C pc1 rev-list --quiet --objects --missing=print \ |
Johannes Schindelin | 95cf2c0 | 2020-11-18 23:44:35 +0000 | [diff] [blame] | 161 | main..origin/main >revs && |
Matthew DeVore | 61de0ff | 2018-10-05 14:54:05 -0700 | [diff] [blame] | 162 | awk -f print_1.awk revs | |
Matthew DeVore | bdbc17e | 2018-10-05 14:54:03 -0700 | [diff] [blame] | 163 | sed "s/?//" | |
| 164 | sort >observed.oids && |
| 165 | |
Jeff Hostetler | 3aa6694 | 2017-12-08 15:58:51 +0000 | [diff] [blame] | 166 | test_line_count = 0 observed.oids |
| 167 | ' |
| 168 | |
Robert Coup | 011b775 | 2022-03-28 14:02:09 +0000 | [diff] [blame] | 169 | # create new commits in "src" repo to establish a history on file.4.txt |
| 170 | # and push to "srv.bare". |
| 171 | test_expect_success 'push new commits to server for file.4.txt' ' |
| 172 | for x in a b c d e f |
| 173 | do |
| 174 | echo "Mod file.4.txt $x" >src/file.4.txt && |
| 175 | if list_contains "a,b" "$x"; then |
| 176 | printf "%10000s" X >>src/file.4.txt |
| 177 | fi && |
| 178 | if list_contains "c,d" "$x"; then |
| 179 | printf "%20000s" X >>src/file.4.txt |
| 180 | fi && |
| 181 | git -C src add file.4.txt && |
| 182 | git -C src commit -m "mod $x" || return 1 |
| 183 | done && |
| 184 | git -C src push -u srv main |
| 185 | ' |
| 186 | |
| 187 | # Do partial fetch to fetch smaller files; then verify that without --refetch |
| 188 | # applying a new filter does not refetch missing large objects. Then use |
| 189 | # --refetch to apply the new filter on existing commits. Test it under both |
| 190 | # protocol v2 & v0. |
| 191 | test_expect_success 'apply a different filter using --refetch' ' |
| 192 | git -C pc1 fetch --filter=blob:limit=999 origin && |
| 193 | git -C pc1 rev-list --quiet --objects --missing=print \ |
| 194 | main..origin/main >observed && |
| 195 | test_line_count = 4 observed && |
| 196 | |
| 197 | git -C pc1 fetch --filter=blob:limit=19999 --refetch origin && |
| 198 | git -C pc1 rev-list --quiet --objects --missing=print \ |
| 199 | main..origin/main >observed && |
| 200 | test_line_count = 2 observed && |
| 201 | |
| 202 | git -c protocol.version=0 -C pc1 fetch --filter=blob:limit=29999 \ |
| 203 | --refetch origin && |
| 204 | git -C pc1 rev-list --quiet --objects --missing=print \ |
| 205 | main..origin/main >observed && |
| 206 | test_line_count = 0 observed |
| 207 | ' |
| 208 | |
| 209 | test_expect_success 'fetch --refetch works with a shallow clone' ' |
| 210 | git clone --no-checkout --depth=1 --filter=blob:none "file://$(pwd)/srv.bare" pc1s && |
| 211 | git -C pc1s rev-list --objects --missing=print HEAD >observed && |
| 212 | test_line_count = 6 observed && |
| 213 | |
| 214 | GIT_TRACE=1 git -C pc1s fetch --filter=blob:limit=999 --refetch origin && |
| 215 | git -C pc1s rev-list --objects --missing=print HEAD >observed && |
| 216 | test_line_count = 6 observed |
| 217 | ' |
| 218 | |
Robert Coup | 7390f05 | 2022-03-28 14:02:10 +0000 | [diff] [blame] | 219 | test_expect_success 'fetch --refetch triggers repacking' ' |
| 220 | GIT_TRACE2_CONFIG_PARAMS=gc.autoPackLimit,maintenance.incremental-repack.auto && |
| 221 | export GIT_TRACE2_CONFIG_PARAMS && |
| 222 | |
| 223 | GIT_TRACE2_EVENT="$PWD/trace1.event" \ |
| 224 | git -C pc1 fetch --refetch origin && |
| 225 | test_subcommand git maintenance run --auto --no-quiet <trace1.event && |
| 226 | grep \"param\":\"gc.autopacklimit\",\"value\":\"1\" trace1.event && |
| 227 | grep \"param\":\"maintenance.incremental-repack.auto\",\"value\":\"-1\" trace1.event && |
| 228 | |
| 229 | GIT_TRACE2_EVENT="$PWD/trace2.event" \ |
| 230 | git -c protocol.version=0 \ |
| 231 | -c gc.autoPackLimit=0 \ |
| 232 | -c maintenance.incremental-repack.auto=1234 \ |
| 233 | -C pc1 fetch --refetch origin && |
| 234 | test_subcommand git maintenance run --auto --no-quiet <trace2.event && |
| 235 | grep \"param\":\"gc.autopacklimit\",\"value\":\"0\" trace2.event && |
| 236 | grep \"param\":\"maintenance.incremental-repack.auto\",\"value\":\"-1\" trace2.event && |
| 237 | |
| 238 | GIT_TRACE2_EVENT="$PWD/trace3.event" \ |
| 239 | git -c protocol.version=0 \ |
| 240 | -c gc.autoPackLimit=1234 \ |
| 241 | -c maintenance.incremental-repack.auto=0 \ |
| 242 | -C pc1 fetch --refetch origin && |
| 243 | test_subcommand git maintenance run --auto --no-quiet <trace3.event && |
| 244 | grep \"param\":\"gc.autopacklimit\",\"value\":\"1\" trace3.event && |
| 245 | grep \"param\":\"maintenance.incremental-repack.auto\",\"value\":\"0\" trace3.event |
| 246 | ' |
| 247 | |
Jonathan Tan | 1b03df5 | 2020-08-20 10:51:16 -0700 | [diff] [blame] | 248 | test_expect_success 'partial clone with transfer.fsckobjects=1 works with submodules' ' |
| 249 | test_create_repo submodule && |
| 250 | test_commit -C submodule mycommit && |
| 251 | |
| 252 | test_create_repo src_with_sub && |
| 253 | test_config -C src_with_sub uploadpack.allowfilter 1 && |
| 254 | test_config -C src_with_sub uploadpack.allowanysha1inwant 1 && |
| 255 | |
| 256 | git -C src_with_sub submodule add "file://$(pwd)/submodule" mysub && |
| 257 | git -C src_with_sub commit -m "commit with submodule" && |
| 258 | |
| 259 | git -c transfer.fsckobjects=1 \ |
| 260 | clone --filter="blob:none" "file://$(pwd)/src_with_sub" dst && |
| 261 | test_when_finished rm -rf dst |
| 262 | ' |
| 263 | |
Jonathan Tan | 98a2ea4 | 2018-03-14 11:42:41 -0700 | [diff] [blame] | 264 | test_expect_success 'partial clone with transfer.fsckobjects=1 uses index-pack --fsck-objects' ' |
| 265 | git init src && |
| 266 | test_commit -C src x && |
| 267 | test_config -C src uploadpack.allowfilter 1 && |
| 268 | test_config -C src uploadpack.allowanysha1inwant 1 && |
| 269 | |
| 270 | GIT_TRACE="$(pwd)/trace" git -c transfer.fsckobjects=1 \ |
| 271 | clone --filter="blob:none" "file://$(pwd)/src" dst && |
| 272 | grep "git index-pack.*--fsck-objects" trace |
| 273 | ' |
| 274 | |
Matthew DeVore | bc5975d | 2018-10-05 14:31:27 -0700 | [diff] [blame] | 275 | test_expect_success 'use fsck before and after manually fetching a missing subtree' ' |
| 276 | # push new commit so server has a subtree |
| 277 | mkdir src/dir && |
| 278 | echo "in dir" >src/dir/file.txt && |
| 279 | git -C src add dir/file.txt && |
| 280 | git -C src commit -m "file in dir" && |
Johannes Schindelin | 95cf2c0 | 2020-11-18 23:44:35 +0000 | [diff] [blame] | 281 | git -C src push -u srv main && |
Matthew DeVore | bc5975d | 2018-10-05 14:31:27 -0700 | [diff] [blame] | 282 | SUBTREE=$(git -C src rev-parse HEAD:dir) && |
| 283 | |
| 284 | rm -rf dst && |
| 285 | git clone --no-checkout --filter=tree:0 "file://$(pwd)/srv.bare" dst && |
| 286 | git -C dst fsck && |
| 287 | |
| 288 | # Make sure we only have commits, and all trees and blobs are missing. |
Johannes Schindelin | 95cf2c0 | 2020-11-18 23:44:35 +0000 | [diff] [blame] | 289 | git -C dst rev-list --missing=allow-any --objects main \ |
Matthew DeVore | bc5975d | 2018-10-05 14:31:27 -0700 | [diff] [blame] | 290 | >fetched_objects && |
| 291 | awk -f print_1.awk fetched_objects | |
| 292 | xargs -n1 git -C dst cat-file -t >fetched_types && |
| 293 | |
| 294 | sort -u fetched_types >unique_types.observed && |
| 295 | echo commit >unique_types.expected && |
| 296 | test_cmp unique_types.expected unique_types.observed && |
| 297 | |
| 298 | # Auto-fetch a tree with cat-file. |
| 299 | git -C dst cat-file -p $SUBTREE >tree_contents && |
| 300 | grep file.txt tree_contents && |
| 301 | |
| 302 | # fsck still works after an auto-fetch of a tree. |
| 303 | git -C dst fsck && |
| 304 | |
| 305 | # Auto-fetch all remaining trees and blobs with --missing=error |
Johannes Schindelin | 95cf2c0 | 2020-11-18 23:44:35 +0000 | [diff] [blame] | 306 | git -C dst rev-list --missing=error --objects main >fetched_objects && |
Robert Coup | 011b775 | 2022-03-28 14:02:09 +0000 | [diff] [blame] | 307 | test_line_count = 88 fetched_objects && |
Matthew DeVore | bc5975d | 2018-10-05 14:31:27 -0700 | [diff] [blame] | 308 | |
| 309 | awk -f print_1.awk fetched_objects | |
| 310 | xargs -n1 git -C dst cat-file -t >fetched_types && |
| 311 | |
| 312 | sort -u fetched_types >unique_types.observed && |
Matthew DeVore | d9e6d09 | 2018-10-12 13:01:41 -0700 | [diff] [blame] | 313 | test_write_lines blob commit tree >unique_types.expected && |
Matthew DeVore | bc5975d | 2018-10-05 14:31:27 -0700 | [diff] [blame] | 314 | test_cmp unique_types.expected unique_types.observed |
| 315 | ' |
| 316 | |
Matthew DeVore | 489fc9e | 2019-06-27 15:54:12 -0700 | [diff] [blame] | 317 | test_expect_success 'implicitly construct combine: filter with repeated flags' ' |
| 318 | GIT_TRACE=$(pwd)/trace git clone --bare \ |
| 319 | --filter=blob:none --filter=tree:1 \ |
| 320 | "file://$(pwd)/srv.bare" pc2 && |
| 321 | grep "trace:.* git pack-objects .*--filter=combine:blob:none+tree:1" \ |
| 322 | trace && |
| 323 | git -C pc2 rev-list --objects --missing=allow-any HEAD >objects && |
| 324 | |
| 325 | # We should have gotten some root trees. |
| 326 | grep " $" objects && |
| 327 | # Should not have gotten any non-root trees or blobs. |
| 328 | ! grep " ." objects && |
| 329 | |
| 330 | xargs -n 1 git -C pc2 cat-file -t <objects >types && |
| 331 | sort -u types >unique_types.actual && |
| 332 | test_write_lines commit tree >unique_types.expected && |
| 333 | test_cmp unique_types.expected unique_types.actual |
| 334 | ' |
| 335 | |
Jeff King | d43a21b | 2020-12-03 03:09:42 -0500 | [diff] [blame] | 336 | test_expect_success 'upload-pack complains of bogus filter config' ' |
| 337 | printf 0000 | |
| 338 | test_must_fail git \ |
| 339 | -c uploadpackfilter.tree.maxdepth \ |
| 340 | upload-pack . >/dev/null 2>err && |
| 341 | test_i18ngrep "unable to parse.*tree.maxdepth" err |
| 342 | ' |
| 343 | |
Taylor Blau | 6dd3456 | 2020-08-03 14:00:10 -0400 | [diff] [blame] | 344 | test_expect_success 'upload-pack fails banned object filters' ' |
| 345 | test_config -C srv.bare uploadpackfilter.blob:none.allow false && |
| 346 | test_must_fail ok=sigpipe git clone --no-checkout --filter=blob:none \ |
| 347 | "file://$(pwd)/srv.bare" pc3 2>err && |
Jeff King | 6cc275e | 2020-08-05 04:42:40 -0400 | [diff] [blame] | 348 | test_i18ngrep "filter '\''blob:none'\'' not supported" err |
Taylor Blau | 6dd3456 | 2020-08-03 14:00:10 -0400 | [diff] [blame] | 349 | ' |
| 350 | |
| 351 | test_expect_success 'upload-pack fails banned combine object filters' ' |
| 352 | test_config -C srv.bare uploadpackfilter.allow false && |
| 353 | test_config -C srv.bare uploadpackfilter.combine.allow true && |
| 354 | test_config -C srv.bare uploadpackfilter.tree.allow true && |
| 355 | test_config -C srv.bare uploadpackfilter.blob:none.allow false && |
| 356 | test_must_fail ok=sigpipe git clone --no-checkout --filter=tree:1 \ |
| 357 | --filter=blob:none "file://$(pwd)/srv.bare" pc3 2>err && |
Jeff King | 6cc275e | 2020-08-05 04:42:40 -0400 | [diff] [blame] | 358 | test_i18ngrep "filter '\''blob:none'\'' not supported" err |
Taylor Blau | 6dd3456 | 2020-08-03 14:00:10 -0400 | [diff] [blame] | 359 | ' |
| 360 | |
| 361 | test_expect_success 'upload-pack fails banned object filters with fallback' ' |
| 362 | test_config -C srv.bare uploadpackfilter.allow false && |
| 363 | test_must_fail ok=sigpipe git clone --no-checkout --filter=blob:none \ |
| 364 | "file://$(pwd)/srv.bare" pc3 2>err && |
Jeff King | 6cc275e | 2020-08-05 04:42:40 -0400 | [diff] [blame] | 365 | test_i18ngrep "filter '\''blob:none'\'' not supported" err |
Taylor Blau | 6dd3456 | 2020-08-03 14:00:10 -0400 | [diff] [blame] | 366 | ' |
| 367 | |
Taylor Blau | 5b01a4e | 2020-08-03 14:00:17 -0400 | [diff] [blame] | 368 | test_expect_success 'upload-pack limits tree depth filters' ' |
| 369 | test_config -C srv.bare uploadpackfilter.allow false && |
| 370 | test_config -C srv.bare uploadpackfilter.tree.allow true && |
| 371 | test_config -C srv.bare uploadpackfilter.tree.maxDepth 0 && |
| 372 | test_must_fail ok=sigpipe git clone --no-checkout --filter=tree:1 \ |
| 373 | "file://$(pwd)/srv.bare" pc3 2>err && |
Taylor Blau | 8d133f5 | 2020-12-03 13:55:18 -0500 | [diff] [blame] | 374 | test_i18ngrep "tree filter allows max depth 0, but got 1" err && |
| 375 | |
| 376 | git clone --no-checkout --filter=tree:0 "file://$(pwd)/srv.bare" pc4 && |
| 377 | |
| 378 | test_config -C srv.bare uploadpackfilter.tree.maxDepth 5 && |
| 379 | git clone --no-checkout --filter=tree:5 "file://$(pwd)/srv.bare" pc5 && |
| 380 | test_must_fail ok=sigpipe git clone --no-checkout --filter=tree:6 \ |
| 381 | "file://$(pwd)/srv.bare" pc6 2>err && |
| 382 | test_i18ngrep "tree filter allows max depth 5, but got 6" err |
Taylor Blau | 5b01a4e | 2020-08-03 14:00:17 -0400 | [diff] [blame] | 383 | ' |
| 384 | |
Jonathan Tan | a0c9016 | 2018-07-06 12:34:09 -0700 | [diff] [blame] | 385 | test_expect_success 'partial clone fetches blobs pointed to by refs even if normally filtered out' ' |
| 386 | rm -rf src dst && |
| 387 | git init src && |
| 388 | test_commit -C src x && |
| 389 | test_config -C src uploadpack.allowfilter 1 && |
| 390 | test_config -C src uploadpack.allowanysha1inwant 1 && |
| 391 | |
| 392 | # Create a tag pointing to a blob. |
| 393 | BLOB=$(echo blob-contents | git -C src hash-object --stdin -w) && |
| 394 | git -C src tag myblob "$BLOB" && |
| 395 | |
| 396 | git clone --filter="blob:none" "file://$(pwd)/src" dst 2>err && |
| 397 | ! grep "does not point to a valid object" err && |
| 398 | git -C dst fsck |
| 399 | ' |
| 400 | |
Jonathan Tan | 35f9e3e | 2018-09-21 11:22:38 -0700 | [diff] [blame] | 401 | test_expect_success 'fetch what is specified on CLI even if already promised' ' |
| 402 | rm -rf src dst.git && |
| 403 | git init src && |
| 404 | test_commit -C src foo && |
| 405 | test_config -C src uploadpack.allowfilter 1 && |
| 406 | test_config -C src uploadpack.allowanysha1inwant 1 && |
| 407 | |
| 408 | git hash-object --stdin <src/foo.t >blob && |
| 409 | |
| 410 | git clone --bare --filter=blob:none "file://$(pwd)/src" dst.git && |
| 411 | git -C dst.git rev-list --objects --quiet --missing=print HEAD >missing_before && |
| 412 | grep "?$(cat blob)" missing_before && |
| 413 | git -C dst.git fetch origin $(cat blob) && |
| 414 | git -C dst.git rev-list --objects --quiet --missing=print HEAD >missing_after && |
| 415 | ! grep "?$(cat blob)" missing_after |
| 416 | ' |
| 417 | |
Jon Simons | 72de589 | 2019-09-14 21:11:16 -0400 | [diff] [blame] | 418 | test_expect_success 'setup src repo for sparse filter' ' |
| 419 | git init sparse-src && |
| 420 | git -C sparse-src config --local uploadpack.allowfilter 1 && |
| 421 | git -C sparse-src config --local uploadpack.allowanysha1inwant 1 && |
| 422 | test_commit -C sparse-src one && |
| 423 | test_commit -C sparse-src two && |
| 424 | echo /one.t >sparse-src/only-one && |
| 425 | git -C sparse-src add . && |
| 426 | git -C sparse-src commit -m "add sparse checkout files" |
| 427 | ' |
| 428 | |
Jeff King | 4c96a77 | 2019-09-15 12:12:44 -0400 | [diff] [blame] | 429 | test_expect_success 'partial clone with sparse filter succeeds' ' |
Jon Simons | 72de589 | 2019-09-14 21:11:16 -0400 | [diff] [blame] | 430 | rm -rf dst.git && |
| 431 | git clone --no-local --bare \ |
Johannes Schindelin | 95cf2c0 | 2020-11-18 23:44:35 +0000 | [diff] [blame] | 432 | --filter=sparse:oid=main:only-one \ |
Jon Simons | 72de589 | 2019-09-14 21:11:16 -0400 | [diff] [blame] | 433 | sparse-src dst.git && |
| 434 | ( |
| 435 | cd dst.git && |
| 436 | git rev-list --objects --missing=print HEAD >out && |
| 437 | grep "^$(git rev-parse HEAD:one.t)" out && |
| 438 | grep "^?$(git rev-parse HEAD:two.t)" out |
| 439 | ) |
| 440 | ' |
| 441 | |
Jeff King | 4c96a77 | 2019-09-15 12:12:44 -0400 | [diff] [blame] | 442 | test_expect_success 'partial clone with unresolvable sparse filter fails cleanly' ' |
Jon Simons | 72de589 | 2019-09-14 21:11:16 -0400 | [diff] [blame] | 443 | rm -rf dst.git && |
| 444 | test_must_fail git clone --no-local --bare \ |
Johannes Schindelin | 95cf2c0 | 2020-11-18 23:44:35 +0000 | [diff] [blame] | 445 | --filter=sparse:oid=main:no-such-name \ |
Jon Simons | 72de589 | 2019-09-14 21:11:16 -0400 | [diff] [blame] | 446 | sparse-src dst.git 2>err && |
Johannes Schindelin | 95cf2c0 | 2020-11-18 23:44:35 +0000 | [diff] [blame] | 447 | test_i18ngrep "unable to access sparse blob in .main:no-such-name" err && |
Jon Simons | 72de589 | 2019-09-14 21:11:16 -0400 | [diff] [blame] | 448 | test_must_fail git clone --no-local --bare \ |
Johannes Schindelin | 95cf2c0 | 2020-11-18 23:44:35 +0000 | [diff] [blame] | 449 | --filter=sparse:oid=main \ |
Jon Simons | 72de589 | 2019-09-14 21:11:16 -0400 | [diff] [blame] | 450 | sparse-src dst.git 2>err && |
Jon Simons | cf34337 | 2019-09-14 21:13:47 -0400 | [diff] [blame] | 451 | test_i18ngrep "unable to parse sparse filter data in" err |
Jon Simons | 72de589 | 2019-09-14 21:11:16 -0400 | [diff] [blame] | 452 | ' |
| 453 | |
Jonathan Tan | 6462d5e | 2019-11-05 10:56:19 -0800 | [diff] [blame] | 454 | setup_triangle () { |
| 455 | rm -rf big-blob.txt server client promisor-remote && |
| 456 | |
| 457 | printf "line %d\n" $(test_seq 1 100) >big-blob.txt && |
| 458 | |
Jonathan Tan | b54128b | 2020-01-13 12:28:23 -0800 | [diff] [blame] | 459 | # Create a server with 2 commits: a commit with a big tree and a child |
Jonathan Tan | 6462d5e | 2019-11-05 10:56:19 -0800 | [diff] [blame] | 460 | # commit with an incremental change. Also, create a partial clone |
| 461 | # client that only contains the first commit. |
| 462 | git init server && |
| 463 | git -C server config --local uploadpack.allowfilter 1 && |
Jonathan Tan | b54128b | 2020-01-13 12:28:23 -0800 | [diff] [blame] | 464 | for i in $(test_seq 1 100) |
| 465 | do |
| 466 | echo "make the tree big" >server/file$i && |
Eric Sunshine | d0fd993 | 2021-12-09 00:11:14 -0500 | [diff] [blame] | 467 | git -C server add file$i || return 1 |
Jonathan Tan | b54128b | 2020-01-13 12:28:23 -0800 | [diff] [blame] | 468 | done && |
Jonathan Tan | 6462d5e | 2019-11-05 10:56:19 -0800 | [diff] [blame] | 469 | git -C server commit -m "initial" && |
| 470 | git clone --bare --filter=tree:0 "file://$(pwd)/server" client && |
Jonathan Tan | b54128b | 2020-01-13 12:28:23 -0800 | [diff] [blame] | 471 | echo another line >>server/file1 && |
| 472 | git -C server commit -am "incremental change" && |
Jonathan Tan | 6462d5e | 2019-11-05 10:56:19 -0800 | [diff] [blame] | 473 | |
Jonathan Tan | b54128b | 2020-01-13 12:28:23 -0800 | [diff] [blame] | 474 | # Create a promisor remote that only contains the tree and blob from |
| 475 | # the first commit. |
Jonathan Tan | 6462d5e | 2019-11-05 10:56:19 -0800 | [diff] [blame] | 476 | git init promisor-remote && |
Jonathan Tan | b54128b | 2020-01-13 12:28:23 -0800 | [diff] [blame] | 477 | git -C server config --local uploadpack.allowanysha1inwant 1 && |
| 478 | TREE_HASH=$(git -C server rev-parse HEAD~1^{tree}) && |
| 479 | git -C promisor-remote fetch --keep "file://$(pwd)/server" "$TREE_HASH" && |
| 480 | git -C promisor-remote count-objects -v >object-count && |
| 481 | test_i18ngrep "count: 0" object-count && |
| 482 | test_i18ngrep "in-pack: 2" object-count && |
| 483 | |
| 484 | # Set it as the promisor remote of client. Thus, whenever |
| 485 | # the client lazy fetches, the lazy fetch will succeed only if it is |
| 486 | # for this tree or blob. |
Jonathan Tan | 6462d5e | 2019-11-05 10:56:19 -0800 | [diff] [blame] | 487 | test_commit -C promisor-remote one && # so that ref advertisement is not empty |
| 488 | git -C promisor-remote config --local uploadpack.allowanysha1inwant 1 && |
Jonathan Tan | 6462d5e | 2019-11-05 10:56:19 -0800 | [diff] [blame] | 489 | git -C client remote set-url origin "file://$(pwd)/promisor-remote" |
| 490 | } |
| 491 | |
| 492 | # NEEDSWORK: The tests beginning with "fetch lazy-fetches" below only |
| 493 | # test that "fetch" avoid fetching trees and blobs, but not commits or |
| 494 | # tags. Revisit this if Git is ever taught to support partial clones |
| 495 | # with commits and/or tags filtered out. |
| 496 | |
| 497 | test_expect_success 'fetch lazy-fetches only to resolve deltas' ' |
| 498 | setup_triangle && |
| 499 | |
| 500 | # Exercise to make sure it works. Git will not fetch anything from the |
Jonathan Tan | b54128b | 2020-01-13 12:28:23 -0800 | [diff] [blame] | 501 | # promisor remote other than for the big tree (because it needs to |
Jonathan Tan | 6462d5e | 2019-11-05 10:56:19 -0800 | [diff] [blame] | 502 | # resolve the delta). |
| 503 | GIT_TRACE_PACKET="$(pwd)/trace" git -C client \ |
Johannes Schindelin | 95cf2c0 | 2020-11-18 23:44:35 +0000 | [diff] [blame] | 504 | fetch "file://$(pwd)/server" main && |
Jonathan Tan | 6462d5e | 2019-11-05 10:56:19 -0800 | [diff] [blame] | 505 | |
| 506 | # Verify the assumption that the client needed to fetch the delta base |
| 507 | # to resolve the delta. |
Jonathan Tan | b54128b | 2020-01-13 12:28:23 -0800 | [diff] [blame] | 508 | git -C server rev-parse HEAD~1^{tree} >hash && |
Jonathan Tan | 6462d5e | 2019-11-05 10:56:19 -0800 | [diff] [blame] | 509 | grep "want $(cat hash)" trace |
| 510 | ' |
| 511 | |
| 512 | test_expect_success 'fetch lazy-fetches only to resolve deltas, protocol v2' ' |
| 513 | setup_triangle && |
| 514 | |
| 515 | git -C server config --local protocol.version 2 && |
| 516 | git -C client config --local protocol.version 2 && |
| 517 | git -C promisor-remote config --local protocol.version 2 && |
| 518 | |
| 519 | # Exercise to make sure it works. Git will not fetch anything from the |
| 520 | # promisor remote other than for the big blob (because it needs to |
| 521 | # resolve the delta). |
| 522 | GIT_TRACE_PACKET="$(pwd)/trace" git -C client \ |
Johannes Schindelin | 95cf2c0 | 2020-11-18 23:44:35 +0000 | [diff] [blame] | 523 | fetch "file://$(pwd)/server" main && |
Jonathan Tan | 6462d5e | 2019-11-05 10:56:19 -0800 | [diff] [blame] | 524 | |
| 525 | # Verify that protocol version 2 was used. |
| 526 | grep "fetch< version 2" trace && |
| 527 | |
| 528 | # Verify the assumption that the client needed to fetch the delta base |
| 529 | # to resolve the delta. |
Jonathan Tan | b54128b | 2020-01-13 12:28:23 -0800 | [diff] [blame] | 530 | git -C server rev-parse HEAD~1^{tree} >hash && |
Jonathan Tan | 6462d5e | 2019-11-05 10:56:19 -0800 | [diff] [blame] | 531 | grep "want $(cat hash)" trace |
| 532 | ' |
| 533 | |
Jonathan Tan | 5c3b801 | 2020-08-17 21:01:35 -0700 | [diff] [blame] | 534 | test_expect_success 'fetch does not lazy-fetch missing targets of its refs' ' |
| 535 | rm -rf server client trace && |
| 536 | |
| 537 | test_create_repo server && |
| 538 | test_config -C server uploadpack.allowfilter 1 && |
| 539 | test_config -C server uploadpack.allowanysha1inwant 1 && |
| 540 | test_commit -C server foo && |
| 541 | |
| 542 | git clone --filter=blob:none "file://$(pwd)/server" client && |
| 543 | # Make all refs point to nothing by deleting all objects. |
| 544 | rm client/.git/objects/pack/* && |
| 545 | |
| 546 | test_commit -C server bar && |
| 547 | GIT_TRACE_PACKET="$(pwd)/trace" git -C client fetch \ |
| 548 | --no-tags --recurse-submodules=no \ |
| 549 | origin refs/tags/bar && |
| 550 | FOO_HASH=$(git -C server rev-parse foo) && |
| 551 | ! grep "want $FOO_HASH" trace |
| 552 | ' |
| 553 | |
Christian Couder | 08450ef | 2020-05-08 10:01:15 +0200 | [diff] [blame] | 554 | # The following two tests must be in this order. It is important that |
| 555 | # the srv.bare repository did not have tags during clone, but has tags |
Derrick Stolee | d0badf8 | 2020-02-21 21:47:27 +0000 | [diff] [blame] | 556 | # in the fetch. |
| 557 | |
Christian Couder | 08450ef | 2020-05-08 10:01:15 +0200 | [diff] [blame] | 558 | test_expect_success 'verify fetch succeeds when asking for new tags' ' |
Derrick Stolee | d0badf8 | 2020-02-21 21:47:27 +0000 | [diff] [blame] | 559 | git clone --filter=blob:none "file://$(pwd)/srv.bare" tag-test && |
| 560 | for i in I J K |
| 561 | do |
| 562 | test_commit -C src $i && |
| 563 | git -C src branch $i || return 1 |
| 564 | done && |
| 565 | git -C srv.bare fetch --tags origin +refs/heads/*:refs/heads/* && |
| 566 | git -C tag-test -c protocol.version=2 fetch --tags origin |
| 567 | ' |
| 568 | |
Derrick Stolee | 3e96c66 | 2020-02-21 21:47:28 +0000 | [diff] [blame] | 569 | test_expect_success 'verify fetch downloads only one pack when updating refs' ' |
Derrick Stolee | d0badf8 | 2020-02-21 21:47:27 +0000 | [diff] [blame] | 570 | git clone --filter=blob:none "file://$(pwd)/srv.bare" pack-test && |
| 571 | ls pack-test/.git/objects/pack/*pack >pack-list && |
| 572 | test_line_count = 2 pack-list && |
| 573 | for i in A B C |
| 574 | do |
| 575 | test_commit -C src $i && |
| 576 | git -C src branch $i || return 1 |
| 577 | done && |
| 578 | git -C srv.bare fetch origin +refs/heads/*:refs/heads/* && |
| 579 | git -C pack-test fetch origin && |
| 580 | ls pack-test/.git/objects/pack/*pack >pack-list && |
| 581 | test_line_count = 3 pack-list |
| 582 | ' |
| 583 | |
Jeff King | 167a575 | 2020-04-01 08:15:37 -0400 | [diff] [blame] | 584 | test_expect_success 'single-branch tag following respects partial clone' ' |
| 585 | git clone --single-branch -b B --filter=blob:none \ |
| 586 | "file://$(pwd)/srv.bare" single && |
| 587 | git -C single rev-parse --verify refs/tags/B && |
| 588 | git -C single rev-parse --verify refs/tags/A && |
| 589 | test_must_fail git -C single rev-parse --verify refs/tags/C |
| 590 | ' |
| 591 | |
Jonathan Tan | 77aa094 | 2020-07-16 11:09:50 -0700 | [diff] [blame] | 592 | test_expect_success 'fetch from a partial clone, protocol v0' ' |
| 593 | rm -rf server client trace && |
| 594 | |
| 595 | # Pretend that the server is a partial clone |
| 596 | git init server && |
| 597 | git -C server remote add a_remote "file://$(pwd)/" && |
| 598 | test_config -C server core.repositoryformatversion 1 && |
| 599 | test_config -C server extensions.partialclone a_remote && |
| 600 | test_config -C server protocol.version 0 && |
| 601 | test_commit -C server foo && |
| 602 | |
| 603 | # Fetch from the server |
| 604 | git init client && |
| 605 | test_config -C client protocol.version 0 && |
| 606 | test_commit -C client bar && |
| 607 | GIT_TRACE_PACKET="$(pwd)/trace" git -C client fetch "file://$(pwd)/server" && |
| 608 | ! grep "version 2" trace |
| 609 | ' |
| 610 | |
| 611 | test_expect_success 'fetch from a partial clone, protocol v2' ' |
| 612 | rm -rf server client trace && |
| 613 | |
| 614 | # Pretend that the server is a partial clone |
| 615 | git init server && |
| 616 | git -C server remote add a_remote "file://$(pwd)/" && |
| 617 | test_config -C server core.repositoryformatversion 1 && |
| 618 | test_config -C server extensions.partialclone a_remote && |
| 619 | test_config -C server protocol.version 2 && |
| 620 | test_commit -C server foo && |
| 621 | |
| 622 | # Fetch from the server |
| 623 | git init client && |
| 624 | test_config -C client protocol.version 2 && |
| 625 | test_commit -C client bar && |
| 626 | GIT_TRACE_PACKET="$(pwd)/trace" git -C client fetch "file://$(pwd)/server" && |
| 627 | grep "version 2" trace |
| 628 | ' |
| 629 | |
Rafael Silva | a643157 | 2021-04-21 21:32:12 +0200 | [diff] [blame] | 630 | test_expect_success 'repack does not loosen promisor objects' ' |
| 631 | rm -rf client trace && |
| 632 | git clone --bare --filter=blob:none "file://$(pwd)/srv.bare" client && |
| 633 | test_when_finished "rm -rf client trace" && |
| 634 | GIT_TRACE2_PERF="$(pwd)/trace" git -C client repack -A -d && |
| 635 | grep "loosen_unused_packed_objects/loosened:0" trace |
| 636 | ' |
| 637 | |
Jonathan Tan | a7e67c1 | 2018-07-06 12:34:10 -0700 | [diff] [blame] | 638 | . "$TEST_DIRECTORY"/lib-httpd.sh |
| 639 | start_httpd |
| 640 | |
Jonathan Tan | 385d1bf | 2019-05-14 14:10:54 -0700 | [diff] [blame] | 641 | # Converts bytes into their hexadecimal representation. For example, |
| 642 | # "printf 'ab\r\n' | hex_unpack" results in '61620d0a'. |
| 643 | hex_unpack () { |
| 644 | perl -e '$/ = undef; $input = <>; print unpack("H2" x length($input), $input)' |
| 645 | } |
| 646 | |
| 647 | # Inserts $1 at the start of the string and every 2 characters thereafter. |
| 648 | intersperse () { |
| 649 | sed 's/\(..\)/'$1'\1/g' |
| 650 | } |
| 651 | |
Johannes Schindelin | eafff6e | 2020-02-27 13:23:11 +0000 | [diff] [blame] | 652 | # Create a one-time-perl command to replace the existing packfile with $1. |
Jonathan Tan | 385d1bf | 2019-05-14 14:10:54 -0700 | [diff] [blame] | 653 | replace_packfile () { |
| 654 | # The protocol requires that the packfile be sent in sideband 1, hence |
| 655 | # the extra \x01 byte at the beginning. |
Johannes Schindelin | eafff6e | 2020-02-27 13:23:11 +0000 | [diff] [blame] | 656 | cp $1 "$HTTPD_ROOT_PATH/one-time-pack" && |
| 657 | echo 'if (/packfile/) { |
| 658 | print; |
| 659 | my $length = -s "one-time-pack"; |
| 660 | printf "%04x\x01", $length + 5; |
| 661 | print `cat one-time-pack` . "0000"; |
| 662 | last |
| 663 | }' >"$HTTPD_ROOT_PATH/one-time-perl" |
Jonathan Tan | a7e67c1 | 2018-07-06 12:34:10 -0700 | [diff] [blame] | 664 | } |
| 665 | |
| 666 | test_expect_success 'upon cloning, check that all refs point to objects' ' |
| 667 | SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" && |
| 668 | rm -rf "$SERVER" repo && |
| 669 | test_create_repo "$SERVER" && |
| 670 | test_commit -C "$SERVER" foo && |
| 671 | test_config -C "$SERVER" uploadpack.allowfilter 1 && |
| 672 | test_config -C "$SERVER" uploadpack.allowanysha1inwant 1 && |
| 673 | |
| 674 | # Create a tag pointing to a blob. |
| 675 | BLOB=$(echo blob-contents | git -C "$SERVER" hash-object --stdin -w) && |
| 676 | git -C "$SERVER" tag myblob "$BLOB" && |
| 677 | |
| 678 | # Craft a packfile not including that blob. |
| 679 | git -C "$SERVER" rev-parse HEAD | |
Matthew DeVore | bdbc17e | 2018-10-05 14:54:03 -0700 | [diff] [blame] | 680 | git -C "$SERVER" pack-objects --stdout >incomplete.pack && |
Jonathan Tan | a7e67c1 | 2018-07-06 12:34:10 -0700 | [diff] [blame] | 681 | |
| 682 | # Replace the existing packfile with the crafted one. The protocol |
| 683 | # requires that the packfile be sent in sideband 1, hence the extra |
| 684 | # \x01 byte at the beginning. |
Jonathan Tan | 385d1bf | 2019-05-14 14:10:54 -0700 | [diff] [blame] | 685 | replace_packfile incomplete.pack && |
Jonathan Tan | a7e67c1 | 2018-07-06 12:34:10 -0700 | [diff] [blame] | 686 | |
Johannes Schindelin | eafff6e | 2020-02-27 13:23:11 +0000 | [diff] [blame] | 687 | # Use protocol v2 because the perl command looks for the "packfile" |
Jonathan Tan | a7e67c1 | 2018-07-06 12:34:10 -0700 | [diff] [blame] | 688 | # section header. |
| 689 | test_config -C "$SERVER" protocol.version 2 && |
| 690 | test_must_fail git -c protocol.version=2 clone \ |
Johannes Schindelin | eafff6e | 2020-02-27 13:23:11 +0000 | [diff] [blame] | 691 | --filter=blob:none $HTTPD_URL/one_time_perl/server repo 2>err && |
Jonathan Tan | a7e67c1 | 2018-07-06 12:34:10 -0700 | [diff] [blame] | 692 | |
Junio C Hamano | 3813a89 | 2019-01-04 13:33:31 -0800 | [diff] [blame] | 693 | test_i18ngrep "did not send all necessary objects" err && |
Jonathan Tan | a7e67c1 | 2018-07-06 12:34:10 -0700 | [diff] [blame] | 694 | |
Johannes Schindelin | eafff6e | 2020-02-27 13:23:11 +0000 | [diff] [blame] | 695 | # Ensure that the one-time-perl script was used. |
| 696 | ! test -e "$HTTPD_ROOT_PATH/one-time-perl" |
Jonathan Tan | a7e67c1 | 2018-07-06 12:34:10 -0700 | [diff] [blame] | 697 | ' |
| 698 | |
Jonathan Tan | dc0a13f | 2018-07-12 17:03:06 -0700 | [diff] [blame] | 699 | test_expect_success 'when partial cloning, tolerate server not sending target of tag' ' |
| 700 | SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" && |
| 701 | rm -rf "$SERVER" repo && |
| 702 | test_create_repo "$SERVER" && |
| 703 | test_commit -C "$SERVER" foo && |
| 704 | test_config -C "$SERVER" uploadpack.allowfilter 1 && |
| 705 | test_config -C "$SERVER" uploadpack.allowanysha1inwant 1 && |
| 706 | |
| 707 | # Create an annotated tag pointing to a blob. |
| 708 | BLOB=$(echo blob-contents | git -C "$SERVER" hash-object --stdin -w) && |
| 709 | git -C "$SERVER" tag -m message -a myblob "$BLOB" && |
| 710 | |
| 711 | # Craft a packfile including the tag, but not the blob it points to. |
Jonathan Tan | 8c4cc32 | 2018-07-12 17:03:07 -0700 | [diff] [blame] | 712 | # Also, omit objects referenced from HEAD in order to force a second |
| 713 | # fetch (to fetch missing objects) upon the automatic checkout that |
| 714 | # happens after a clone. |
| 715 | printf "%s\n%s\n--not\n%s\n%s\n" \ |
Jonathan Tan | dc0a13f | 2018-07-12 17:03:06 -0700 | [diff] [blame] | 716 | $(git -C "$SERVER" rev-parse HEAD) \ |
| 717 | $(git -C "$SERVER" rev-parse myblob) \ |
Jonathan Tan | 8c4cc32 | 2018-07-12 17:03:07 -0700 | [diff] [blame] | 718 | $(git -C "$SERVER" rev-parse HEAD^{tree}) \ |
Jonathan Tan | dc0a13f | 2018-07-12 17:03:06 -0700 | [diff] [blame] | 719 | $(git -C "$SERVER" rev-parse myblob^{blob}) | |
| 720 | git -C "$SERVER" pack-objects --thin --stdout >incomplete.pack && |
| 721 | |
| 722 | # Replace the existing packfile with the crafted one. The protocol |
| 723 | # requires that the packfile be sent in sideband 1, hence the extra |
| 724 | # \x01 byte at the beginning. |
Jonathan Tan | 385d1bf | 2019-05-14 14:10:54 -0700 | [diff] [blame] | 725 | replace_packfile incomplete.pack && |
Jonathan Tan | dc0a13f | 2018-07-12 17:03:06 -0700 | [diff] [blame] | 726 | |
Johannes Schindelin | eafff6e | 2020-02-27 13:23:11 +0000 | [diff] [blame] | 727 | # Use protocol v2 because the perl command looks for the "packfile" |
Jonathan Tan | dc0a13f | 2018-07-12 17:03:06 -0700 | [diff] [blame] | 728 | # section header. |
| 729 | test_config -C "$SERVER" protocol.version 2 && |
| 730 | |
| 731 | # Exercise to make sure it works. |
| 732 | git -c protocol.version=2 clone \ |
Johannes Schindelin | eafff6e | 2020-02-27 13:23:11 +0000 | [diff] [blame] | 733 | --filter=blob:none $HTTPD_URL/one_time_perl/server repo 2> err && |
Jonathan Tan | 8c4cc32 | 2018-07-12 17:03:07 -0700 | [diff] [blame] | 734 | ! grep "missing object referenced by" err && |
Jonathan Tan | dc0a13f | 2018-07-12 17:03:06 -0700 | [diff] [blame] | 735 | |
Johannes Schindelin | eafff6e | 2020-02-27 13:23:11 +0000 | [diff] [blame] | 736 | # Ensure that the one-time-perl script was used. |
| 737 | ! test -e "$HTTPD_ROOT_PATH/one-time-perl" |
Jonathan Tan | dc0a13f | 2018-07-12 17:03:06 -0700 | [diff] [blame] | 738 | ' |
| 739 | |
Jonathan Tan | 8a30a1e | 2019-05-14 14:10:55 -0700 | [diff] [blame] | 740 | test_expect_success 'tolerate server sending REF_DELTA against missing promisor objects' ' |
| 741 | SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" && |
| 742 | rm -rf "$SERVER" repo && |
| 743 | test_create_repo "$SERVER" && |
| 744 | test_config -C "$SERVER" uploadpack.allowfilter 1 && |
| 745 | test_config -C "$SERVER" uploadpack.allowanysha1inwant 1 && |
| 746 | |
Jonathan Tan | 810e193 | 2019-06-11 14:06:47 -0700 | [diff] [blame] | 747 | # Create a commit with 2 blobs to be used as delta bases. |
Jonathan Tan | 8a30a1e | 2019-05-14 14:10:55 -0700 | [diff] [blame] | 748 | for i in $(test_seq 10) |
| 749 | do |
Jonathan Tan | 810e193 | 2019-06-11 14:06:47 -0700 | [diff] [blame] | 750 | echo "this is a line" >>"$SERVER/foo.txt" && |
Eric Sunshine | d0fd993 | 2021-12-09 00:11:14 -0500 | [diff] [blame] | 751 | echo "this is another line" >>"$SERVER/have.txt" || return 1 |
Jonathan Tan | 8a30a1e | 2019-05-14 14:10:55 -0700 | [diff] [blame] | 752 | done && |
Jonathan Tan | 810e193 | 2019-06-11 14:06:47 -0700 | [diff] [blame] | 753 | git -C "$SERVER" add foo.txt have.txt && |
Jonathan Tan | 8a30a1e | 2019-05-14 14:10:55 -0700 | [diff] [blame] | 754 | git -C "$SERVER" commit -m bar && |
Jonathan Tan | 810e193 | 2019-06-11 14:06:47 -0700 | [diff] [blame] | 755 | git -C "$SERVER" rev-parse HEAD:foo.txt >deltabase_missing && |
| 756 | git -C "$SERVER" rev-parse HEAD:have.txt >deltabase_have && |
Jonathan Tan | 8a30a1e | 2019-05-14 14:10:55 -0700 | [diff] [blame] | 757 | |
Jonathan Tan | 810e193 | 2019-06-11 14:06:47 -0700 | [diff] [blame] | 758 | # Clone. The client has deltabase_have but not deltabase_missing. |
Jonathan Tan | 8a30a1e | 2019-05-14 14:10:55 -0700 | [diff] [blame] | 759 | git -c protocol.version=2 clone --no-checkout \ |
Johannes Schindelin | eafff6e | 2020-02-27 13:23:11 +0000 | [diff] [blame] | 760 | --filter=blob:none $HTTPD_URL/one_time_perl/server repo && |
Jonathan Tan | 810e193 | 2019-06-11 14:06:47 -0700 | [diff] [blame] | 761 | git -C repo hash-object -w -- "$SERVER/have.txt" && |
Jonathan Tan | 8a30a1e | 2019-05-14 14:10:55 -0700 | [diff] [blame] | 762 | |
Jonathan Tan | 810e193 | 2019-06-11 14:06:47 -0700 | [diff] [blame] | 763 | # Sanity check to ensure that the client does not have |
| 764 | # deltabase_missing. |
Jonathan Tan | 5718c53 | 2019-06-11 14:06:46 -0700 | [diff] [blame] | 765 | git -C repo rev-list --objects --ignore-missing \ |
Jonathan Tan | 810e193 | 2019-06-11 14:06:47 -0700 | [diff] [blame] | 766 | -- $(cat deltabase_missing) >objlist && |
Jonathan Tan | 8a30a1e | 2019-05-14 14:10:55 -0700 | [diff] [blame] | 767 | test_line_count = 0 objlist && |
| 768 | |
| 769 | # Another commit. This commit will be fetched by the client. |
| 770 | echo "abcdefghijklmnopqrstuvwxyz" >>"$SERVER/foo.txt" && |
Jonathan Tan | 810e193 | 2019-06-11 14:06:47 -0700 | [diff] [blame] | 771 | echo "abcdefghijklmnopqrstuvwxyz" >>"$SERVER/have.txt" && |
| 772 | git -C "$SERVER" add foo.txt have.txt && |
Jonathan Tan | 8a30a1e | 2019-05-14 14:10:55 -0700 | [diff] [blame] | 773 | git -C "$SERVER" commit -m baz && |
| 774 | |
| 775 | # Pack a thin pack containing, among other things, HEAD:foo.txt |
Jonathan Tan | 810e193 | 2019-06-11 14:06:47 -0700 | [diff] [blame] | 776 | # delta-ed against HEAD^:foo.txt and HEAD:have.txt delta-ed against |
| 777 | # HEAD^:have.txt. |
Jonathan Tan | 8a30a1e | 2019-05-14 14:10:55 -0700 | [diff] [blame] | 778 | printf "%s\n--not\n%s\n" \ |
| 779 | $(git -C "$SERVER" rev-parse HEAD) \ |
| 780 | $(git -C "$SERVER" rev-parse HEAD^) | |
| 781 | git -C "$SERVER" pack-objects --thin --stdout >thin.pack && |
| 782 | |
| 783 | # Ensure that the pack contains one delta against HEAD^:foo.txt. Since |
| 784 | # the delta contains at least 26 novel characters, the size cannot be |
| 785 | # contained in 4 bits, so the object header will take up 2 bytes. The |
| 786 | # most significant nybble of the first byte is 0b1111 (0b1 to indicate |
| 787 | # that the header continues, and 0b111 to indicate REF_DELTA), followed |
| 788 | # by any 3 nybbles, then the OID of the delta base. |
Jonathan Tan | 810e193 | 2019-06-11 14:06:47 -0700 | [diff] [blame] | 789 | printf "f.,..%s" $(intersperse "," <deltabase_missing) >want && |
| 790 | hex_unpack <thin.pack | intersperse "," >have && |
| 791 | grep $(cat want) have && |
| 792 | |
| 793 | # Ensure that the pack contains one delta against HEAD^:have.txt, |
| 794 | # similar to the above. |
| 795 | printf "f.,..%s" $(intersperse "," <deltabase_have) >want && |
Jonathan Tan | 8a30a1e | 2019-05-14 14:10:55 -0700 | [diff] [blame] | 796 | hex_unpack <thin.pack | intersperse "," >have && |
| 797 | grep $(cat want) have && |
| 798 | |
| 799 | replace_packfile thin.pack && |
| 800 | |
Johannes Schindelin | eafff6e | 2020-02-27 13:23:11 +0000 | [diff] [blame] | 801 | # Use protocol v2 because the perl command looks for the "packfile" |
Jonathan Tan | 8a30a1e | 2019-05-14 14:10:55 -0700 | [diff] [blame] | 802 | # section header. |
| 803 | test_config -C "$SERVER" protocol.version 2 && |
| 804 | |
| 805 | # Fetch the thin pack and ensure that index-pack is able to handle the |
| 806 | # REF_DELTA object with a missing promisor delta base. |
Jonathan Tan | 810e193 | 2019-06-11 14:06:47 -0700 | [diff] [blame] | 807 | GIT_TRACE_PACKET="$(pwd)/trace" git -C repo -c protocol.version=2 fetch && |
| 808 | |
| 809 | # Ensure that the missing delta base was directly fetched, but not the |
| 810 | # one that the client has. |
| 811 | grep "want $(cat deltabase_missing)" trace && |
| 812 | ! grep "want $(cat deltabase_have)" trace && |
Jonathan Tan | 8a30a1e | 2019-05-14 14:10:55 -0700 | [diff] [blame] | 813 | |
Johannes Schindelin | eafff6e | 2020-02-27 13:23:11 +0000 | [diff] [blame] | 814 | # Ensure that the one-time-perl script was used. |
| 815 | ! test -e "$HTTPD_ROOT_PATH/one-time-perl" |
Jonathan Tan | 8a30a1e | 2019-05-14 14:10:55 -0700 | [diff] [blame] | 816 | ' |
| 817 | |
SZEDER Gábor | decfe05 | 2019-08-01 17:53:09 +0200 | [diff] [blame] | 818 | # DO NOT add non-httpd-specific tests here, because the last part of this |
| 819 | # test script is only executed when httpd is available and enabled. |
| 820 | |
Jeff Hostetler | 35a7ae9 | 2017-12-08 15:58:49 +0000 | [diff] [blame] | 821 | test_done |