1#!/bin/sh
   2test_description='checkout '
   4. ./test-lib.sh
   6# Arguments: <branch> <sha> [<checkout options>]
   8#
   9# Runs "git checkout" to switch to <branch>, testing that
  10#
  11#   1) we are on the specified branch, <branch>;
  12#   2) HEAD is <sha>; if <sha> is not specified, the old HEAD is used.
  13#
  14# If <checkout options> is not specified, "git checkout" is run with -b.
  15do_checkout() {
  16        exp_branch=$1 &&
  17        exp_ref="refs/heads/$exp_branch" &&
  18        # if <sha> is not specified, use HEAD.
  20        exp_sha=${2:-$(git rev-parse --verify HEAD)} &&
  21        # default options for git checkout: -b
  23        if [ -z "$3" ]; then
  24                opts="-b"
  25        else
  26                opts="$3"
  27        fi
  28        git checkout $opts $exp_branch $exp_sha &&
  30        test $exp_ref = $(git rev-parse --symbolic-full-name HEAD) &&
  32        test $exp_sha = $(git rev-parse --verify HEAD)
  33}
  34test_dirty_unmergeable() {
  36        ! git diff --exit-code >/dev/null
  37}
  38setup_dirty_unmergeable() {
  40        echo >>file1 change2
  41}
  42test_dirty_mergeable() {
  44        ! git diff --cached --exit-code >/dev/null
  45}
  46setup_dirty_mergeable() {
  48        echo >file2 file2 &&
  49        git add file2
  50}
  51test_expect_success 'setup' '
  53        test_commit initial file1 &&
  54        HEAD1=$(git rev-parse --verify HEAD) &&
  55        test_commit change1 file1 &&
  57        HEAD2=$(git rev-parse --verify HEAD) &&
  58        git branch -m branch1
  60'
  61test_expect_success 'checkout -b to a new branch, set to HEAD' '
  63        do_checkout branch2
  64'
  65test_expect_success 'checkout -b to a new branch, set to an explicit ref' '
  67        git checkout branch1 &&
  68        git branch -D branch2 &&
  69        do_checkout branch2 $HEAD1
  71'
  72test_expect_success 'checkout -b to a new branch with unmergeable changes fails' '
  74        git checkout branch1 &&
  75        # clean up from previous test
  77        git branch -D branch2 &&
  78        setup_dirty_unmergeable &&
  80        test_must_fail do_checkout branch2 $HEAD1 &&
  81        test_dirty_unmergeable
  82'
  83test_expect_success 'checkout -f -b to a new branch with unmergeable changes discards changes' '
  85        # still dirty and on branch1
  86        do_checkout branch2 $HEAD1 "-f -b" &&
  87        test_must_fail test_dirty_unmergeable
  88'
  89test_expect_success 'checkout -b to a new branch preserves mergeable changes' '
  91        git checkout branch1 &&
  92        # clean up from previous test
  94        git branch -D branch2 &&
  95        setup_dirty_mergeable &&
  97        do_checkout branch2 $HEAD1 &&
  98        test_dirty_mergeable
  99'
 100test_expect_success 'checkout -f -b to a new branch with mergeable changes discards changes' '
 102        # clean up from previous test
 103        git reset --hard &&
 104        git checkout branch1 &&
 106        # clean up from previous test
 108        git branch -D branch2 &&
 109        setup_dirty_mergeable &&
 111        do_checkout branch2 $HEAD1 "-f -b" &&
 112        test_must_fail test_dirty_mergeable
 113'
 114test_expect_success 'checkout -b to an existing branch fails' '
 116        git reset --hard HEAD &&
 117        test_must_fail do_checkout branch2 $HEAD2
 119'
 120test_expect_success 'checkout -b to @{-1} fails with the right branch name' '
 122        git reset --hard HEAD &&
 123        git checkout branch1 &&
 124        git checkout branch2 &&
 125        echo  >expect "fatal: A branch named '\''branch1'\'' already exists." &&
 126        test_must_fail git checkout -b @{-1} 2>actual &&
 127        test_cmp expect actual
 128'
 129test_expect_success 'checkout -B to an existing branch resets branch to HEAD' '
 131        git checkout branch1 &&
 132        do_checkout branch2 "" -B
 134'
 135test_expect_success 'checkout -B to an existing branch from detached HEAD resets branch to HEAD' '
 137        git checkout $(git rev-parse --verify HEAD) &&
 138        do_checkout branch2 "" -B
 140'
 141test_expect_success 'checkout -B to an existing branch with an explicit ref resets branch to that ref' '
 143        git checkout branch1 &&
 144        do_checkout branch2 $HEAD1 -B
 146'
 147test_expect_success 'checkout -B to an existing branch with unmergeable changes fails' '
 149        git checkout branch1 &&
 150        setup_dirty_unmergeable &&
 152        test_must_fail do_checkout branch2 $HEAD1 -B &&
 153        test_dirty_unmergeable
 154'
 155test_expect_success 'checkout -f -B to an existing branch with unmergeable changes discards changes' '
 157        # still dirty and on branch1
 158        do_checkout branch2 $HEAD1 "-f -B" &&
 159        test_must_fail test_dirty_unmergeable
 160'
 161test_expect_success 'checkout -B to an existing branch preserves mergeable changes' '
 163        git checkout branch1 &&
 164        setup_dirty_mergeable &&
 166        do_checkout branch2 $HEAD1 -B &&
 167        test_dirty_mergeable
 168'
 169test_expect_success 'checkout -f -B to an existing branch with mergeable changes discards changes' '
 171        # clean up from previous test
 172        git reset --hard &&
 173        git checkout branch1 &&
 175        setup_dirty_mergeable &&
 177        do_checkout branch2 $HEAD1 "-f -B" &&
 178        test_must_fail test_dirty_mergeable
 179'
 180test_expect_success 'checkout -b <describe>' '
 182        git tag -f -m "First commit" initial initial &&
 183        git checkout -f change1 &&
 184        name=$(git describe) &&
 185        git checkout -b $name &&
 186        git diff --exit-code change1 &&
 187        echo "refs/heads/$name" >expect &&
 188        git symbolic-ref HEAD >actual &&
 189        test_cmp expect actual
 190'
 191test_expect_success 'checkout -B to the current branch works' '
 193        git checkout branch1 &&
 194        git checkout -B branch1-scratch &&
 195        setup_dirty_mergeable &&
 197        git checkout -B branch1-scratch initial &&
 198        test_dirty_mergeable
 199'
 200test_done