f1655820194278fb36ee7c7a73a83f869d040589
   1#!/bin/sh
   2#
   3# Copyright (c) 2006 Junio C Hamano
   4#
   5
   6test_description='git checkout tests.
   7
   8Creates master, forks renamer and side branches from it.
   9Test switching across them.
  10
  11  ! [master] Initial A one, A two
  12   * [renamer] Renamer R one->uno, M two
  13    ! [side] Side M one, D two, A three
  14     ! [simple] Simple D one, M two
  15  ----
  16     + [simple] Simple D one, M two
  17    +  [side] Side M one, D two, A three
  18   *   [renamer] Renamer R one->uno, M two
  19  +*++ [master] Initial A one, A two
  20
  21'
  22
  23. ./test-lib.sh
  24
  25test_tick
  26
  27fill () {
  28        for i
  29        do
  30                echo "$i"
  31        done
  32}
  33
  34
  35test_expect_success setup '
  36
  37        fill x y z > same &&
  38        fill 1 2 3 4 5 6 7 8 >one &&
  39        fill a b c d e >two &&
  40        git add same one two &&
  41        git commit -m "Initial A one, A two" &&
  42
  43        git checkout -b renamer &&
  44        rm -f one &&
  45        fill 1 3 4 5 6 7 8 >uno &&
  46        git add uno &&
  47        fill a b c d e f >two &&
  48        git commit -a -m "Renamer R one->uno, M two" &&
  49
  50        git checkout -b side master &&
  51        fill 1 2 3 4 5 6 7 >one &&
  52        fill A B C D E >three &&
  53        rm -f two &&
  54        git update-index --add --remove one two three &&
  55        git commit -m "Side M one, D two, A three" &&
  56
  57        git checkout -b simple master &&
  58        rm -f one &&
  59        fill a c e > two &&
  60        git commit -a -m "Simple D one, M two" &&
  61
  62        git checkout master
  63'
  64
  65test_expect_success "checkout from non-existing branch" '
  66
  67        git checkout -b delete-me master &&
  68        git update-ref -d --no-deref refs/heads/delete-me &&
  69        test refs/heads/delete-me = "$(git symbolic-ref HEAD)" &&
  70        git checkout master &&
  71        test refs/heads/master = "$(git symbolic-ref HEAD)"
  72'
  73
  74test_expect_success "checkout with dirty tree without -m" '
  75
  76        fill 0 1 2 3 4 5 6 7 8 >one &&
  77        if git checkout side
  78        then
  79                echo Not happy
  80                false
  81        else
  82                echo "happy - failed correctly"
  83        fi
  84
  85'
  86
  87test_expect_success "checkout with unrelated dirty tree without -m" '
  88
  89        git checkout -f master &&
  90        fill 0 1 2 3 4 5 6 7 8 >same &&
  91        cp same kept &&
  92        git checkout side >messages &&
  93        test_cmp same kept &&
  94        printf "M\t%s\n" same >messages.expect &&
  95        test_cmp messages.expect messages
  96'
  97
  98test_expect_success "checkout -m with dirty tree" '
  99
 100        git checkout -f master &&
 101        git clean -f &&
 102
 103        fill 0 1 2 3 4 5 6 7 8 >one &&
 104        git checkout -m side > messages &&
 105
 106        test "$(git symbolic-ref HEAD)" = "refs/heads/side" &&
 107
 108        printf "M\t%s\n" one >expect.messages &&
 109        test_cmp expect.messages messages &&
 110
 111        fill "M one" "A three" "D       two" >expect.master &&
 112        git diff --name-status master >current.master &&
 113        test_cmp expect.master current.master &&
 114
 115        fill "M one" >expect.side &&
 116        git diff --name-status side >current.side &&
 117        test_cmp expect.side current.side &&
 118
 119        git diff --cached >current.index &&
 120        test_must_be_empty current.index
 121'
 122
 123test_expect_success "checkout -m with dirty tree, renamed" '
 124
 125        git checkout -f master && git clean -f &&
 126
 127        fill 1 2 3 4 5 7 8 >one &&
 128        if git checkout renamer
 129        then
 130                echo Not happy
 131                false
 132        else
 133                echo "happy - failed correctly"
 134        fi &&
 135
 136        git checkout -m renamer &&
 137        fill 1 3 4 5 7 8 >expect &&
 138        test_cmp expect uno &&
 139        ! test -f one &&
 140        git diff --cached >current &&
 141        test_must_be_empty current
 142
 143'
 144
 145test_expect_success 'checkout -m with merge conflict' '
 146
 147        git checkout -f master && git clean -f &&
 148
 149        fill 1 T 3 4 5 6 S 8 >one &&
 150        if git checkout renamer
 151        then
 152                echo Not happy
 153                false
 154        else
 155                echo "happy - failed correctly"
 156        fi &&
 157
 158        git checkout -m renamer &&
 159
 160        git diff master:one :3:uno |
 161        sed -e "1,/^@@/d" -e "/^ /d" -e "s/^-/d/" -e "s/^+/a/" >current &&
 162        fill d2 aT d7 aS >expect &&
 163        test_cmp expect current &&
 164        git diff --cached two >current &&
 165        test_must_be_empty current
 166'
 167
 168test_expect_success 'format of merge conflict from checkout -m' '
 169
 170        git checkout -f master && git clean -f &&
 171
 172        fill b d > two &&
 173        git checkout -m simple &&
 174
 175        git ls-files >current &&
 176        fill same two two two >expect &&
 177        test_cmp expect current &&
 178
 179        cat <<-EOF >expect &&
 180        <<<<<<< simple
 181        a
 182        c
 183        e
 184        =======
 185        b
 186        d
 187        >>>>>>> local
 188        EOF
 189        test_cmp expect two
 190'
 191
 192test_expect_success 'checkout --merge --conflict=diff3 <branch>' '
 193
 194        git checkout -f master && git reset --hard && git clean -f &&
 195
 196        fill b d > two &&
 197        git checkout --merge --conflict=diff3 simple &&
 198
 199        cat <<-EOF >expect &&
 200        <<<<<<< simple
 201        a
 202        c
 203        e
 204        ||||||| master
 205        a
 206        b
 207        c
 208        d
 209        e
 210        =======
 211        b
 212        d
 213        >>>>>>> local
 214        EOF
 215        test_cmp expect two
 216'
 217
 218test_expect_success 'switch to another branch while carrying a deletion' '
 219
 220        git checkout -f master && git reset --hard && git clean -f &&
 221        git rm two &&
 222
 223        test_must_fail git checkout simple 2>errs &&
 224        test_i18ngrep overwritten errs &&
 225
 226        test_must_fail git read-tree --quiet -m -u HEAD simple 2>errs &&
 227        test_must_be_empty errs &&
 228
 229        git checkout --merge simple 2>errs &&
 230        test_i18ngrep ! overwritten errs &&
 231        git ls-files -u &&
 232        test_must_fail git cat-file -t :0:two &&
 233        test "$(git cat-file -t :1:two)" = blob &&
 234        test "$(git cat-file -t :2:two)" = blob &&
 235        test_must_fail git cat-file -t :3:two
 236'
 237
 238test_expect_success 'checkout to detach HEAD (with advice declined)' '
 239
 240        git config advice.detachedHead false &&
 241        git checkout -f renamer && git clean -f &&
 242        git checkout renamer^ 2>messages &&
 243        test_i18ngrep "HEAD is now at 7329388" messages &&
 244        test_line_count = 1 messages &&
 245        H=$(git rev-parse --verify HEAD) &&
 246        M=$(git show-ref -s --verify refs/heads/master) &&
 247        test "z$H" = "z$M" &&
 248        if git symbolic-ref HEAD >/dev/null 2>&1
 249        then
 250                echo "OOPS, HEAD is still symbolic???"
 251                false
 252        else
 253                : happy
 254        fi
 255'
 256
 257test_expect_success 'checkout to detach HEAD' '
 258        git config advice.detachedHead true &&
 259        git checkout -f renamer && git clean -f &&
 260        GIT_TEST_GETTEXT_POISON= git checkout renamer^ 2>messages &&
 261        grep "HEAD is now at 7329388" messages &&
 262        test_line_count -gt 1 messages &&
 263        H=$(git rev-parse --verify HEAD) &&
 264        M=$(git show-ref -s --verify refs/heads/master) &&
 265        test "z$H" = "z$M" &&
 266        if git symbolic-ref HEAD >/dev/null 2>&1
 267        then
 268                echo "OOPS, HEAD is still symbolic???"
 269                false
 270        else
 271                : happy
 272        fi
 273'
 274
 275test_expect_success 'checkout to detach HEAD with branchname^' '
 276
 277        git checkout -f master && git clean -f &&
 278        git checkout renamer^ &&
 279        H=$(git rev-parse --verify HEAD) &&
 280        M=$(git show-ref -s --verify refs/heads/master) &&
 281        test "z$H" = "z$M" &&
 282        if git symbolic-ref HEAD >/dev/null 2>&1
 283        then
 284                echo "OOPS, HEAD is still symbolic???"
 285                false
 286        else
 287                : happy
 288        fi
 289'
 290
 291test_expect_success 'checkout to detach HEAD with :/message' '
 292
 293        git checkout -f master && git clean -f &&
 294        git checkout ":/Initial" &&
 295        H=$(git rev-parse --verify HEAD) &&
 296        M=$(git show-ref -s --verify refs/heads/master) &&
 297        test "z$H" = "z$M" &&
 298        if git symbolic-ref HEAD >/dev/null 2>&1
 299        then
 300                echo "OOPS, HEAD is still symbolic???"
 301                false
 302        else
 303                : happy
 304        fi
 305'
 306
 307test_expect_success 'checkout to detach HEAD with HEAD^0' '
 308
 309        git checkout -f master && git clean -f &&
 310        git checkout HEAD^0 &&
 311        H=$(git rev-parse --verify HEAD) &&
 312        M=$(git show-ref -s --verify refs/heads/master) &&
 313        test "z$H" = "z$M" &&
 314        if git symbolic-ref HEAD >/dev/null 2>&1
 315        then
 316                echo "OOPS, HEAD is still symbolic???"
 317                false
 318        else
 319                : happy
 320        fi
 321'
 322
 323test_expect_success 'checkout with ambiguous tag/branch names' '
 324
 325        git tag both side &&
 326        git branch both master &&
 327        git reset --hard &&
 328        git checkout master &&
 329
 330        git checkout both &&
 331        H=$(git rev-parse --verify HEAD) &&
 332        M=$(git show-ref -s --verify refs/heads/master) &&
 333        test "z$H" = "z$M" &&
 334        name=$(git symbolic-ref HEAD 2>/dev/null) &&
 335        test "z$name" = zrefs/heads/both
 336
 337'
 338
 339test_expect_success 'checkout with ambiguous tag/branch names' '
 340
 341        git reset --hard &&
 342        git checkout master &&
 343
 344        git tag frotz side &&
 345        git branch frotz master &&
 346        git reset --hard &&
 347        git checkout master &&
 348
 349        git checkout tags/frotz &&
 350        H=$(git rev-parse --verify HEAD) &&
 351        S=$(git show-ref -s --verify refs/heads/side) &&
 352        test "z$H" = "z$S" &&
 353        if name=$(git symbolic-ref HEAD 2>/dev/null)
 354        then
 355                echo "Bad -- should have detached"
 356                false
 357        else
 358                : happy
 359        fi
 360
 361'
 362
 363test_expect_success 'switch branches while in subdirectory' '
 364
 365        git reset --hard &&
 366        git checkout master &&
 367
 368        mkdir subs &&
 369        (
 370                cd subs &&
 371                git checkout side
 372        ) &&
 373        ! test -f subs/one &&
 374        rm -fr subs
 375
 376'
 377
 378test_expect_success 'checkout specific path while in subdirectory' '
 379
 380        git reset --hard &&
 381        git checkout side &&
 382        mkdir subs &&
 383        >subs/bero &&
 384        git add subs/bero &&
 385        git commit -m "add subs/bero" &&
 386
 387        git checkout master &&
 388        mkdir -p subs &&
 389        (
 390                cd subs &&
 391                git checkout side -- bero
 392        ) &&
 393        test -f subs/bero
 394
 395'
 396
 397test_expect_success \
 398    'checkout w/--track sets up tracking' '
 399    git config branch.autosetupmerge false &&
 400    git checkout master &&
 401    git checkout --track -b track1 &&
 402    test "$(git config branch.track1.remote)" &&
 403    test "$(git config branch.track1.merge)"'
 404
 405test_expect_success \
 406    'checkout w/autosetupmerge=always sets up tracking' '
 407    test_when_finished git config branch.autosetupmerge false &&
 408    git config branch.autosetupmerge always &&
 409    git checkout master &&
 410    git checkout -b track2 &&
 411    test "$(git config branch.track2.remote)" &&
 412    test "$(git config branch.track2.merge)"'
 413
 414test_expect_success 'checkout w/--track from non-branch HEAD fails' '
 415    git checkout master^0 &&
 416    test_must_fail git symbolic-ref HEAD &&
 417    test_must_fail git checkout --track -b track &&
 418    test_must_fail git rev-parse --verify track &&
 419    test_must_fail git symbolic-ref HEAD &&
 420    test "z$(git rev-parse master^0)" = "z$(git rev-parse HEAD)"
 421'
 422
 423test_expect_success 'checkout w/--track from tag fails' '
 424    git checkout master^0 &&
 425    test_must_fail git symbolic-ref HEAD &&
 426    test_must_fail git checkout --track -b track frotz &&
 427    test_must_fail git rev-parse --verify track &&
 428    test_must_fail git symbolic-ref HEAD &&
 429    test "z$(git rev-parse master^0)" = "z$(git rev-parse HEAD)"
 430'
 431
 432test_expect_success 'detach a symbolic link HEAD' '
 433    git checkout master &&
 434    git config --bool core.prefersymlinkrefs yes &&
 435    git checkout side &&
 436    git checkout master &&
 437    it=$(git symbolic-ref HEAD) &&
 438    test "z$it" = zrefs/heads/master &&
 439    here=$(git rev-parse --verify refs/heads/master) &&
 440    git checkout side^ &&
 441    test "z$(git rev-parse --verify refs/heads/master)" = "z$here"
 442'
 443
 444test_expect_success \
 445    'checkout with --track fakes a sensible -b <name>' '
 446    git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" &&
 447    git update-ref refs/remotes/origin/koala/bear renamer &&
 448
 449    git checkout --track origin/koala/bear &&
 450    test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
 451    test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" &&
 452
 453    git checkout master && git branch -D koala/bear &&
 454
 455    git checkout --track refs/remotes/origin/koala/bear &&
 456    test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
 457    test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" &&
 458
 459    git checkout master && git branch -D koala/bear &&
 460
 461    git checkout --track remotes/origin/koala/bear &&
 462    test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
 463    test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)"
 464'
 465
 466test_expect_success \
 467    'checkout with --track, but without -b, fails with too short tracked name' '
 468    test_must_fail git checkout --track renamer'
 469
 470setup_conflicting_index () {
 471        rm -f .git/index &&
 472        O=$(echo original | git hash-object -w --stdin) &&
 473        A=$(echo ourside | git hash-object -w --stdin) &&
 474        B=$(echo theirside | git hash-object -w --stdin) &&
 475        (
 476                echo "100644 $A 0       fild" &&
 477                echo "100644 $O 1       file" &&
 478                echo "100644 $A 2       file" &&
 479                echo "100644 $B 3       file" &&
 480                echo "100644 $A 0       filf"
 481        ) | git update-index --index-info
 482}
 483
 484test_expect_success 'checkout an unmerged path should fail' '
 485        setup_conflicting_index &&
 486        echo "none of the above" >sample &&
 487        cat sample >fild &&
 488        cat sample >file &&
 489        cat sample >filf &&
 490        test_must_fail git checkout fild file filf &&
 491        test_cmp sample fild &&
 492        test_cmp sample filf &&
 493        test_cmp sample file
 494'
 495
 496test_expect_success 'checkout with an unmerged path can be ignored' '
 497        setup_conflicting_index &&
 498        echo "none of the above" >sample &&
 499        echo ourside >expect &&
 500        cat sample >fild &&
 501        cat sample >file &&
 502        cat sample >filf &&
 503        git checkout -f fild file filf &&
 504        test_cmp expect fild &&
 505        test_cmp expect filf &&
 506        test_cmp sample file
 507'
 508
 509test_expect_success 'checkout unmerged stage' '
 510        setup_conflicting_index &&
 511        echo "none of the above" >sample &&
 512        echo ourside >expect &&
 513        cat sample >fild &&
 514        cat sample >file &&
 515        cat sample >filf &&
 516        git checkout --ours . &&
 517        test_cmp expect fild &&
 518        test_cmp expect filf &&
 519        test_cmp expect file &&
 520        git checkout --theirs file &&
 521        test ztheirside = "z$(cat file)"
 522'
 523
 524test_expect_success 'checkout with --merge' '
 525        setup_conflicting_index &&
 526        echo "none of the above" >sample &&
 527        echo ourside >expect &&
 528        cat sample >fild &&
 529        cat sample >file &&
 530        cat sample >filf &&
 531        git checkout -m -- fild file filf &&
 532        (
 533                echo "<<<<<<< ours" &&
 534                echo ourside &&
 535                echo "=======" &&
 536                echo theirside &&
 537                echo ">>>>>>> theirs"
 538        ) >merged &&
 539        test_cmp expect fild &&
 540        test_cmp expect filf &&
 541        test_cmp merged file
 542'
 543
 544test_expect_success 'checkout with --merge, in diff3 -m style' '
 545        git config merge.conflictstyle diff3 &&
 546        setup_conflicting_index &&
 547        echo "none of the above" >sample &&
 548        echo ourside >expect &&
 549        cat sample >fild &&
 550        cat sample >file &&
 551        cat sample >filf &&
 552        git checkout -m -- fild file filf &&
 553        (
 554                echo "<<<<<<< ours" &&
 555                echo ourside &&
 556                echo "||||||| base" &&
 557                echo original &&
 558                echo "=======" &&
 559                echo theirside &&
 560                echo ">>>>>>> theirs"
 561        ) >merged &&
 562        test_cmp expect fild &&
 563        test_cmp expect filf &&
 564        test_cmp merged file
 565'
 566
 567test_expect_success 'checkout --conflict=merge, overriding config' '
 568        git config merge.conflictstyle diff3 &&
 569        setup_conflicting_index &&
 570        echo "none of the above" >sample &&
 571        echo ourside >expect &&
 572        cat sample >fild &&
 573        cat sample >file &&
 574        cat sample >filf &&
 575        git checkout --conflict=merge -- fild file filf &&
 576        (
 577                echo "<<<<<<< ours" &&
 578                echo ourside &&
 579                echo "=======" &&
 580                echo theirside &&
 581                echo ">>>>>>> theirs"
 582        ) >merged &&
 583        test_cmp expect fild &&
 584        test_cmp expect filf &&
 585        test_cmp merged file
 586'
 587
 588test_expect_success 'checkout --conflict=diff3' '
 589        test_unconfig merge.conflictstyle &&
 590        setup_conflicting_index &&
 591        echo "none of the above" >sample &&
 592        echo ourside >expect &&
 593        cat sample >fild &&
 594        cat sample >file &&
 595        cat sample >filf &&
 596        git checkout --conflict=diff3 -- fild file filf &&
 597        (
 598                echo "<<<<<<< ours" &&
 599                echo ourside &&
 600                echo "||||||| base" &&
 601                echo original &&
 602                echo "=======" &&
 603                echo theirside &&
 604                echo ">>>>>>> theirs"
 605        ) >merged &&
 606        test_cmp expect fild &&
 607        test_cmp expect filf &&
 608        test_cmp merged file
 609'
 610
 611test_expect_success 'failing checkout -b should not break working tree' '
 612        git reset --hard master &&
 613        git symbolic-ref HEAD refs/heads/master &&
 614        test_must_fail git checkout -b renamer side^ &&
 615        test $(git symbolic-ref HEAD) = refs/heads/master &&
 616        git diff --exit-code &&
 617        git diff --cached --exit-code
 618
 619'
 620
 621test_expect_success 'switch out of non-branch' '
 622        git reset --hard master &&
 623        git checkout master^0 &&
 624        echo modified >one &&
 625        test_must_fail git checkout renamer 2>error.log &&
 626        ! grep "^Previous HEAD" error.log
 627'
 628
 629(
 630 echo "#!$SHELL_PATH"
 631 cat <<\EOF
 632O=$1 A=$2 B=$3
 633cat "$A" >.tmp
 634exec >"$A"
 635echo '<<<<<<< filfre-theirs'
 636cat "$B"
 637echo '||||||| filfre-common'
 638cat "$O"
 639echo '======='
 640cat ".tmp"
 641echo '>>>>>>> filfre-ours'
 642rm -f .tmp
 643exit 1
 644EOF
 645) >filfre.sh
 646chmod +x filfre.sh
 647
 648test_expect_success 'custom merge driver with checkout -m' '
 649        git reset --hard &&
 650
 651        git config merge.filfre.driver "./filfre.sh %O %A %B" &&
 652        git config merge.filfre.name "Feel-free merge driver" &&
 653        git config merge.filfre.recursive binary &&
 654        echo "arm merge=filfre" >.gitattributes &&
 655
 656        git checkout -b left &&
 657        echo neutral >arm &&
 658        git add arm .gitattributes &&
 659        test_tick &&
 660        git commit -m neutral &&
 661        git branch right &&
 662
 663        echo left >arm &&
 664        test_tick &&
 665        git commit -a -m left &&
 666        git checkout right &&
 667
 668        echo right >arm &&
 669        test_tick &&
 670        git commit -a -m right &&
 671
 672        test_must_fail git merge left &&
 673        (
 674                for t in filfre-common left right
 675                do
 676                        grep $t arm || exit 1
 677                done
 678        ) &&
 679
 680        mv arm expect &&
 681        git checkout -m arm &&
 682        test_cmp expect arm
 683'
 684
 685test_done