Git fork
at reftables-rust 1138 lines 32 kB view raw
1#!/bin/sh 2# 3# Copyright (c) 2020 Google LLC 4# 5 6test_description='reftable basics' 7 8GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 9export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 10GIT_TEST_DEFAULT_REF_FORMAT=reftable 11export GIT_TEST_DEFAULT_REF_FORMAT 12 13. ./test-lib.sh 14 15INVALID_OID=$(test_oid 001) 16 17test_expect_success 'pack-refs does not crash with -h' ' 18 test_expect_code 129 git pack-refs -h >usage && 19 test_grep "[Uu]sage: git pack-refs " usage && 20 test_expect_code 129 nongit git pack-refs -h >usage && 21 test_grep "[Uu]sage: git pack-refs " usage 22' 23 24test_expect_success 'init: creates basic reftable structures' ' 25 test_when_finished "rm -rf repo" && 26 git init repo && 27 test_path_is_dir repo/.git/reftable && 28 test_path_is_file repo/.git/reftable/tables.list && 29 echo reftable >expect && 30 git -C repo rev-parse --show-ref-format >actual && 31 test_cmp expect actual 32' 33 34test_expect_success 'init: sha256 object format via environment variable' ' 35 test_when_finished "rm -rf repo" && 36 GIT_DEFAULT_HASH=sha256 git init repo && 37 cat >expect <<-EOF && 38 sha256 39 reftable 40 EOF 41 git -C repo rev-parse --show-object-format --show-ref-format >actual && 42 test_cmp expect actual 43' 44 45test_expect_success 'init: sha256 object format via option' ' 46 test_when_finished "rm -rf repo" && 47 git init --object-format=sha256 repo && 48 cat >expect <<-EOF && 49 sha256 50 reftable 51 EOF 52 git -C repo rev-parse --show-object-format --show-ref-format >actual && 53 test_cmp expect actual 54' 55 56test_expect_success 'init: reinitializing reftable backend succeeds' ' 57 test_when_finished "rm -rf repo" && 58 git init repo && 59 test_commit -C repo A && 60 61 git -C repo for-each-ref >expect && 62 git init --ref-format=reftable repo && 63 git -C repo for-each-ref >actual && 64 test_cmp expect actual 65' 66 67test_expect_success 'init: reinitializing files with reftable backend fails' ' 68 test_when_finished "rm -rf repo" && 69 git init --ref-format=files repo && 70 test_commit -C repo file && 71 72 cp repo/.git/HEAD expect && 73 test_must_fail git init --ref-format=reftable repo && 74 test_cmp expect repo/.git/HEAD 75' 76 77test_expect_success 'init: reinitializing reftable with files backend fails' ' 78 test_when_finished "rm -rf repo" && 79 git init --ref-format=reftable repo && 80 test_commit -C repo file && 81 82 cp repo/.git/HEAD expect && 83 test_must_fail git init --ref-format=files repo && 84 test_cmp expect repo/.git/HEAD 85' 86 87test_expect_perms () { 88 local perms="$1" && 89 local file="$2" && 90 local actual="$(ls -l "$file")" && 91 92 case "$actual" in 93 $perms*) 94 : happy 95 ;; 96 *) 97 echo "$(basename $2) is not $perms but $actual" 98 false 99 ;; 100 esac 101} 102 103test_expect_reftable_perms () { 104 local umask="$1" 105 local shared="$2" 106 local expect="$3" 107 108 test_expect_success POSIXPERM "init: honors --shared=$shared with umask $umask" ' 109 test_when_finished "rm -rf repo" && 110 ( 111 umask $umask && 112 git init --shared=$shared repo 113 ) && 114 test_expect_perms "$expect" repo/.git/reftable/tables.list && 115 for table in repo/.git/reftable/*.ref 116 do 117 test_expect_perms "$expect" "$table" || 118 return 1 119 done 120 ' 121 122 test_expect_success POSIXPERM "pack-refs: honors --shared=$shared with umask $umask" ' 123 test_when_finished "rm -rf repo" && 124 ( 125 umask $umask && 126 git init --shared=$shared repo && 127 test_commit -C repo A && 128 test_line_count = 2 repo/.git/reftable/tables.list && 129 git -C repo pack-refs 130 ) && 131 test_expect_perms "$expect" repo/.git/reftable/tables.list && 132 for table in repo/.git/reftable/*.ref 133 do 134 test_expect_perms "$expect" "$table" || 135 return 1 136 done 137 ' 138} 139 140test_expect_reftable_perms 002 umask "-rw-rw-r--" 141test_expect_reftable_perms 022 umask "-rw-r--r--" 142test_expect_reftable_perms 027 umask "-rw-r-----" 143 144test_expect_reftable_perms 002 group "-rw-rw-r--" 145test_expect_reftable_perms 022 group "-rw-rw-r--" 146test_expect_reftable_perms 027 group "-rw-rw----" 147 148test_expect_reftable_perms 002 world "-rw-rw-r--" 149test_expect_reftable_perms 022 world "-rw-rw-r--" 150test_expect_reftable_perms 027 world "-rw-rw-r--" 151 152test_expect_success 'clone: can clone reftable repository' ' 153 test_when_finished "rm -rf repo clone" && 154 git init repo && 155 test_commit -C repo message1 file1 && 156 157 git clone repo cloned && 158 echo reftable >expect && 159 git -C cloned rev-parse --show-ref-format >actual && 160 test_cmp expect actual && 161 test_path_is_file cloned/file1 162' 163 164test_expect_success 'clone: can clone reffiles into reftable repository' ' 165 test_when_finished "rm -rf reffiles reftable" && 166 git init --ref-format=files reffiles && 167 test_commit -C reffiles A && 168 git clone --ref-format=reftable ./reffiles reftable && 169 170 git -C reffiles rev-parse HEAD >expect && 171 git -C reftable rev-parse HEAD >actual && 172 test_cmp expect actual && 173 174 git -C reftable rev-parse --show-ref-format >actual && 175 echo reftable >expect && 176 test_cmp expect actual && 177 178 git -C reffiles rev-parse --show-ref-format >actual && 179 echo files >expect && 180 test_cmp expect actual 181' 182 183test_expect_success 'clone: can clone reftable into reffiles repository' ' 184 test_when_finished "rm -rf reffiles reftable" && 185 git init --ref-format=reftable reftable && 186 test_commit -C reftable A && 187 git clone --ref-format=files ./reftable reffiles && 188 189 git -C reftable rev-parse HEAD >expect && 190 git -C reffiles rev-parse HEAD >actual && 191 test_cmp expect actual && 192 193 git -C reftable rev-parse --show-ref-format >actual && 194 echo reftable >expect && 195 test_cmp expect actual && 196 197 git -C reffiles rev-parse --show-ref-format >actual && 198 echo files >expect && 199 test_cmp expect actual 200' 201 202test_expect_success 'ref transaction: corrupted tables cause failure' ' 203 test_when_finished "rm -rf repo" && 204 git init repo && 205 ( 206 cd repo && 207 test_commit file1 && 208 for f in .git/reftable/*.ref 209 do 210 : >"$f" || return 1 211 done && 212 test_must_fail git update-ref refs/heads/main HEAD 213 ) 214' 215 216test_expect_success 'ref transaction: corrupted tables.list cause failure' ' 217 test_when_finished "rm -rf repo" && 218 git init repo && 219 ( 220 cd repo && 221 test_commit file1 && 222 echo garbage >.git/reftable/tables.list && 223 test_must_fail git update-ref refs/heads/main HEAD 224 ) 225' 226 227test_expect_success 'ref transaction: refuses to write ref causing F/D conflict' ' 228 test_when_finished "rm -rf repo" && 229 git init repo && 230 test_commit -C repo file && 231 test_must_fail git -C repo update-ref refs/heads/main/forbidden 232' 233 234test_expect_success 'ref transaction: deleting ref with invalid name fails' ' 235 test_when_finished "rm -rf repo" && 236 git init repo && 237 test_commit -C repo file && 238 test_must_fail git -C repo update-ref -d ../../my-private-file 239' 240 241test_expect_success 'ref transaction: can skip object ID verification' ' 242 test_when_finished "rm -rf repo" && 243 git init repo && 244 test_must_fail test-tool -C repo ref-store main update-ref msg refs/heads/branch $INVALID_OID $ZERO_OID 0 && 245 test-tool -C repo ref-store main update-ref msg refs/heads/branch $INVALID_OID $ZERO_OID REF_SKIP_OID_VERIFICATION 246' 247 248test_expect_success 'ref transaction: updating same ref multiple times fails' ' 249 test_when_finished "rm -rf repo" && 250 git init repo && 251 test_commit -C repo A && 252 cat >updates <<-EOF && 253 update refs/heads/main $A 254 update refs/heads/main $A 255 EOF 256 cat >expect <<-EOF && 257 fatal: multiple updates for ref ${SQ}refs/heads/main${SQ} not allowed 258 EOF 259 test_must_fail git -C repo update-ref --stdin <updates 2>err && 260 test_cmp expect err 261' 262 263test_expect_success 'ref transaction: can delete symbolic self-reference with git-symbolic-ref(1)' ' 264 test_when_finished "rm -rf repo" && 265 git init repo && 266 git -C repo symbolic-ref refs/heads/self refs/heads/self && 267 git -C repo symbolic-ref -d refs/heads/self 268' 269 270test_expect_success 'ref transaction: deleting symbolic self-reference without --no-deref fails' ' 271 test_when_finished "rm -rf repo" && 272 git init repo && 273 git -C repo symbolic-ref refs/heads/self refs/heads/self && 274 cat >expect <<-EOF && 275 error: multiple updates for ${SQ}refs/heads/self${SQ} (including one via symref ${SQ}refs/heads/self${SQ}) are not allowed 276 EOF 277 test_must_fail git -C repo update-ref -d refs/heads/self 2>err && 278 test_cmp expect err 279' 280 281test_expect_success 'ref transaction: deleting symbolic self-reference with --no-deref succeeds' ' 282 test_when_finished "rm -rf repo" && 283 git init repo && 284 git -C repo symbolic-ref refs/heads/self refs/heads/self && 285 git -C repo update-ref -d --no-deref refs/heads/self 286' 287 288test_expect_success 'ref transaction: creating symbolic ref fails with F/D conflict' ' 289 test_when_finished "rm -rf repo" && 290 git init repo && 291 test_commit -C repo A && 292 cat >expect <<-EOF && 293 error: ${SQ}refs/heads/main${SQ} exists; cannot create ${SQ}refs/heads${SQ} 294 EOF 295 test_must_fail git -C repo symbolic-ref refs/heads refs/heads/foo 2>err && 296 test_cmp expect err 297' 298 299test_expect_success 'ref transaction: ref deletion' ' 300 test_when_finished "rm -rf repo" && 301 git init repo && 302 ( 303 cd repo && 304 test_commit file && 305 HEAD_OID=$(git show-ref -s --verify HEAD) && 306 cat >expect <<-EOF && 307 $HEAD_OID refs/heads/main 308 $HEAD_OID refs/tags/file 309 EOF 310 git show-ref >actual && 311 test_cmp expect actual && 312 313 test_must_fail git update-ref -d refs/tags/file $INVALID_OID && 314 git show-ref >actual && 315 test_cmp expect actual && 316 317 git update-ref -d refs/tags/file $HEAD_OID && 318 echo "$HEAD_OID refs/heads/main" >expect && 319 git show-ref >actual && 320 test_cmp expect actual 321 ) 322' 323 324test_expect_success 'ref transaction: writes cause auto-compaction' ' 325 test_when_finished "rm -rf repo" && 326 327 git init repo && 328 test_line_count = 1 repo/.git/reftable/tables.list && 329 330 test_commit -C repo --no-tag A && 331 test_line_count = 1 repo/.git/reftable/tables.list && 332 333 test_commit -C repo --no-tag B && 334 test_line_count = 1 repo/.git/reftable/tables.list 335' 336 337test_expect_success 'ref transaction: env var disables compaction' ' 338 test_when_finished "rm -rf repo" && 339 340 git init repo && 341 test_commit -C repo A && 342 343 start=$(wc -l <repo/.git/reftable/tables.list) && 344 iterations=5 && 345 expected=$((start + iterations)) && 346 347 for i in $(test_seq $iterations) 348 do 349 GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ 350 git -C repo update-ref branch-$i HEAD || return 1 351 done && 352 test_line_count = $expected repo/.git/reftable/tables.list && 353 354 git -C repo update-ref foo HEAD && 355 test_line_count -lt $expected repo/.git/reftable/tables.list 356' 357 358test_expect_success 'ref transaction: alternating table sizes are compacted' ' 359 test_when_finished "rm -rf repo" && 360 361 git init repo && 362 test_commit -C repo A && 363 for i in $(test_seq 5) 364 do 365 git -C repo branch -f foo && 366 git -C repo branch -d foo || return 1 367 done && 368 test_line_count = 2 repo/.git/reftable/tables.list 369' 370 371check_fsync_events () { 372 local trace="$1" && 373 shift && 374 375 cat >expect && 376 sed -n \ 377 -e '/^{"event":"counter",.*"category":"fsync",/ { 378 s/.*"category":"fsync",//; 379 s/}$//; 380 p; 381 }' \ 382 <"$trace" >actual && 383 test_cmp expect actual 384} 385 386test_expect_success 'ref transaction: writes are synced' ' 387 test_when_finished "rm -rf repo" && 388 git init repo && 389 test_commit -C repo initial && 390 391 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ 392 GIT_TEST_FSYNC=true \ 393 git -C repo -c core.fsync=reference \ 394 -c core.fsyncMethod=fsync update-ref refs/heads/branch HEAD && 395 check_fsync_events trace2.txt <<-EOF 396 "name":"hardware-flush","count":4 397 EOF 398' 399 400test_expect_success 'ref transaction: empty transaction in empty repo' ' 401 test_when_finished "rm -rf repo" && 402 git init repo && 403 test_commit -C repo --no-tag A && 404 git -C repo update-ref -d refs/heads/main && 405 test-tool -C repo ref-store main delete-refs REF_NO_DEREF msg HEAD && 406 git -C repo update-ref --stdin <<-EOF 407 prepare 408 commit 409 EOF 410' 411 412test_expect_success 'ref transaction: fails gracefully when auto compaction fails' ' 413 test_when_finished "rm -rf repo" && 414 git init repo && 415 ( 416 cd repo && 417 418 test_commit A && 419 for i in $(test_seq 10) 420 do 421 git branch branch-$i && 422 for table in .git/reftable/*.ref 423 do 424 touch "$table.lock" || exit 1 425 done || 426 exit 1 427 done && 428 test_line_count = 10 .git/reftable/tables.list 429 ) 430' 431 432test_expect_success 'ref transaction: timeout acquiring tables.list lock' ' 433 test_when_finished "rm -rf repo" && 434 git init repo && 435 ( 436 cd repo && 437 test_commit initial && 438 >.git/reftable/tables.list.lock && 439 test_must_fail git update-ref refs/heads/branch HEAD 2>err && 440 test_grep "cannot lock references" err 441 ) 442' 443 444test_expect_success 'ref transaction: retry acquiring tables.list lock' ' 445 test_when_finished "rm -rf repo" && 446 git init repo && 447 ( 448 cd repo && 449 test_commit initial && 450 LOCK=.git/reftable/tables.list.lock && 451 >$LOCK && 452 { 453 ( sleep 1 && rm -f $LOCK ) & 454 } && 455 git -c reftable.lockTimeout=5000 update-ref refs/heads/branch HEAD 456 ) 457' 458 459# This test fails most of the time on Cygwin systems. The root cause is 460# that Windows does not allow us to rename the "tables.list.lock" file into 461# place when "tables.list" is open for reading by a concurrent process. We have 462# worked around that in our MinGW-based rename emulation, but the Cygwin 463# emulation seems to be insufficient. 464test_expect_success !CYGWIN 'ref transaction: many concurrent writers' ' 465 test_when_finished "rm -rf repo" && 466 git init repo && 467 ( 468 cd repo && 469 # Set a high timeout. While a couple of seconds should be 470 # plenty, using the address sanitizer will significantly slow 471 # us down here. So we are aiming way higher than you would ever 472 # think is necessary just to keep us from flaking. We could 473 # also lock indefinitely by passing -1, but that could 474 # potentially block CI jobs indefinitely if there was a bug 475 # here. 476 git config set reftable.lockTimeout 300000 && 477 test_commit --no-tag initial && 478 479 head=$(git rev-parse HEAD) && 480 test_seq -f "$head commit\trefs/heads/branch-%d" 100 >expect && 481 printf "%s commit\trefs/heads/main\n" "$head" >>expect && 482 483 for i in $(test_seq 100) 484 do 485 { git update-ref refs/heads/branch-$i HEAD& } || 486 return 1 487 done && 488 489 wait && 490 git for-each-ref --sort=v:refname >actual && 491 test_cmp expect actual 492 ) 493' 494 495test_expect_success 'pack-refs: compacts tables' ' 496 test_when_finished "rm -rf repo" && 497 git init repo && 498 499 test_commit -C repo A && 500 ls -1 repo/.git/reftable >table-files && 501 test_line_count = 3 table-files && 502 test_line_count = 2 repo/.git/reftable/tables.list && 503 504 git -C repo pack-refs && 505 ls -1 repo/.git/reftable >table-files && 506 test_line_count = 2 table-files && 507 test_line_count = 1 repo/.git/reftable/tables.list 508' 509 510test_expect_success 'pack-refs: compaction raises locking errors' ' 511 test_when_finished "rm -rf repo" && 512 git init repo && 513 test_commit -C repo A && 514 touch repo/.git/reftable/tables.list.lock && 515 cat >expect <<-EOF && 516 error: unable to compact stack: data is locked 517 EOF 518 test_must_fail git -C repo pack-refs 2>err && 519 test_cmp expect err 520' 521 522for command in pack-refs gc "maintenance run --task=pack-refs" 523do 524test_expect_success "$command: auto compaction" ' 525 test_when_finished "rm -rf repo" && 526 git init repo && 527 ( 528 cd repo && 529 530 test_commit A && 531 532 # We need a bit of setup to ensure that git-gc(1) actually 533 # triggers, and that it does not write anything to the refdb. 534 git config gc.auto 1 && 535 git config gc.autoDetach 0 && 536 git config gc.reflogExpire never && 537 git config gc.reflogExpireUnreachable never && 538 test_oid blob17_1 | git hash-object -w --stdin && 539 540 # The tables should have been auto-compacted, and thus auto 541 # compaction should not have to do anything. 542 ls -1 .git/reftable >tables-expect && 543 test_line_count = 3 tables-expect && 544 git $command --auto && 545 ls -1 .git/reftable >tables-actual && 546 test_cmp tables-expect tables-actual && 547 548 test_oid blob17_2 | git hash-object -w --stdin && 549 550 # Lock all tables, write some refs. Auto-compaction will be 551 # unable to compact tables and thus fails gracefully, 552 # compacting only those tables which are not locked. 553 ls .git/reftable/*.ref | sort | 554 while read table 555 do 556 touch "$table.lock" && 557 basename "$table" >>tables.expect || exit 1 558 done && 559 test_line_count = 2 .git/reftable/tables.list && 560 git branch B && 561 git branch C && 562 563 # The new tables are auto-compacted, but the locked tables are 564 # left intact. 565 test_line_count = 3 .git/reftable/tables.list && 566 head -n 2 .git/reftable/tables.list >tables.head && 567 test_cmp tables.expect tables.head && 568 569 rm .git/reftable/*.lock && 570 git $command --auto && 571 test_line_count = 1 .git/reftable/tables.list 572 ) 573' 574done 575 576test_expect_success 'pack-refs: prunes stale tables' ' 577 test_when_finished "rm -rf repo" && 578 git init repo && 579 touch repo/.git/reftable/stale-table.ref && 580 git -C repo pack-refs && 581 test_path_is_missing repo/.git/reftable/stable-ref.ref 582' 583 584test_expect_success 'pack-refs: does not prune non-table files' ' 585 test_when_finished "rm -rf repo" && 586 git init repo && 587 touch repo/.git/reftable/garbage && 588 git -C repo pack-refs && 589 test_path_is_file repo/.git/reftable/garbage 590' 591 592test_expect_success 'packed-refs: writes are synced' ' 593 test_when_finished "rm -rf repo" && 594 git init repo && 595 test_commit -C repo initial && 596 test_line_count = 2 table-files && 597 598 : >trace2.txt && 599 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ 600 GIT_TEST_FSYNC=true \ 601 git -C repo -c core.fsync=reference \ 602 -c core.fsyncMethod=fsync pack-refs && 603 check_fsync_events trace2.txt <<-EOF 604 "name":"hardware-flush","count":2 605 EOF 606' 607 608test_expect_success 'ref iterator: bogus names are flagged' ' 609 test_when_finished "rm -rf repo" && 610 git init repo && 611 ( 612 cd repo && 613 test_commit --no-tag file && 614 test-tool ref-store main update-ref msg "refs/heads/bogus..name" $(git rev-parse HEAD) $ZERO_OID REF_SKIP_REFNAME_VERIFICATION && 615 616 cat >expect <<-EOF && 617 $ZERO_OID refs/heads/bogus..name 0xc 618 $(git rev-parse HEAD) refs/heads/main 0x0 619 EOF 620 test-tool ref-store main for-each-ref "" >actual && 621 test_cmp expect actual 622 ) 623' 624 625test_expect_success 'ref iterator: missing object IDs are not flagged' ' 626 test_when_finished "rm -rf repo" && 627 git init repo && 628 ( 629 cd repo && 630 test-tool ref-store main update-ref msg "refs/heads/broken-hash" $INVALID_OID $ZERO_OID REF_SKIP_OID_VERIFICATION && 631 632 cat >expect <<-EOF && 633 $INVALID_OID refs/heads/broken-hash 0x0 634 EOF 635 test-tool ref-store main for-each-ref "" >actual && 636 test_cmp expect actual 637 ) 638' 639 640test_expect_success 'basic: commit and list refs' ' 641 test_when_finished "rm -rf repo" && 642 git init repo && 643 test_commit -C repo file && 644 test_write_lines refs/heads/main refs/tags/file >expect && 645 git -C repo for-each-ref --format="%(refname)" >actual && 646 test_cmp actual expect 647' 648 649test_expect_success 'basic: can write large commit message' ' 650 test_when_finished "rm -rf repo" && 651 git init repo && 652 653 awk "BEGIN { for (i = 0; i < 50000; i++) printf \"%s\", \"this is a long commit message\" }" >commit-msg && 654 git -C repo commit --allow-empty --file=../commit-msg 655' 656 657test_expect_success 'basic: show-ref fails with empty repository' ' 658 test_when_finished "rm -rf repo" && 659 git init repo && 660 test_must_fail git -C repo show-ref >actual && 661 test_must_be_empty actual 662' 663 664test_expect_success 'basic: can check out unborn branch' ' 665 test_when_finished "rm -rf repo" && 666 git init repo && 667 git -C repo checkout -b main 668' 669 670test_expect_success 'basic: peeled tags are stored' ' 671 test_when_finished "rm -rf repo" && 672 git init repo && 673 test_commit -C repo file && 674 git -C repo tag -m "annotated tag" test_tag HEAD && 675 for ref in refs/heads/main refs/tags/file refs/tags/test_tag refs/tags/test_tag^{} 676 do 677 echo "$(git -C repo rev-parse "$ref") $ref" || return 1 678 done >expect && 679 git -C repo show-ref -d >actual && 680 test_cmp expect actual 681' 682 683test_expect_success 'basic: for-each-ref can print symrefs' ' 684 test_when_finished "rm -rf repo" && 685 git init repo && 686 ( 687 cd repo && 688 test_commit file && 689 git branch && 690 git symbolic-ref refs/heads/sym refs/heads/main && 691 cat >expected <<-EOF && 692 refs/heads/main 693 EOF 694 git for-each-ref --format="%(symref)" refs/heads/sym >actual && 695 test_cmp expected actual 696 ) 697' 698 699test_expect_success 'basic: notes' ' 700 test_when_finished "rm -rf repo" && 701 git init repo && 702 ( 703 write_script fake_editor <<-\EOF && 704 echo "$MSG" >"$1" 705 echo "$MSG" >&2 706 EOF 707 708 test_commit 1st && 709 test_commit 2nd && 710 GIT_EDITOR=./fake_editor MSG=b4 git notes add && 711 GIT_EDITOR=./fake_editor MSG=b3 git notes edit && 712 echo b4 >expect && 713 git notes --ref commits@{1} show >actual && 714 test_cmp expect actual 715 ) 716' 717 718test_expect_success 'basic: stash' ' 719 test_when_finished "rm -rf repo" && 720 git init repo && 721 ( 722 cd repo && 723 test_commit file && 724 git stash list >expect && 725 test_line_count = 0 expect && 726 727 echo hoi >>file.t && 728 git stash push -m stashed && 729 git stash list >expect && 730 test_line_count = 1 expect && 731 732 git stash clear && 733 git stash list >expect && 734 test_line_count = 0 expect 735 ) 736' 737 738test_expect_success 'basic: cherry-pick' ' 739 test_when_finished "rm -rf repo" && 740 git init repo && 741 ( 742 cd repo && 743 test_commit message1 file1 && 744 test_commit message2 file2 && 745 git branch source && 746 git checkout HEAD^ && 747 test_commit message3 file3 && 748 git cherry-pick source && 749 test_path_is_file file2 750 ) 751' 752 753test_expect_success 'basic: rebase' ' 754 test_when_finished "rm -rf repo" && 755 git init repo && 756 ( 757 cd repo && 758 test_commit message1 file1 && 759 test_commit message2 file2 && 760 git branch source && 761 git checkout HEAD^ && 762 test_commit message3 file3 && 763 git rebase source && 764 test_path_is_file file2 765 ) 766' 767 768test_expect_success 'reflog: can delete separate reflog entries' ' 769 test_when_finished "rm -rf repo" && 770 git init repo && 771 ( 772 cd repo && 773 774 test_commit file && 775 test_commit file2 && 776 test_commit file3 && 777 test_commit file4 && 778 git reflog >actual && 779 grep file3 actual && 780 781 git reflog delete HEAD@{1} && 782 git reflog >actual && 783 ! grep file3 actual 784 ) 785' 786 787test_expect_success 'reflog: can switch to previous branch' ' 788 test_when_finished "rm -rf repo" && 789 git init repo && 790 ( 791 cd repo && 792 test_commit file1 && 793 git checkout -b branch1 && 794 test_commit file2 && 795 git checkout -b branch2 && 796 git switch - && 797 git rev-parse --symbolic-full-name HEAD >actual && 798 echo refs/heads/branch1 >expect && 799 test_cmp actual expect 800 ) 801' 802 803test_expect_success 'reflog: copying branch writes reflog entry' ' 804 test_when_finished "rm -rf repo" && 805 git init repo && 806 ( 807 cd repo && 808 test_commit file1 && 809 test_commit file2 && 810 oid=$(git rev-parse --short HEAD) && 811 git branch src && 812 cat >expect <<-EOF && 813 ${oid} dst@{0}: Branch: copied refs/heads/src to refs/heads/dst 814 ${oid} dst@{1}: branch: Created from main 815 EOF 816 git branch -c src dst && 817 git reflog dst >actual && 818 test_cmp expect actual 819 ) 820' 821 822test_expect_success 'reflog: renaming branch writes reflog entry' ' 823 test_when_finished "rm -rf repo" && 824 git init repo && 825 ( 826 cd repo && 827 git symbolic-ref HEAD refs/heads/before && 828 test_commit file && 829 git show-ref >expected.refs && 830 sed s/before/after/g <expected.refs >expected && 831 git branch -M after && 832 git show-ref >actual && 833 test_cmp expected actual && 834 echo refs/heads/after >expected && 835 git symbolic-ref HEAD >actual && 836 test_cmp expected actual 837 ) 838' 839 840test_expect_success 'reflog: can store empty logs' ' 841 test_when_finished "rm -rf repo" && 842 git init repo && 843 ( 844 cd repo && 845 846 test_must_fail test-tool ref-store main reflog-exists refs/heads/branch && 847 test-tool ref-store main create-reflog refs/heads/branch && 848 test-tool ref-store main reflog-exists refs/heads/branch && 849 test-tool ref-store main for-each-reflog-ent-reverse refs/heads/branch >actual && 850 test_must_be_empty actual 851 ) 852' 853 854test_expect_success 'reflog: expiry empties reflog' ' 855 test_when_finished "rm -rf repo" && 856 git init repo && 857 ( 858 cd repo && 859 860 test_commit initial && 861 git checkout -b branch && 862 test_commit fileA && 863 test_commit fileB && 864 865 cat >expect <<-EOF && 866 commit: fileB 867 commit: fileA 868 branch: Created from HEAD 869 EOF 870 git reflog show --format="%gs" refs/heads/branch >actual && 871 test_cmp expect actual && 872 873 git reflog expire branch --expire=all && 874 git reflog show --format="%gs" refs/heads/branch >actual && 875 test_must_be_empty actual && 876 test-tool ref-store main reflog-exists refs/heads/branch 877 ) 878' 879 880test_expect_success 'reflog: can be deleted' ' 881 test_when_finished "rm -rf repo" && 882 git init repo && 883 ( 884 cd repo && 885 test_commit initial && 886 test-tool ref-store main reflog-exists refs/heads/main && 887 test-tool ref-store main delete-reflog refs/heads/main && 888 test_must_fail test-tool ref-store main reflog-exists refs/heads/main 889 ) 890' 891 892test_expect_success 'reflog: garbage collection deletes reflog entries' ' 893 test_when_finished "rm -rf repo" && 894 git init repo && 895 ( 896 cd repo && 897 898 for count in $(test_seq 1 10) 899 do 900 test_commit "number $count" file.t $count number-$count || 901 return 1 902 done && 903 git reflog refs/heads/main >actual && 904 test_line_count = 10 actual && 905 grep "commit (initial): number 1" actual && 906 grep "commit: number 10" actual && 907 908 git gc && 909 git reflog refs/heads/main >actual && 910 test_line_count = 0 actual 911 ) 912' 913 914test_expect_success 'reflog: updates via HEAD update HEAD reflog' ' 915 test_when_finished "rm -rf repo" && 916 git init repo && 917 ( 918 cd repo && 919 test_commit main-one && 920 git checkout -b new-branch && 921 test_commit new-one && 922 test_commit new-two && 923 924 echo new-one >expect && 925 git log -1 --format=%s HEAD@{1} >actual && 926 test_cmp expect actual 927 ) 928' 929 930test_expect_success 'branch: copying branch with D/F conflict' ' 931 test_when_finished "rm -rf repo" && 932 git init repo && 933 ( 934 cd repo && 935 test_commit A && 936 git branch branch && 937 cat >expect <<-EOF && 938 error: ${SQ}refs/heads/branch${SQ} exists; cannot create ${SQ}refs/heads/branch/moved${SQ} 939 fatal: branch copy failed 940 EOF 941 test_must_fail git branch -c branch branch/moved 2>err && 942 test_cmp expect err 943 ) 944' 945 946test_expect_success 'branch: moving branch with D/F conflict' ' 947 test_when_finished "rm -rf repo" && 948 git init repo && 949 ( 950 cd repo && 951 test_commit A && 952 git branch branch && 953 git branch conflict && 954 cat >expect <<-EOF && 955 error: ${SQ}refs/heads/conflict${SQ} exists; cannot create ${SQ}refs/heads/conflict/moved${SQ} 956 fatal: branch rename failed 957 EOF 958 test_must_fail git branch -m branch conflict/moved 2>err && 959 test_cmp expect err 960 ) 961' 962 963test_expect_success 'worktree: adding worktree creates separate stack' ' 964 test_when_finished "rm -rf repo worktree" && 965 git init repo && 966 test_commit -C repo A && 967 968 git -C repo worktree add ../worktree && 969 test_path_is_file repo/.git/worktrees/worktree/refs/heads && 970 echo "ref: refs/heads/.invalid" >expect && 971 test_cmp expect repo/.git/worktrees/worktree/HEAD && 972 test_path_is_dir repo/.git/worktrees/worktree/reftable && 973 test_path_is_file repo/.git/worktrees/worktree/reftable/tables.list 974' 975 976test_expect_success 'worktree: pack-refs in main repo packs main refs' ' 977 test_when_finished "rm -rf repo worktree" && 978 git init repo && 979 test_commit -C repo A && 980 981 GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ 982 git -C repo worktree add ../worktree && 983 GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ 984 git -C worktree update-ref refs/worktree/per-worktree HEAD && 985 986 test_line_count = 4 repo/.git/worktrees/worktree/reftable/tables.list && 987 test_line_count = 3 repo/.git/reftable/tables.list && 988 git -C repo pack-refs && 989 test_line_count = 4 repo/.git/worktrees/worktree/reftable/tables.list && 990 test_line_count = 1 repo/.git/reftable/tables.list 991' 992 993test_expect_success 'worktree: pack-refs in worktree packs worktree refs' ' 994 test_when_finished "rm -rf repo worktree" && 995 git init repo && 996 test_commit -C repo A && 997 998 GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ 999 git -C repo worktree add ../worktree && 1000 GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ 1001 git -C worktree update-ref refs/worktree/per-worktree HEAD && 1002 1003 test_line_count = 4 repo/.git/worktrees/worktree/reftable/tables.list && 1004 test_line_count = 3 repo/.git/reftable/tables.list && 1005 git -C worktree pack-refs && 1006 test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && 1007 test_line_count = 3 repo/.git/reftable/tables.list 1008' 1009 1010test_expect_success 'worktree: creating shared ref updates main stack' ' 1011 test_when_finished "rm -rf repo worktree" && 1012 git init repo && 1013 test_commit -C repo A && 1014 1015 git -C repo worktree add ../worktree && 1016 git -C repo pack-refs && 1017 git -C worktree pack-refs && 1018 test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && 1019 test_line_count = 1 repo/.git/reftable/tables.list && 1020 1021 GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ 1022 git -C worktree update-ref refs/heads/shared HEAD && 1023 test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && 1024 test_line_count = 2 repo/.git/reftable/tables.list 1025' 1026 1027test_expect_success 'worktree: creating per-worktree ref updates worktree stack' ' 1028 test_when_finished "rm -rf repo worktree" && 1029 git init repo && 1030 test_commit -C repo A && 1031 1032 git -C repo worktree add ../worktree && 1033 git -C repo pack-refs && 1034 git -C worktree pack-refs && 1035 test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && 1036 test_line_count = 1 repo/.git/reftable/tables.list && 1037 1038 git -C worktree update-ref refs/bisect/per-worktree HEAD && 1039 test_line_count = 2 repo/.git/worktrees/worktree/reftable/tables.list && 1040 test_line_count = 1 repo/.git/reftable/tables.list 1041' 1042 1043test_expect_success 'worktree: creating per-worktree ref from main repo' ' 1044 test_when_finished "rm -rf repo worktree" && 1045 git init repo && 1046 test_commit -C repo A && 1047 1048 git -C repo worktree add ../worktree && 1049 git -C repo pack-refs && 1050 git -C worktree pack-refs && 1051 test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && 1052 test_line_count = 1 repo/.git/reftable/tables.list && 1053 1054 git -C repo update-ref worktrees/worktree/refs/bisect/per-worktree HEAD && 1055 test_line_count = 2 repo/.git/worktrees/worktree/reftable/tables.list && 1056 test_line_count = 1 repo/.git/reftable/tables.list 1057' 1058 1059test_expect_success 'worktree: creating per-worktree ref from second worktree' ' 1060 test_when_finished "rm -rf repo wt1 wt2" && 1061 git init repo && 1062 test_commit -C repo A && 1063 1064 git -C repo worktree add ../wt1 && 1065 git -C repo worktree add ../wt2 && 1066 git -C repo pack-refs && 1067 git -C wt1 pack-refs && 1068 git -C wt2 pack-refs && 1069 test_line_count = 1 repo/.git/worktrees/wt1/reftable/tables.list && 1070 test_line_count = 1 repo/.git/worktrees/wt2/reftable/tables.list && 1071 test_line_count = 1 repo/.git/reftable/tables.list && 1072 1073 git -C wt1 update-ref worktrees/wt2/refs/bisect/per-worktree HEAD && 1074 test_line_count = 1 repo/.git/worktrees/wt1/reftable/tables.list && 1075 test_line_count = 2 repo/.git/worktrees/wt2/reftable/tables.list && 1076 test_line_count = 1 repo/.git/reftable/tables.list 1077' 1078 1079test_expect_success 'worktree: can create shared and per-worktree ref in one transaction' ' 1080 test_when_finished "rm -rf repo worktree" && 1081 git init repo && 1082 test_commit -C repo A && 1083 1084 git -C repo worktree add ../worktree && 1085 git -C repo pack-refs && 1086 git -C worktree pack-refs && 1087 test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && 1088 test_line_count = 1 repo/.git/reftable/tables.list && 1089 1090 cat >stdin <<-EOF && 1091 create worktrees/worktree/refs/bisect/per-worktree HEAD 1092 create refs/branches/shared HEAD 1093 EOF 1094 git -C repo update-ref --stdin <stdin && 1095 test_line_count = 2 repo/.git/worktrees/worktree/reftable/tables.list && 1096 test_line_count = 2 repo/.git/reftable/tables.list 1097' 1098 1099test_expect_success 'worktree: can access common refs' ' 1100 test_when_finished "rm -rf repo worktree" && 1101 git init repo && 1102 test_commit -C repo file1 && 1103 git -C repo branch branch1 && 1104 git -C repo worktree add ../worktree && 1105 1106 echo refs/heads/worktree >expect && 1107 git -C worktree symbolic-ref HEAD >actual && 1108 test_cmp expect actual && 1109 git -C worktree checkout branch1 1110' 1111 1112test_expect_success 'worktree: adds worktree with detached HEAD' ' 1113 test_when_finished "rm -rf repo worktree" && 1114 1115 git init repo && 1116 test_commit -C repo A && 1117 git -C repo rev-parse main >expect && 1118 1119 git -C repo worktree add --detach ../worktree main && 1120 git -C worktree rev-parse HEAD >actual && 1121 test_cmp expect actual 1122' 1123 1124test_expect_success 'fetch: accessing FETCH_HEAD special ref works' ' 1125 test_when_finished "rm -rf repo sub" && 1126 1127 git init sub && 1128 test_commit -C sub two && 1129 git -C sub rev-parse HEAD >expect && 1130 1131 git init repo && 1132 test_commit -C repo one && 1133 git -C repo fetch ../sub && 1134 git -C repo rev-parse FETCH_HEAD >actual && 1135 test_cmp expect actual 1136' 1137 1138test_done