| 1 | #!/bin/sh |
| 2 | |
| 3 | test_description='git repack works correctly' |
| 4 | |
| 5 | . ./test-lib.sh |
| 6 | . "${TEST_DIRECTORY}/lib-bitmap.sh" |
| 7 | . "${TEST_DIRECTORY}/lib-midx.sh" |
| 8 | . "${TEST_DIRECTORY}/lib-terminal.sh" |
| 9 | |
| 10 | GIT_TEST_MULTI_PACK_INDEX=0 |
| 11 | GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0 |
| 12 | |
| 13 | commit_and_pack () { |
| 14 | test_commit "$@" 1>&2 && |
| 15 | incrpackid=$(git pack-objects --all --unpacked --incremental .git/objects/pack/pack </dev/null) && |
| 16 | # Remove any loose object(s) created by test_commit, since they have |
| 17 | # already been packed. Leaving these around can create subtly different |
| 18 | # packs with `pack-objects`'s `--unpacked` option. |
| 19 | git prune-packed 1>&2 && |
| 20 | echo pack-${incrpackid}.pack |
| 21 | } |
| 22 | |
| 23 | test_no_missing_in_packs () { |
| 24 | myidx=$(ls -1 .git/objects/pack/*.idx) && |
| 25 | test_path_is_file "$myidx" && |
| 26 | git verify-pack -v alt_objects/pack/*.idx >orig.raw && |
| 27 | sed -n -e "s/^\($OID_REGEX\).*/\1/p" orig.raw | sort >orig && |
| 28 | git verify-pack -v $myidx >dest.raw && |
| 29 | cut -d" " -f1 dest.raw | sort >dest && |
| 30 | comm -23 orig dest >missing && |
| 31 | test_must_be_empty missing |
| 32 | } |
| 33 | |
| 34 | # we expect $packid and $oid to be defined |
| 35 | test_has_duplicate_object () { |
| 36 | want_duplicate_object="$1" |
| 37 | found_duplicate_object=false |
| 38 | for p in .git/objects/pack/*.idx |
| 39 | do |
| 40 | idx=$(basename $p) |
| 41 | test "pack-$packid.idx" = "$idx" && continue |
| 42 | git verify-pack -v $p >packlist || return $? |
| 43 | if grep "^$oid" packlist |
| 44 | then |
| 45 | found_duplicate_object=true |
| 46 | echo "DUPLICATE OBJECT FOUND" |
| 47 | break |
| 48 | fi |
| 49 | done && |
| 50 | test "$want_duplicate_object" = "$found_duplicate_object" |
| 51 | } |
| 52 | |
| 53 | test_expect_success 'objects in packs marked .keep are not repacked' ' |
| 54 | echo content1 >file1 && |
| 55 | echo content2 >file2 && |
| 56 | git add . && |
| 57 | test_tick && |
| 58 | git commit -m initial_commit && |
| 59 | # Create two packs |
| 60 | # The first pack will contain all of the objects except one |
| 61 | git rev-list --objects --all >objs && |
| 62 | grep -v file2 objs | git pack-objects pack && |
| 63 | # The second pack will contain the excluded object |
| 64 | packid=$(grep file2 objs | git pack-objects pack) && |
| 65 | >pack-$packid.keep && |
| 66 | git verify-pack -v pack-$packid.idx >packlist && |
| 67 | oid=$(head -n 1 packlist | sed -e "s/^\($OID_REGEX\).*/\1/") && |
| 68 | mv pack-* .git/objects/pack/ && |
| 69 | git repack -A -d -l && |
| 70 | git prune-packed && |
| 71 | test_has_duplicate_object false |
| 72 | ' |
| 73 | |
| 74 | test_expect_success 'writing bitmaps via command-line can duplicate .keep objects' ' |
| 75 | # build on $oid, $packid, and .keep state from previous |
| 76 | git repack -Adbl && |
| 77 | test_has_duplicate_object true |
| 78 | ' |
| 79 | |
| 80 | test_expect_success 'writing bitmaps via config can duplicate .keep objects' ' |
| 81 | # build on $oid, $packid, and .keep state from previous |
| 82 | git -c repack.writebitmaps=true repack -Adl && |
| 83 | test_has_duplicate_object true |
| 84 | ' |
| 85 | |
| 86 | test_expect_success 'loose objects in alternate ODB are not repacked' ' |
| 87 | mkdir alt_objects && |
| 88 | echo $(pwd)/alt_objects >.git/objects/info/alternates && |
| 89 | echo content3 >file3 && |
| 90 | oid=$(GIT_OBJECT_DIRECTORY=alt_objects git hash-object -w file3) && |
| 91 | git add file3 && |
| 92 | test_tick && |
| 93 | git commit -m commit_file3 && |
| 94 | git repack -a -d -l && |
| 95 | git prune-packed && |
| 96 | test_has_duplicate_object false |
| 97 | ' |
| 98 | |
| 99 | test_expect_success SYMLINKS '--local keeps packs when alternate is objectdir ' ' |
| 100 | test_when_finished "rm -rf repo" && |
| 101 | git init repo && |
| 102 | test_commit -C repo A && |
| 103 | ( |
| 104 | cd repo && |
| 105 | git repack -a && |
| 106 | ls .git/objects/pack/*.pack >../expect && |
| 107 | ln -s objects .git/alt_objects && |
| 108 | echo "$(pwd)/.git/alt_objects" >.git/objects/info/alternates && |
| 109 | git repack -a -d -l && |
| 110 | ls .git/objects/pack/*.pack >../actual |
| 111 | ) && |
| 112 | test_cmp expect actual |
| 113 | ' |
| 114 | |
| 115 | test_expect_success '--local disables writing bitmaps when connected to alternate ODB' ' |
| 116 | test_when_finished "rm -rf shared member" && |
| 117 | |
| 118 | git init shared && |
| 119 | git clone --shared shared member && |
| 120 | ( |
| 121 | cd member && |
| 122 | test_commit "object" && |
| 123 | git repack -Adl --write-bitmap-index 2>err && |
| 124 | cat >expect <<-EOF && |
| 125 | warning: disabling bitmap writing, as some objects are not being packed |
| 126 | EOF |
| 127 | test_cmp expect err && |
| 128 | test_path_is_missing .git/objects/pack-*.bitmap |
| 129 | ) |
| 130 | ' |
| 131 | |
| 132 | test_expect_success 'packed obs in alt ODB are repacked even when local repo is packless' ' |
| 133 | mkdir alt_objects/pack && |
| 134 | mv .git/objects/pack/* alt_objects/pack && |
| 135 | git repack -a && |
| 136 | test_no_missing_in_packs |
| 137 | ' |
| 138 | |
| 139 | test_expect_success 'packed obs in alt ODB are repacked when local repo has packs' ' |
| 140 | rm -f .git/objects/pack/* && |
| 141 | echo new_content >>file1 && |
| 142 | git add file1 && |
| 143 | test_tick && |
| 144 | git commit -m more_content && |
| 145 | git repack && |
| 146 | git repack -a -d && |
| 147 | test_no_missing_in_packs |
| 148 | ' |
| 149 | |
| 150 | test_expect_success 'packed obs in alternate ODB kept pack are repacked' ' |
| 151 | # swap the .keep so the commit object is in the pack with .keep |
| 152 | for p in alt_objects/pack/*.pack |
| 153 | do |
| 154 | base_name=$(basename $p .pack) && |
| 155 | if test_path_is_file alt_objects/pack/$base_name.keep |
| 156 | then |
| 157 | rm alt_objects/pack/$base_name.keep |
| 158 | else |
| 159 | touch alt_objects/pack/$base_name.keep |
| 160 | fi || return 1 |
| 161 | done && |
| 162 | git repack -a -d && |
| 163 | test_no_missing_in_packs |
| 164 | ' |
| 165 | |
| 166 | test_expect_success 'packed unreachable obs in alternate ODB are not loosened' ' |
| 167 | rm -f alt_objects/pack/*.keep && |
| 168 | mv .git/objects/pack/* alt_objects/pack/ && |
| 169 | coid=$(git rev-parse HEAD^{commit}) && |
| 170 | git reset --hard HEAD^ && |
| 171 | test_tick && |
| 172 | git reflog expire --expire=$test_tick --expire-unreachable=$test_tick --all && |
| 173 | # The pack-objects call on the next line is equivalent to |
| 174 | # git repack -A -d without the call to prune-packed |
| 175 | git pack-objects --honor-pack-keep --non-empty --all --reflog \ |
| 176 | --unpack-unreachable </dev/null pack && |
| 177 | rm -f .git/objects/pack/* && |
| 178 | mv pack-* .git/objects/pack/ && |
| 179 | git verify-pack -v -- .git/objects/pack/*.idx >packlist && |
| 180 | ! grep "^$coid " packlist && |
| 181 | echo >.git/objects/info/alternates && |
| 182 | test_must_fail git show $coid |
| 183 | ' |
| 184 | |
| 185 | test_expect_success 'local packed unreachable obs that exist in alternate ODB are not loosened' ' |
| 186 | echo $(pwd)/alt_objects >.git/objects/info/alternates && |
| 187 | echo "$coid" | git pack-objects --non-empty --all --reflog pack && |
| 188 | rm -f .git/objects/pack/* && |
| 189 | mv pack-* .git/objects/pack/ && |
| 190 | # The pack-objects call on the next line is equivalent to |
| 191 | # git repack -A -d without the call to prune-packed |
| 192 | git pack-objects --honor-pack-keep --non-empty --all --reflog \ |
| 193 | --unpack-unreachable </dev/null pack && |
| 194 | rm -f .git/objects/pack/* && |
| 195 | mv pack-* .git/objects/pack/ && |
| 196 | git verify-pack -v -- .git/objects/pack/*.idx >packlist && |
| 197 | ! grep "^$coid " && |
| 198 | echo >.git/objects/info/alternates && |
| 199 | test_must_fail git show $coid |
| 200 | ' |
| 201 | |
| 202 | test_expect_success 'objects made unreachable by grafts only are kept' ' |
| 203 | test_tick && |
| 204 | git commit --allow-empty -m "commit 4" && |
| 205 | H0=$(git rev-parse HEAD) && |
| 206 | H1=$(git rev-parse HEAD^) && |
| 207 | H2=$(git rev-parse HEAD^^) && |
| 208 | echo "$H0 $H2" >.git/info/grafts && |
| 209 | git reflog expire --expire=$test_tick --expire-unreachable=$test_tick --all && |
| 210 | git repack -a -d && |
| 211 | git cat-file -t $H1 |
| 212 | ' |
| 213 | |
| 214 | test_expect_success 'repack --keep-pack' ' |
| 215 | test_create_repo keep-pack && |
| 216 | ( |
| 217 | cd keep-pack && |
| 218 | # avoid producing different packs due to delta/base choices |
| 219 | git config pack.window 0 && |
| 220 | git config maintenance.auto false && |
| 221 | P1=$(commit_and_pack 1) && |
| 222 | P2=$(commit_and_pack 2) && |
| 223 | P3=$(commit_and_pack 3) && |
| 224 | P4=$(commit_and_pack 4) && |
| 225 | ls .git/objects/pack/*.pack >old-counts && |
| 226 | test_line_count = 4 old-counts && |
| 227 | git repack -a -d --keep-pack $P1 --keep-pack $P4 && |
| 228 | ls .git/objects/pack/*.pack >new-counts && |
| 229 | grep -q $P1 new-counts && |
| 230 | grep -q $P4 new-counts && |
| 231 | test_line_count = 3 new-counts && |
| 232 | git fsck && |
| 233 | |
| 234 | P5=$(commit_and_pack --no-tag 5) && |
| 235 | git reset --hard HEAD^ && |
| 236 | git reflog expire --all --expire=all && |
| 237 | rm -f ".git/objects/pack/${P5%.pack}.idx" && |
| 238 | rm -f ".git/objects/info/commit-graph" && |
| 239 | for from in $(find .git/objects/pack -type f -name "${P5%.pack}.*") |
| 240 | do |
| 241 | to="$(dirname "$from")/.tmp-1234-$(basename "$from")" && |
| 242 | mv "$from" "$to" || return 1 |
| 243 | done && |
| 244 | |
| 245 | # A .idx file without a .pack should not stop us from |
| 246 | # repacking what we can. |
| 247 | touch .git/objects/pack/pack-does-not-exist.idx && |
| 248 | |
| 249 | git repack --cruft -d --keep-pack $P1 --keep-pack $P4 && |
| 250 | |
| 251 | ls .git/objects/pack/*.pack >newer-counts && |
| 252 | test_cmp new-counts newer-counts && |
| 253 | git fsck |
| 254 | ) |
| 255 | ' |
| 256 | |
| 257 | test_expect_success 'repacking fails when missing .pack actually means missing objects' ' |
| 258 | test_create_repo idx-without-pack && |
| 259 | ( |
| 260 | cd idx-without-pack && |
| 261 | |
| 262 | # Avoid producing different packs due to delta/base choices |
| 263 | git config pack.window 0 && |
| 264 | git config maintenance.auto false && |
| 265 | P1=$(commit_and_pack 1) && |
| 266 | P2=$(commit_and_pack 2) && |
| 267 | P3=$(commit_and_pack 3) && |
| 268 | P4=$(commit_and_pack 4) && |
| 269 | ls .git/objects/pack/*.pack >old-counts && |
| 270 | test_line_count = 4 old-counts && |
| 271 | |
| 272 | # Remove one .pack file |
| 273 | rm .git/objects/pack/$P2 && |
| 274 | |
| 275 | ls .git/objects/pack/*.pack >before-pack-dir && |
| 276 | |
| 277 | test_must_fail git fsck && |
| 278 | test_must_fail env GIT_COMMIT_GRAPH_PARANOIA=true git repack --cruft -d 2>err && |
| 279 | grep "bad object" err && |
| 280 | |
| 281 | # Before failing, the repack did not modify the |
| 282 | # pack directory. |
| 283 | ls .git/objects/pack/*.pack >after-pack-dir && |
| 284 | test_cmp before-pack-dir after-pack-dir |
| 285 | ) |
| 286 | ' |
| 287 | |
| 288 | test_expect_success 'bitmaps are created by default in bare repos' ' |
| 289 | git clone --bare .git bare.git && |
| 290 | rm -f bare.git/objects/pack/*.bitmap && |
| 291 | git -C bare.git repack -ad && |
| 292 | bitmap=$(ls bare.git/objects/pack/*.bitmap) && |
| 293 | test_path_is_file "$bitmap" |
| 294 | ' |
| 295 | |
| 296 | test_expect_success 'incremental repack does not complain' ' |
| 297 | git -C bare.git repack -q 2>repack.err && |
| 298 | test_must_be_empty repack.err |
| 299 | ' |
| 300 | |
| 301 | test_expect_success 'bitmaps can be disabled on bare repos' ' |
| 302 | git -c repack.writeBitmaps=false -C bare.git repack -ad && |
| 303 | bitmap=$(ls bare.git/objects/pack/*.bitmap || :) && |
| 304 | test -z "$bitmap" |
| 305 | ' |
| 306 | |
| 307 | test_expect_success 'no bitmaps created if .keep files present' ' |
| 308 | pack=$(ls bare.git/objects/pack/*.pack) && |
| 309 | test_path_is_file "$pack" && |
| 310 | keep=${pack%.pack}.keep && |
| 311 | test_when_finished "rm -f \"\$keep\"" && |
| 312 | >"$keep" && |
| 313 | |
| 314 | # Disable --name-hash-version test due to stderr comparison. |
| 315 | GIT_TEST_NAME_HASH_VERSION=1 \ |
| 316 | git -C bare.git repack -ad 2>stderr && |
| 317 | test_must_be_empty stderr && |
| 318 | find bare.git/objects/pack/ -type f -name "*.bitmap" >actual && |
| 319 | test_must_be_empty actual |
| 320 | ' |
| 321 | |
| 322 | test_expect_success 'auto-bitmaps do not complain if unavailable' ' |
| 323 | test_config -C bare.git pack.packSizeLimit 1M && |
| 324 | blob=$(test-tool genrandom big 1m | |
| 325 | git -C bare.git hash-object -w --stdin) && |
| 326 | git -C bare.git update-ref refs/tags/big $blob && |
| 327 | |
| 328 | # Disable --name-hash-version test due to stderr comparison. |
| 329 | GIT_TEST_NAME_HASH_VERSION=1 \ |
| 330 | git -C bare.git repack -ad 2>stderr && |
| 331 | test_must_be_empty stderr && |
| 332 | find bare.git/objects/pack -type f -name "*.bitmap" >actual && |
| 333 | test_must_be_empty actual |
| 334 | ' |
| 335 | |
| 336 | test_expect_success 'repacking with a filter works' ' |
| 337 | git -C bare.git repack -a -d && |
| 338 | test_stdout_line_count = 1 ls bare.git/objects/pack/*.pack && |
| 339 | git -C bare.git -c repack.writebitmaps=false repack -a -d --filter=blob:none && |
| 340 | test_stdout_line_count = 2 ls bare.git/objects/pack/*.pack && |
| 341 | commit_pack=$(test-tool -C bare.git find-pack -c 1 HEAD) && |
| 342 | blob_pack=$(test-tool -C bare.git find-pack -c 1 HEAD:file1) && |
| 343 | test "$commit_pack" != "$blob_pack" && |
| 344 | tree_pack=$(test-tool -C bare.git find-pack -c 1 HEAD^{tree}) && |
| 345 | test "$tree_pack" = "$commit_pack" && |
| 346 | blob_pack2=$(test-tool -C bare.git find-pack -c 1 HEAD:file2) && |
| 347 | test "$blob_pack2" = "$blob_pack" |
| 348 | ' |
| 349 | |
| 350 | test_expect_success '--filter fails with --write-bitmap-index' ' |
| 351 | test_must_fail git -C bare.git repack -a -d --write-bitmap-index --filter=blob:none |
| 352 | ' |
| 353 | |
| 354 | test_expect_success 'repacking with two filters works' ' |
| 355 | git init two-filters && |
| 356 | ( |
| 357 | cd two-filters && |
| 358 | mkdir subdir && |
| 359 | test_commit foo && |
| 360 | test_commit subdir_bar subdir/bar && |
| 361 | test_commit subdir_baz subdir/baz |
| 362 | ) && |
| 363 | git clone --no-local --bare two-filters two-filters.git && |
| 364 | ( |
| 365 | cd two-filters.git && |
| 366 | test_stdout_line_count = 1 ls objects/pack/*.pack && |
| 367 | git -c repack.writebitmaps=false repack -a -d \ |
| 368 | --filter=blob:none --filter=tree:1 && |
| 369 | test_stdout_line_count = 2 ls objects/pack/*.pack && |
| 370 | commit_pack=$(test-tool find-pack -c 1 HEAD) && |
| 371 | blob_pack=$(test-tool find-pack -c 1 HEAD:foo.t) && |
| 372 | root_tree_pack=$(test-tool find-pack -c 1 HEAD^{tree}) && |
| 373 | subdir_tree_hash=$(git ls-tree --object-only HEAD -- subdir) && |
| 374 | subdir_tree_pack=$(test-tool find-pack -c 1 "$subdir_tree_hash") && |
| 375 | |
| 376 | # Root tree and subdir tree are not in the same packfiles |
| 377 | test "$commit_pack" != "$blob_pack" && |
| 378 | test "$commit_pack" = "$root_tree_pack" && |
| 379 | test "$blob_pack" = "$subdir_tree_pack" |
| 380 | ) |
| 381 | ' |
| 382 | |
| 383 | prepare_for_keep_packs () { |
| 384 | git init keep-packs && |
| 385 | ( |
| 386 | cd keep-packs && |
| 387 | test_commit foo && |
| 388 | test_commit bar |
| 389 | ) && |
| 390 | git clone --no-local --bare keep-packs keep-packs.git && |
| 391 | ( |
| 392 | cd keep-packs.git && |
| 393 | |
| 394 | # Create two packs |
| 395 | # The first pack will contain all of the objects except one blob |
| 396 | git rev-list --objects --all >objs && |
| 397 | grep -v "bar.t" objs | git pack-objects pack && |
| 398 | # The second pack will contain the excluded object and be kept |
| 399 | packid=$(grep "bar.t" objs | git pack-objects pack) && |
| 400 | >pack-$packid.keep && |
| 401 | |
| 402 | # Replace the existing pack with the 2 new ones |
| 403 | rm -f objects/pack/pack* && |
| 404 | mv pack-* objects/pack/ |
| 405 | ) |
| 406 | } |
| 407 | |
| 408 | test_expect_success '--filter works with .keep packs' ' |
| 409 | prepare_for_keep_packs && |
| 410 | ( |
| 411 | cd keep-packs.git && |
| 412 | |
| 413 | foo_pack=$(test-tool find-pack -c 1 HEAD:foo.t) && |
| 414 | bar_pack=$(test-tool find-pack -c 1 HEAD:bar.t) && |
| 415 | head_pack=$(test-tool find-pack -c 1 HEAD) && |
| 416 | |
| 417 | test "$foo_pack" != "$bar_pack" && |
| 418 | test "$foo_pack" = "$head_pack" && |
| 419 | |
| 420 | git -c repack.writebitmaps=false repack -a -d --filter=blob:none && |
| 421 | |
| 422 | foo_pack_1=$(test-tool find-pack -c 1 HEAD:foo.t) && |
| 423 | bar_pack_1=$(test-tool find-pack -c 1 HEAD:bar.t) && |
| 424 | head_pack_1=$(test-tool find-pack -c 1 HEAD) && |
| 425 | |
| 426 | # Object bar is still only in the old .keep pack |
| 427 | test "$foo_pack_1" != "$foo_pack" && |
| 428 | test "$bar_pack_1" = "$bar_pack" && |
| 429 | test "$head_pack_1" != "$head_pack" && |
| 430 | |
| 431 | test "$foo_pack_1" != "$bar_pack_1" && |
| 432 | test "$foo_pack_1" != "$head_pack_1" && |
| 433 | test "$bar_pack_1" != "$head_pack_1" |
| 434 | ) |
| 435 | ' |
| 436 | |
| 437 | test_expect_success '--filter works with --pack-kept-objects and .keep packs' ' |
| 438 | rm -rf keep-packs keep-packs.git && |
| 439 | prepare_for_keep_packs && |
| 440 | ( |
| 441 | cd keep-packs.git && |
| 442 | |
| 443 | foo_pack=$(test-tool find-pack -c 1 HEAD:foo.t) && |
| 444 | bar_pack=$(test-tool find-pack -c 1 HEAD:bar.t) && |
| 445 | head_pack=$(test-tool find-pack -c 1 HEAD) && |
| 446 | |
| 447 | test "$foo_pack" != "$bar_pack" && |
| 448 | test "$foo_pack" = "$head_pack" && |
| 449 | |
| 450 | git -c repack.writebitmaps=false repack -a -d --filter=blob:none \ |
| 451 | --pack-kept-objects && |
| 452 | |
| 453 | foo_pack_1=$(test-tool find-pack -c 1 HEAD:foo.t) && |
| 454 | test-tool find-pack -c 2 HEAD:bar.t >bar_pack_1 && |
| 455 | head_pack_1=$(test-tool find-pack -c 1 HEAD) && |
| 456 | |
| 457 | test "$foo_pack_1" != "$foo_pack" && |
| 458 | test "$foo_pack_1" != "$bar_pack" && |
| 459 | test "$head_pack_1" != "$head_pack" && |
| 460 | |
| 461 | # Object bar is in both the old .keep pack and the new |
| 462 | # pack that contained the filtered out objects |
| 463 | grep "$bar_pack" bar_pack_1 && |
| 464 | grep "$foo_pack_1" bar_pack_1 && |
| 465 | test "$foo_pack_1" != "$head_pack_1" |
| 466 | ) |
| 467 | ' |
| 468 | |
| 469 | test_expect_success '--filter-to stores filtered out objects' ' |
| 470 | git -C bare.git repack -a -d && |
| 471 | test_stdout_line_count = 1 ls bare.git/objects/pack/*.pack && |
| 472 | |
| 473 | git init --bare filtered.git && |
| 474 | git -C bare.git -c repack.writebitmaps=false repack -a -d \ |
| 475 | --filter=blob:none \ |
| 476 | --filter-to=../filtered.git/objects/pack/pack && |
| 477 | test_stdout_line_count = 1 ls bare.git/objects/pack/pack-*.pack && |
| 478 | test_stdout_line_count = 1 ls filtered.git/objects/pack/pack-*.pack && |
| 479 | |
| 480 | commit_pack=$(test-tool -C bare.git find-pack -c 1 HEAD) && |
| 481 | blob_pack=$(test-tool -C bare.git find-pack -c 0 HEAD:file1) && |
| 482 | blob_hash=$(git -C bare.git rev-parse HEAD:file1) && |
| 483 | test -n "$blob_hash" && |
| 484 | blob_pack=$(test-tool -C filtered.git find-pack -c 1 $blob_hash) && |
| 485 | |
| 486 | echo $(pwd)/filtered.git/objects >bare.git/objects/info/alternates && |
| 487 | blob_pack=$(test-tool -C bare.git find-pack -c 1 HEAD:file1) && |
| 488 | blob_content=$(git -C bare.git show $blob_hash) && |
| 489 | test "$blob_content" = "content1" |
| 490 | ' |
| 491 | |
| 492 | test_expect_success '--filter works with --max-pack-size' ' |
| 493 | rm -rf filtered.git && |
| 494 | git init --bare filtered.git && |
| 495 | git init max-pack-size && |
| 496 | ( |
| 497 | cd max-pack-size && |
| 498 | test_commit base && |
| 499 | # two blobs which exceed the maximum pack size |
| 500 | test-tool genrandom foo 1m >foo && |
| 501 | git hash-object -w foo && |
| 502 | test-tool genrandom bar 1m >bar && |
| 503 | git hash-object -w bar && |
| 504 | git add foo bar && |
| 505 | git commit -m "adding foo and bar" |
| 506 | ) && |
| 507 | git clone --no-local --bare max-pack-size max-pack-size.git && |
| 508 | ( |
| 509 | cd max-pack-size.git && |
| 510 | git -c repack.writebitmaps=false repack -a -d --filter=blob:none \ |
| 511 | --max-pack-size=1M \ |
| 512 | --filter-to=../filtered.git/objects/pack/pack && |
| 513 | echo $(cd .. && pwd)/filtered.git/objects >objects/info/alternates && |
| 514 | |
| 515 | # Check that the 3 blobs are in different packfiles in filtered.git |
| 516 | test_stdout_line_count = 3 ls ../filtered.git/objects/pack/pack-*.pack && |
| 517 | test_stdout_line_count = 1 ls objects/pack/pack-*.pack && |
| 518 | foo_pack=$(test-tool find-pack -c 1 HEAD:foo) && |
| 519 | bar_pack=$(test-tool find-pack -c 1 HEAD:bar) && |
| 520 | base_pack=$(test-tool find-pack -c 1 HEAD:base.t) && |
| 521 | test "$foo_pack" != "$bar_pack" && |
| 522 | test "$foo_pack" != "$base_pack" && |
| 523 | test "$bar_pack" != "$base_pack" && |
| 524 | for pack in "$foo_pack" "$bar_pack" "$base_pack" |
| 525 | do |
| 526 | case "$foo_pack" in */filtered.git/objects/pack/*) true ;; *) return 1 ;; esac |
| 527 | done |
| 528 | ) |
| 529 | ' |
| 530 | |
| 531 | objdir=.git/objects |
| 532 | midx=$objdir/pack/multi-pack-index |
| 533 | |
| 534 | test_expect_success 'setup for --write-midx tests' ' |
| 535 | git init midx && |
| 536 | ( |
| 537 | cd midx && |
| 538 | git config core.multiPackIndex true && |
| 539 | git config maintenance.auto false && |
| 540 | |
| 541 | test_commit base |
| 542 | ) |
| 543 | ' |
| 544 | |
| 545 | test_expect_success '--write-midx unchanged' ' |
| 546 | ( |
| 547 | cd midx && |
| 548 | git repack && |
| 549 | test_path_is_missing $midx && |
| 550 | test_path_is_missing $midx-*.bitmap && |
| 551 | |
| 552 | git repack --write-midx && |
| 553 | |
| 554 | test_path_is_file $midx && |
| 555 | test_path_is_missing $midx-*.bitmap && |
| 556 | test_midx_consistent $objdir |
| 557 | ) |
| 558 | ' |
| 559 | |
| 560 | test_expect_success '--write-midx with a new pack' ' |
| 561 | ( |
| 562 | cd midx && |
| 563 | test_commit loose && |
| 564 | |
| 565 | git repack --write-midx && |
| 566 | |
| 567 | test_path_is_file $midx && |
| 568 | test_path_is_missing $midx-*.bitmap && |
| 569 | test_midx_consistent $objdir |
| 570 | ) |
| 571 | ' |
| 572 | |
| 573 | test_expect_success '--write-midx with -b' ' |
| 574 | ( |
| 575 | cd midx && |
| 576 | git repack -mb && |
| 577 | |
| 578 | test_path_is_file $midx && |
| 579 | test_path_is_file $midx-*.bitmap && |
| 580 | test_midx_consistent $objdir |
| 581 | ) |
| 582 | ' |
| 583 | |
| 584 | test_expect_success '--write-midx with -d' ' |
| 585 | ( |
| 586 | cd midx && |
| 587 | test_commit repack && |
| 588 | |
| 589 | git repack -Ad --write-midx && |
| 590 | |
| 591 | test_path_is_file $midx && |
| 592 | test_path_is_missing $midx-*.bitmap && |
| 593 | test_midx_consistent $objdir |
| 594 | ) |
| 595 | ' |
| 596 | |
| 597 | test_expect_success 'cleans up MIDX when appropriate' ' |
| 598 | ( |
| 599 | cd midx && |
| 600 | |
| 601 | test_commit repack-2 && |
| 602 | git repack -Adb --write-midx && |
| 603 | |
| 604 | checksum=$(midx_checksum $objdir) && |
| 605 | test_path_is_file $midx && |
| 606 | test_path_is_file $midx-$checksum.bitmap && |
| 607 | |
| 608 | test_commit repack-3 && |
| 609 | git repack -Adb --write-midx && |
| 610 | |
| 611 | test_path_is_file $midx && |
| 612 | test_path_is_missing $midx-$checksum.bitmap && |
| 613 | test_path_is_file $midx-$(midx_checksum $objdir).bitmap && |
| 614 | |
| 615 | test_commit repack-4 && |
| 616 | git repack -Adb && |
| 617 | |
| 618 | find $objdir/pack -type f -name "multi-pack-index*" >files && |
| 619 | test_must_be_empty files |
| 620 | ) |
| 621 | ' |
| 622 | |
| 623 | test_expect_success '--write-midx with preferred bitmap tips' ' |
| 624 | git init midx-preferred-tips && |
| 625 | test_when_finished "rm -fr midx-preferred-tips" && |
| 626 | ( |
| 627 | cd midx-preferred-tips && |
| 628 | |
| 629 | test_commit_bulk --message="%s" 103 && |
| 630 | |
| 631 | git log --format="%H" >commits.raw && |
| 632 | sort <commits.raw >commits && |
| 633 | |
| 634 | git log --format="create refs/tags/%s/%s %H" HEAD >refs && |
| 635 | git update-ref --stdin <refs && |
| 636 | |
| 637 | git repack --write-midx --write-bitmap-index && |
| 638 | test_path_is_file $midx && |
| 639 | test_path_is_file $midx-$(midx_checksum $objdir).bitmap && |
| 640 | |
| 641 | test-tool bitmap list-commits | sort >bitmaps && |
| 642 | comm -13 bitmaps commits >before && |
| 643 | test_line_count = 1 before && |
| 644 | |
| 645 | rm -fr $midx-$(midx_checksum $objdir).bitmap && |
| 646 | rm -fr $midx && |
| 647 | |
| 648 | # instead of constructing the snapshot ourselves (c.f., the test |
| 649 | # "write a bitmap with --refs-snapshot (preferred tips)" in |
| 650 | # t5326), mark the missing commit as preferred by adding it to |
| 651 | # the pack.preferBitmapTips configuration. |
| 652 | git for-each-ref --format="%(refname:rstrip=1)" \ |
| 653 | --points-at="$(cat before)" >missing && |
| 654 | git config pack.preferBitmapTips "$(cat missing)" && |
| 655 | git repack --write-midx --write-bitmap-index && |
| 656 | |
| 657 | test-tool bitmap list-commits | sort >bitmaps && |
| 658 | comm -13 bitmaps commits >after && |
| 659 | |
| 660 | ! test_cmp before after |
| 661 | ) |
| 662 | ' |
| 663 | |
| 664 | # The first argument is expected to be a filename |
| 665 | # and that file should contain the name of a .idx |
| 666 | # file. Send the list of objects in that .idx file |
| 667 | # into stdout. |
| 668 | get_sorted_objects_from_pack () { |
| 669 | git show-index <$(cat "$1") >raw && |
| 670 | cut -d" " -f2 raw |
| 671 | } |
| 672 | |
| 673 | test_expect_success '--write-midx -b packs non-kept objects' ' |
| 674 | git init repo && |
| 675 | test_when_finished "rm -fr repo" && |
| 676 | ( |
| 677 | cd repo && |
| 678 | |
| 679 | # Create a kept pack-file |
| 680 | test_commit base && |
| 681 | git repack -ad && |
| 682 | find $objdir/pack -name "*.idx" >before && |
| 683 | test_line_count = 1 before && |
| 684 | before_name=$(cat before) && |
| 685 | >${before_name%.idx}.keep && |
| 686 | |
| 687 | # Create a non-kept pack-file |
| 688 | test_commit other && |
| 689 | git repack && |
| 690 | |
| 691 | # Create loose objects |
| 692 | test_commit loose && |
| 693 | |
| 694 | # Repack everything |
| 695 | git repack --write-midx -a -b -d && |
| 696 | |
| 697 | # There should be two pack-files now, the |
| 698 | # old, kept pack and the new, non-kept pack. |
| 699 | find $objdir/pack -name "*.idx" | sort >after && |
| 700 | test_line_count = 2 after && |
| 701 | find $objdir/pack -name "*.keep" >kept && |
| 702 | kept_name=$(cat kept) && |
| 703 | echo ${kept_name%.keep}.idx >kept-idx && |
| 704 | test_cmp before kept-idx && |
| 705 | |
| 706 | # Get object list from the kept pack. |
| 707 | get_sorted_objects_from_pack before >old.objects && |
| 708 | |
| 709 | # Get object list from the one non-kept pack-file |
| 710 | comm -13 before after >new-pack && |
| 711 | test_line_count = 1 new-pack && |
| 712 | get_sorted_objects_from_pack new-pack >new.objects && |
| 713 | |
| 714 | # None of the objects in the new pack should |
| 715 | # exist within the kept pack. |
| 716 | comm -12 old.objects new.objects >shared.objects && |
| 717 | test_must_be_empty shared.objects |
| 718 | ) |
| 719 | ' |
| 720 | |
| 721 | test_expect_success '--write-midx removes stale pack-based bitmaps' ' |
| 722 | rm -fr repo && |
| 723 | git init repo && |
| 724 | test_when_finished "rm -fr repo" && |
| 725 | ( |
| 726 | cd repo && |
| 727 | test_commit base && |
| 728 | git repack -Ab && |
| 729 | |
| 730 | pack_bitmap=$(ls $objdir/pack/pack-*.bitmap) && |
| 731 | test_path_is_file "$pack_bitmap" && |
| 732 | |
| 733 | test_commit tip && |
| 734 | git repack -bm && |
| 735 | |
| 736 | test_path_is_file $midx && |
| 737 | test_path_is_file $midx-$(midx_checksum $objdir).bitmap && |
| 738 | test_path_is_missing $pack_bitmap |
| 739 | ) |
| 740 | ' |
| 741 | |
| 742 | test_expect_success '--write-midx with --pack-kept-objects' ' |
| 743 | git init repo && |
| 744 | test_when_finished "rm -fr repo" && |
| 745 | ( |
| 746 | cd repo && |
| 747 | |
| 748 | test_commit one && |
| 749 | test_commit two && |
| 750 | |
| 751 | one="$(echo "one" | git pack-objects --revs $objdir/pack/pack)" && |
| 752 | two="$(echo "one..two" | git pack-objects --revs $objdir/pack/pack)" && |
| 753 | |
| 754 | keep="$objdir/pack/pack-$one.keep" && |
| 755 | touch "$keep" && |
| 756 | |
| 757 | git repack --write-midx --write-bitmap-index --geometric=2 -d \ |
| 758 | --pack-kept-objects && |
| 759 | |
| 760 | test_path_is_file $keep && |
| 761 | test_path_is_file $midx && |
| 762 | test_path_is_file $midx-$(midx_checksum $objdir).bitmap |
| 763 | ) |
| 764 | ' |
| 765 | |
| 766 | test_expect_success TTY '--quiet disables progress' ' |
| 767 | test_terminal env GIT_PROGRESS_DELAY=0 \ |
| 768 | git -C midx repack -ad --quiet --write-midx 2>stderr && |
| 769 | test_must_be_empty stderr |
| 770 | ' |
| 771 | |
| 772 | test_expect_success 'clean up .tmp-* packs on error' ' |
| 773 | test_must_fail ok=sigpipe git \ |
| 774 | -c repack.cruftwindow=bogus \ |
| 775 | repack -ad --cruft && |
| 776 | find $objdir/pack -name '.tmp-*' >tmpfiles && |
| 777 | test_must_be_empty tmpfiles |
| 778 | ' |
| 779 | |
| 780 | test_expect_success 'repack -ad cleans up old .tmp-* packs' ' |
| 781 | git rev-parse HEAD >input && |
| 782 | git pack-objects $objdir/pack/.tmp-1234 <input && |
| 783 | git repack -ad && |
| 784 | find $objdir/pack -name '.tmp-*' >tmpfiles && |
| 785 | test_must_be_empty tmpfiles |
| 786 | ' |
| 787 | |
| 788 | test_expect_success '--name-hash-version option passes through to pack-objects' ' |
| 789 | GIT_TRACE2_EVENT="$(pwd)/hash-trace.txt" \ |
| 790 | git repack -a --name-hash-version=2 && |
| 791 | test_subcommand_flex git pack-objects --name-hash-version=2 <hash-trace.txt |
| 792 | ' |
| 793 | |
| 794 | test_expect_success 'setup for update-server-info' ' |
| 795 | git init update-server-info && |
| 796 | test_commit -C update-server-info message |
| 797 | ' |
| 798 | |
| 799 | test_server_info_present () { |
| 800 | test_path_is_file update-server-info/.git/objects/info/packs && |
| 801 | test_path_is_file update-server-info/.git/info/refs |
| 802 | } |
| 803 | |
| 804 | test_server_info_missing () { |
| 805 | test_path_is_missing update-server-info/.git/objects/info/packs && |
| 806 | test_path_is_missing update-server-info/.git/info/refs |
| 807 | } |
| 808 | |
| 809 | test_server_info_cleanup () { |
| 810 | rm -f update-server-info/.git/objects/info/packs update-server-info/.git/info/refs && |
| 811 | test_server_info_missing |
| 812 | } |
| 813 | |
| 814 | test_expect_success 'updates server info by default' ' |
| 815 | test_server_info_cleanup && |
| 816 | git -C update-server-info repack && |
| 817 | test_server_info_present |
| 818 | ' |
| 819 | |
| 820 | test_expect_success '-n skips updating server info' ' |
| 821 | test_server_info_cleanup && |
| 822 | git -C update-server-info repack -n && |
| 823 | test_server_info_missing |
| 824 | ' |
| 825 | |
| 826 | test_expect_success 'repack.updateServerInfo=true updates server info' ' |
| 827 | test_server_info_cleanup && |
| 828 | git -C update-server-info -c repack.updateServerInfo=true repack && |
| 829 | test_server_info_present |
| 830 | ' |
| 831 | |
| 832 | test_expect_success 'repack.updateServerInfo=false skips updating server info' ' |
| 833 | test_server_info_cleanup && |
| 834 | git -C update-server-info -c repack.updateServerInfo=false repack && |
| 835 | test_server_info_missing |
| 836 | ' |
| 837 | |
| 838 | test_expect_success '-n overrides repack.updateServerInfo=true' ' |
| 839 | test_server_info_cleanup && |
| 840 | git -C update-server-info -c repack.updateServerInfo=true repack -n && |
| 841 | test_server_info_missing |
| 842 | ' |
| 843 | |
| 844 | test_expect_success 'pending objects are repacked appropriately' ' |
| 845 | test_when_finished rm -rf pending && |
| 846 | git init pending && |
| 847 | |
| 848 | ( |
| 849 | cd pending && |
| 850 | |
| 851 | # Commit file, a/b/c and never change them. |
| 852 | mkdir -p a/b && |
| 853 | echo singleton >file && |
| 854 | echo stuff >a/b/c && |
| 855 | echo more >a/d && |
| 856 | git add file a && |
| 857 | git commit -m "single blobs" && |
| 858 | |
| 859 | # Files a/d and a/e will not be singletons. |
| 860 | echo d >a/d && |
| 861 | echo e >a/e && |
| 862 | git add a && |
| 863 | git commit -m "more blobs" && |
| 864 | |
| 865 | # This use of a sparse index helps to force |
| 866 | # test that the cache-tree is walked, too. |
| 867 | git sparse-checkout set --sparse-index a x && |
| 868 | |
| 869 | # Create staged changes: |
| 870 | # * a/e now has multiple versions. |
| 871 | # * a/i now has only one version. |
| 872 | echo f >a/d && |
| 873 | echo h >a/e && |
| 874 | echo i >a/i && |
| 875 | git add a && |
| 876 | |
| 877 | # Stage and unstage a change to make use of |
| 878 | # resolve-undo cache and how that impacts fsck. |
| 879 | mkdir x && |
| 880 | echo y >x/y && |
| 881 | git add x && |
| 882 | xy=$(git rev-parse :x/y) && |
| 883 | git rm --cached x/y && |
| 884 | |
| 885 | # The blob for x/y must persist through repacks, |
| 886 | # but fsck currently ignores the REUC extension |
| 887 | # for finding links to the blob. |
| 888 | cat >expect <<-EOF && |
| 889 | dangling blob $xy |
| 890 | EOF |
| 891 | |
| 892 | # Bring the loose objects into a packfile to avoid |
| 893 | # leftovers in next test. Without this, the loose |
| 894 | # objects persist and the test succeeds for other |
| 895 | # reasons. |
| 896 | git repack -adf && |
| 897 | git fsck >out && |
| 898 | test_cmp expect out && |
| 899 | |
| 900 | # Test path walk version with pack.useSparse. |
| 901 | git -c pack.useSparse=true repack -adf --path-walk && |
| 902 | git fsck >out && |
| 903 | test_cmp expect out |
| 904 | ) |
| 905 | ' |
| 906 | |
| 907 | test_done |