Git fork
at reftables-rust 704 lines 18 kB view raw
1#!/bin/sh 2# 3# Copyright (c) 2007 Junio C Hamano 4# 5 6test_description='Test prune and reflog expiration' 7GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 8export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 9 10. ./test-lib.sh 11 12check_have () { 13 gaah= && 14 for N in "$@" 15 do 16 eval "o=\$$N" && git cat-file -t $o || { 17 echo Gaah $N 18 gaah=$N 19 break 20 } 21 done && 22 test -z "$gaah" 23} 24 25check_fsck () { 26 git fsck --full >fsck.output 27 case "$1" in 28 '') 29 test_must_be_empty fsck.output ;; 30 *) 31 test_grep "$1" fsck.output ;; 32 esac 33} 34 35corrupt () { 36 mv .git/objects/$(test_oid_to_path $1) .git/$1 37} 38 39recover () { 40 aa=$(echo $1 | cut -c 1-2) 41 mkdir -p .git/objects/$aa 42 mv .git/$1 .git/objects/$(test_oid_to_path $1) 43} 44 45check_dont_have () { 46 gaah= && 47 for N in "$@" 48 do 49 eval "o=\$$N" 50 git cat-file -t $o && { 51 echo Gaah $N 52 gaah=$N 53 break 54 } 55 done 56 test -z "$gaah" 57} 58 59test_expect_success setup ' 60 mkdir -p A/B && 61 echo rat >C && 62 echo ox >A/D && 63 echo tiger >A/B/E && 64 git add . && 65 66 test_tick && git commit -m rabbit && 67 H=$(git rev-parse --verify HEAD) && 68 A=$(git rev-parse --verify HEAD:A) && 69 B=$(git rev-parse --verify HEAD:A/B) && 70 C=$(git rev-parse --verify HEAD:C) && 71 D=$(git rev-parse --verify HEAD:A/D) && 72 E=$(git rev-parse --verify HEAD:A/B/E) && 73 check_fsck && 74 75 test_chmod +x C && 76 git add C && 77 test_tick && git commit -m dragon && 78 L=$(git rev-parse --verify HEAD) && 79 check_fsck && 80 81 rm -f C A/B/E && 82 echo snake >F && 83 echo horse >A/G && 84 git add F A/G && 85 test_tick && git commit -a -m sheep && 86 F=$(git rev-parse --verify HEAD:F) && 87 G=$(git rev-parse --verify HEAD:A/G) && 88 I=$(git rev-parse --verify HEAD:A) && 89 J=$(git rev-parse --verify HEAD) && 90 check_fsck && 91 92 rm -f A/G && 93 test_tick && git commit -a -m monkey && 94 K=$(git rev-parse --verify HEAD) && 95 check_fsck && 96 97 check_have A B C D E F G H I J K L && 98 99 git prune && 100 101 check_have A B C D E F G H I J K L && 102 103 check_fsck && 104 105 git reflog refs/heads/main >output && 106 test_line_count = 4 output 107' 108 109test_expect_success 'correct usage on sub-command -h' ' 110 test_expect_code 129 git reflog expire -h >err && 111 grep "git reflog expire" err 112' 113 114test_expect_success 'correct usage on "git reflog show -h"' ' 115 test_expect_code 129 git reflog show -h >err && 116 grep -F "git reflog [show]" err 117' 118 119test_expect_success 'pass through -- to sub-command' ' 120 test_when_finished "rm -rf repo" && 121 git init repo && 122 test_commit -C repo message --a-file contents dash-tag && 123 124 git -C repo reflog show -- --does-not-exist >out && 125 test_must_be_empty out && 126 git -C repo reflog show >expect && 127 git -C repo reflog show -- --a-file >actual && 128 test_cmp expect actual 129' 130 131test_expect_success rewind ' 132 test_tick && git reset --hard HEAD~2 && 133 test -f C && 134 test -f A/B/E && 135 ! test -f F && 136 ! test -f A/G && 137 138 check_have A B C D E F G H I J K L && 139 140 git prune && 141 142 check_have A B C D E F G H I J K L && 143 144 git reflog refs/heads/main >output && 145 test_line_count = 5 output 146' 147 148test_expect_success 'reflog expire should not barf on an annotated tag' ' 149 test_when_finished "git tag -d v0.tag || :" && 150 git -c core.logAllRefUpdates=always \ 151 tag -a -m "tag name" v0.tag main && 152 git reflog expire --dry-run refs/tags/v0.tag 2>err && 153 test_grep ! "error: [Oo]bject .* not a commit" err 154' 155 156test_expect_success 'corrupt and check' ' 157 158 corrupt $F && 159 check_fsck "missing blob $F" 160 161' 162 163test_expect_success 'reflog expire --dry-run should not touch reflog' ' 164 165 git reflog expire --dry-run \ 166 --expire=$(($test_tick - 10000)) \ 167 --expire-unreachable=$(($test_tick - 10000)) \ 168 --stale-fix \ 169 --all && 170 171 git reflog refs/heads/main >output && 172 test_line_count = 5 output && 173 174 check_fsck "missing blob $F" 175' 176 177test_expect_success 'reflog expire' ' 178 179 git reflog expire --verbose \ 180 --expire=$(($test_tick - 10000)) \ 181 --expire-unreachable=$(($test_tick - 10000)) \ 182 --stale-fix \ 183 --all && 184 185 git reflog refs/heads/main >output && 186 test_line_count = 2 output && 187 188 check_fsck "dangling commit $K" 189' 190 191test_expect_success '--stale-fix handles missing objects generously' ' 192 git -c core.logAllRefUpdates=false fast-import --date-format=now <<-EOS && 193 commit refs/heads/stale-fix 194 mark :1 195 committer Author <a@uth.or> now 196 data <<EOF 197 start stale fix 198 EOF 199 M 100644 inline file 200 data <<EOF 201 contents 202 EOF 203 commit refs/heads/stale-fix 204 committer Author <a@uth.or> now 205 data <<EOF 206 stale fix branch tip 207 EOF 208 from :1 209 EOS 210 211 parent_oid=$(git rev-parse stale-fix^) && 212 test_when_finished "recover $parent_oid" && 213 corrupt $parent_oid && 214 git reflog expire --stale-fix 215' 216 217test_expect_success 'prune and fsck' ' 218 219 git prune && 220 check_fsck && 221 222 check_have A B C D E H L && 223 check_dont_have F G I J K 224 225' 226 227test_expect_success 'recover and check' ' 228 229 recover $F && 230 check_fsck "dangling blob $F" 231 232' 233 234test_expect_success 'delete' ' 235 echo 1 > C && 236 test_tick && 237 git commit -m rat C && 238 239 echo 2 > C && 240 test_tick && 241 git commit -m ox C && 242 243 echo 3 > C && 244 test_tick && 245 git commit -m tiger C && 246 247 HEAD_entry_count=$(git reflog | wc -l) && 248 main_entry_count=$(git reflog show main | wc -l) && 249 250 test $HEAD_entry_count = 5 && 251 test $main_entry_count = 5 && 252 253 254 git reflog delete main@{1} && 255 git reflog show main > output && 256 test_line_count = $(($main_entry_count - 1)) output && 257 test $HEAD_entry_count = $(git reflog | wc -l) && 258 ! grep ox < output && 259 260 main_entry_count=$(wc -l < output) && 261 262 git reflog delete HEAD@{1} && 263 test $(($HEAD_entry_count -1)) = $(git reflog | wc -l) && 264 test $main_entry_count = $(git reflog show main | wc -l) && 265 266 HEAD_entry_count=$(git reflog | wc -l) && 267 268 git reflog delete main@{07.04.2005.15:15:00.-0700} && 269 git reflog show main > output && 270 test_line_count = $(($main_entry_count - 1)) output && 271 ! grep dragon < output 272 273' 274 275test_expect_success 'rewind2' ' 276 277 test_tick && git reset --hard HEAD~2 && 278 git reflog refs/heads/main >output && 279 test_line_count = 4 output 280' 281 282test_expect_success '--expire=never' ' 283 284 git reflog expire --verbose \ 285 --expire=never \ 286 --expire-unreachable=never \ 287 --all && 288 git reflog refs/heads/main >output && 289 test_line_count = 4 output 290' 291 292test_expect_success 'gc.reflogexpire=never' ' 293 test_config gc.reflogexpire never && 294 test_config gc.reflogexpireunreachable never && 295 296 git reflog expire --verbose --all >output && 297 test_line_count = 9 output && 298 299 git reflog refs/heads/main >output && 300 test_line_count = 4 output 301' 302 303test_expect_success 'gc.reflogexpire=false' ' 304 test_config gc.reflogexpire false && 305 test_config gc.reflogexpireunreachable false && 306 307 git reflog expire --verbose --all && 308 git reflog refs/heads/main >output && 309 test_line_count = 4 output 310 311' 312 313test_expect_success 'git reflog expire unknown reference' ' 314 test_config gc.reflogexpire never && 315 test_config gc.reflogexpireunreachable never && 316 317 test_must_fail git reflog expire main@{123} 2>stderr && 318 test_grep "error: reflog could not be found: ${SQ}main@{123}${SQ}" stderr && 319 test_must_fail git reflog expire does-not-exist 2>stderr && 320 test_grep "error: reflog could not be found: ${SQ}does-not-exist${SQ}" stderr 321' 322 323test_expect_success 'checkout should not delete log for packed ref' ' 324 test $(git reflog main | wc -l) = 4 && 325 git branch foo && 326 git pack-refs --all && 327 git checkout foo && 328 test $(git reflog main | wc -l) = 4 329' 330 331test_expect_success 'stale dirs do not cause d/f conflicts (reflogs on)' ' 332 test_when_finished "git branch -d one || git branch -d one/two" && 333 334 git branch one/two main && 335 echo "one/two@{0} branch: Created from main" >expect && 336 git log -g --format="%gd %gs" one/two >actual && 337 test_cmp expect actual && 338 git branch -d one/two && 339 340 # now logs/refs/heads/one is a stale directory, but 341 # we should move it out of the way to create "one" reflog 342 git branch one main && 343 echo "one@{0} branch: Created from main" >expect && 344 git log -g --format="%gd %gs" one >actual && 345 test_cmp expect actual 346' 347 348test_expect_success 'stale dirs do not cause d/f conflicts (reflogs off)' ' 349 test_when_finished "git branch -d one || git branch -d one/two" && 350 351 git branch one/two main && 352 echo "one/two@{0} branch: Created from main" >expect && 353 git log -g --format="%gd %gs" one/two >actual && 354 test_cmp expect actual && 355 git branch -d one/two && 356 357 # same as before, but we only create a reflog for "one" if 358 # it already exists, which it does not 359 git -c core.logallrefupdates=false branch one main && 360 git log -g --format="%gd %gs" one >actual && 361 test_must_be_empty actual 362' 363 364test_expect_success 'no segfaults for reflog containing non-commit sha1s' ' 365 git update-ref --create-reflog -m "Creating ref" \ 366 refs/tests/tree-in-reflog HEAD && 367 git update-ref -m "Forcing tree" refs/tests/tree-in-reflog HEAD^{tree} && 368 git update-ref -m "Restoring to commit" refs/tests/tree-in-reflog HEAD && 369 git reflog refs/tests/tree-in-reflog 370' 371 372test_expect_failure 'reflog with non-commit entries displays all entries' ' 373 git reflog refs/tests/tree-in-reflog >actual && 374 test_line_count = 3 actual 375' 376 377test_expect_success 'continue walking past root commits' ' 378 git init orphanage && 379 ( 380 cd orphanage && 381 cat >expect <<-\EOF && 382 HEAD@{0} commit (initial): orphan2-1 383 HEAD@{1} commit: orphan1-2 384 HEAD@{2} commit (initial): orphan1-1 385 HEAD@{3} commit (initial): initial 386 EOF 387 test_commit initial && 388 git checkout --orphan orphan1 && 389 test_commit orphan1-1 && 390 test_commit orphan1-2 && 391 git checkout --orphan orphan2 && 392 test_commit orphan2-1 && 393 git log -g --format="%gd %gs" >actual && 394 test_cmp expect actual 395 ) 396' 397 398test_expect_success 'expire with multiple worktrees' ' 399 git init main-wt && 400 ( 401 cd main-wt && 402 test_tick && 403 test_commit foo && 404 git worktree add link-wt && 405 test_tick && 406 test_commit -C link-wt foobar && 407 test_tick && 408 git reflog expire --verbose --all --expire=$test_tick && 409 test-tool ref-store worktree:link-wt for-each-reflog-ent HEAD >actual && 410 test_must_be_empty actual 411 ) 412' 413 414test_expect_success 'expire one of multiple worktrees' ' 415 git init main-wt2 && 416 ( 417 cd main-wt2 && 418 test_tick && 419 test_commit foo && 420 git worktree add link-wt && 421 test_tick && 422 test_commit -C link-wt foobar && 423 test_tick && 424 test-tool ref-store worktree:link-wt for-each-reflog-ent HEAD \ 425 >expect-link-wt && 426 git reflog expire --verbose --all --expire=$test_tick \ 427 --single-worktree && 428 test-tool ref-store worktree:main for-each-reflog-ent HEAD \ 429 >actual-main && 430 test-tool ref-store worktree:link-wt for-each-reflog-ent HEAD \ 431 >actual-link-wt && 432 test_must_be_empty actual-main && 433 test_cmp expect-link-wt actual-link-wt 434 ) 435' 436 437test_expect_success 'empty reflog' ' 438 test_when_finished "rm -rf empty" && 439 git init empty && 440 test_commit -C empty A && 441 test-tool ref-store main create-reflog refs/heads/foo && 442 git -C empty reflog expire --all 2>err && 443 test_must_be_empty err 444' 445 446test_expect_success 'list reflogs' ' 447 test_when_finished "rm -rf repo" && 448 git init repo && 449 ( 450 cd repo && 451 git reflog list >actual && 452 test_must_be_empty actual && 453 454 test_commit A && 455 cat >expect <<-EOF && 456 HEAD 457 refs/heads/main 458 EOF 459 git reflog list >actual && 460 test_cmp expect actual && 461 462 git branch b && 463 cat >expect <<-EOF && 464 HEAD 465 refs/heads/b 466 refs/heads/main 467 EOF 468 git reflog list >actual && 469 test_cmp expect actual 470 ) 471' 472 473test_expect_success 'list reflogs with worktree' ' 474 test_when_finished "rm -rf repo" && 475 git init repo && 476 ( 477 cd repo && 478 479 test_commit A && 480 git worktree add wt && 481 git -c core.logAllRefUpdates=always \ 482 update-ref refs/worktree/main HEAD && 483 git -c core.logAllRefUpdates=always \ 484 update-ref refs/worktree/per-worktree HEAD && 485 git -c core.logAllRefUpdates=always -C wt \ 486 update-ref refs/worktree/per-worktree HEAD && 487 git -c core.logAllRefUpdates=always -C wt \ 488 update-ref refs/worktree/worktree HEAD && 489 490 cat >expect <<-EOF && 491 HEAD 492 refs/heads/main 493 refs/heads/wt 494 refs/worktree/main 495 refs/worktree/per-worktree 496 EOF 497 git reflog list >actual && 498 test_cmp expect actual && 499 500 cat >expect <<-EOF && 501 HEAD 502 refs/heads/main 503 refs/heads/wt 504 refs/worktree/per-worktree 505 refs/worktree/worktree 506 EOF 507 git -C wt reflog list >actual && 508 test_cmp expect actual 509 ) 510' 511 512test_expect_success 'reflog list returns error with additional args' ' 513 cat >expect <<-EOF && 514 error: list does not accept arguments: ${SQ}bogus${SQ} 515 EOF 516 test_must_fail git reflog list bogus 2>err && 517 test_cmp expect err 518' 519 520test_expect_success 'reflog for symref with unborn target can be listed' ' 521 test_when_finished "rm -rf repo" && 522 git init repo && 523 ( 524 cd repo && 525 test_commit A && 526 git symbolic-ref HEAD refs/heads/unborn && 527 cat >expect <<-EOF && 528 HEAD 529 refs/heads/main 530 EOF 531 git reflog list >actual && 532 test_cmp expect actual 533 ) 534' 535 536test_expect_success 'reflog with invalid object ID can be listed' ' 537 test_when_finished "rm -rf repo" && 538 git init repo && 539 ( 540 cd repo && 541 test_commit A && 542 test-tool ref-store main update-ref msg refs/heads/missing \ 543 $(test_oid deadbeef) "$ZERO_OID" REF_SKIP_OID_VERIFICATION && 544 cat >expect <<-EOF && 545 HEAD 546 refs/heads/main 547 refs/heads/missing 548 EOF 549 git reflog list >actual && 550 test_cmp expect actual 551 ) 552' 553 554test_expect_success 'reflog drop non-existent ref' ' 555 test_when_finished "rm -rf repo" && 556 git init repo && 557 ( 558 cd repo && 559 test_must_fail git reflog exists refs/heads/non-existent && 560 test_must_fail git reflog drop refs/heads/non-existent 2>stderr && 561 test_grep "error: reflog could not be found: ${SQ}refs/heads/non-existent${SQ}" stderr 562 ) 563' 564 565test_expect_success 'reflog drop' ' 566 test_when_finished "rm -rf repo" && 567 git init repo && 568 ( 569 cd repo && 570 test_commit A && 571 test_commit_bulk --ref=refs/heads/branch 1 && 572 git reflog exists refs/heads/main && 573 git reflog exists refs/heads/branch && 574 git reflog drop refs/heads/main && 575 test_must_fail git reflog exists refs/heads/main && 576 git reflog exists refs/heads/branch 577 ) 578' 579 580test_expect_success 'reflog drop multiple references' ' 581 test_when_finished "rm -rf repo" && 582 git init repo && 583 ( 584 cd repo && 585 test_commit A && 586 test_commit_bulk --ref=refs/heads/branch 1 && 587 git reflog exists refs/heads/main && 588 git reflog exists refs/heads/branch && 589 git reflog drop refs/heads/main refs/heads/branch && 590 test_must_fail git reflog exists refs/heads/main && 591 test_must_fail git reflog exists refs/heads/branch 592 ) 593' 594 595test_expect_success 'reflog drop multiple references some non-existent' ' 596 test_when_finished "rm -rf repo" && 597 git init repo && 598 ( 599 cd repo && 600 test_commit A && 601 test_commit_bulk --ref=refs/heads/branch 1 && 602 git reflog exists refs/heads/main && 603 git reflog exists refs/heads/branch && 604 test_must_fail git reflog exists refs/heads/non-existent && 605 test_must_fail git reflog drop refs/heads/main refs/heads/non-existent refs/heads/branch 2>stderr && 606 test_must_fail git reflog exists refs/heads/main && 607 test_must_fail git reflog exists refs/heads/branch && 608 test_must_fail git reflog exists refs/heads/non-existent && 609 test_grep "error: reflog could not be found: ${SQ}refs/heads/non-existent${SQ}" stderr 610 ) 611' 612 613test_expect_success 'reflog drop --all' ' 614 test_when_finished "rm -rf repo" && 615 git init repo && 616 ( 617 cd repo && 618 test_commit A && 619 test_commit_bulk --ref=refs/heads/branch 1 && 620 git reflog exists refs/heads/main && 621 git reflog exists refs/heads/branch && 622 git reflog drop --all && 623 test_must_fail git reflog exists refs/heads/main && 624 test_must_fail git reflog exists refs/heads/branch 625 ) 626' 627 628test_expect_success 'reflog drop --all multiple worktrees' ' 629 test_when_finished "rm -rf repo" && 630 test_when_finished "rm -rf wt" && 631 git init repo && 632 ( 633 cd repo && 634 test_commit A && 635 git worktree add ../wt && 636 test_commit_bulk -C ../wt --ref=refs/heads/branch 1 && 637 git reflog exists refs/heads/main && 638 git reflog exists refs/heads/branch && 639 git reflog drop --all && 640 test_must_fail git reflog exists refs/heads/main && 641 test_must_fail git reflog exists refs/heads/branch 642 ) 643' 644 645test_expect_success 'reflog drop --all --single-worktree' ' 646 test_when_finished "rm -rf repo" && 647 test_when_finished "rm -rf wt" && 648 git init repo && 649 ( 650 cd repo && 651 test_commit A && 652 git worktree add ../wt && 653 test_commit -C ../wt foobar && 654 git reflog exists refs/heads/main && 655 git reflog exists refs/heads/wt && 656 test-tool ref-store worktree:wt reflog-exists HEAD && 657 git reflog drop --all --single-worktree && 658 test_must_fail git reflog exists refs/heads/main && 659 test_must_fail git reflog exists refs/heads/wt && 660 test_must_fail test-tool ref-store worktree:main reflog-exists HEAD && 661 test-tool ref-store worktree:wt reflog-exists HEAD 662 ) 663' 664 665test_expect_success 'reflog drop --all with reference' ' 666 test_when_finished "rm -rf repo" && 667 git init repo && 668 ( 669 cd repo && 670 test_commit A && 671 test_must_fail git reflog drop --all refs/heads/main 2>stderr && 672 test_grep "usage: references specified along with --all" stderr 673 ) 674' 675 676test_expect_success 'expire with pattern config' ' 677 # Split refs/heads/ into two roots so we can apply config to each. Make 678 # two branches per root to verify that config is applied correctly 679 # multiple times. 680 git branch root1/branch1 && 681 git branch root1/branch2 && 682 git branch root2/branch1 && 683 git branch root2/branch2 && 684 685 test_config "gc.reflogexpire" "never" && 686 test_config "gc.refs/heads/root2/*.reflogExpire" "now" && 687 git reflog expire \ 688 root1/branch1 root1/branch2 \ 689 root2/branch1 root2/branch2 && 690 691 cat >expect <<-\EOF && 692 root1/branch1@{0} 693 root1/branch2@{0} 694 EOF 695 git log -g --branches="root*" --format=%gD >actual.raw && 696 # The sole reflog entry of each branch points to the same commit, so 697 # the order in which they are shown is nondeterministic. We just care 698 # about the what was expired (and what was not), so sort to get a known 699 # order. 700 sort <actual.raw >actual.sorted && 701 test_cmp expect actual.sorted 702' 703 704test_done