t / t2024-checkout-dwim.shon commit built-in rebase --autostash: leave the current branch alone if possible (176f5d9)
   1#!/bin/sh
   2
   3test_description='checkout <branch>
   4
   5Ensures that checkout on an unborn branch does what the user expects'
   6
   7. ./test-lib.sh
   8
   9# Is the current branch "refs/heads/$1"?
  10test_branch () {
  11        printf "%s\n" "refs/heads/$1" >expect.HEAD &&
  12        git symbolic-ref HEAD >actual.HEAD &&
  13        test_cmp expect.HEAD actual.HEAD
  14}
  15
  16# Is branch "refs/heads/$1" set to pull from "$2/$3"?
  17test_branch_upstream () {
  18        printf "%s\n" "$2" "refs/heads/$3" >expect.upstream &&
  19        {
  20                git config "branch.$1.remote" &&
  21                git config "branch.$1.merge"
  22        } >actual.upstream &&
  23        test_cmp expect.upstream actual.upstream
  24}
  25
  26status_uno_is_clean () {
  27        >status.expect &&
  28        git status -uno --porcelain >status.actual &&
  29        test_cmp status.expect status.actual
  30}
  31
  32test_expect_success 'setup' '
  33        test_commit my_master &&
  34        git init repo_a &&
  35        (
  36                cd repo_a &&
  37                test_commit a_master &&
  38                git checkout -b foo &&
  39                test_commit a_foo &&
  40                git checkout -b bar &&
  41                test_commit a_bar
  42        ) &&
  43        git init repo_b &&
  44        (
  45                cd repo_b &&
  46                test_commit b_master &&
  47                git checkout -b foo &&
  48                test_commit b_foo &&
  49                git checkout -b baz &&
  50                test_commit b_baz
  51        ) &&
  52        git remote add repo_a repo_a &&
  53        git remote add repo_b repo_b &&
  54        git config remote.repo_b.fetch \
  55                "+refs/heads/*:refs/remotes/other_b/*" &&
  56        git fetch --all
  57'
  58
  59test_expect_success 'checkout of non-existing branch fails' '
  60        git checkout -B master &&
  61        test_might_fail git branch -D xyzzy &&
  62
  63        test_must_fail git checkout xyzzy &&
  64        status_uno_is_clean &&
  65        test_must_fail git rev-parse --verify refs/heads/xyzzy &&
  66        test_branch master
  67'
  68
  69test_expect_success 'checkout of branch from multiple remotes fails #1' '
  70        git checkout -B master &&
  71        test_might_fail git branch -D foo &&
  72
  73        test_must_fail git checkout foo &&
  74        status_uno_is_clean &&
  75        test_must_fail git rev-parse --verify refs/heads/foo &&
  76        test_branch master
  77'
  78
  79test_expect_success 'checkout of branch from multiple remotes fails with advice' '
  80        git checkout -B master &&
  81        test_might_fail git branch -D foo &&
  82        test_must_fail git checkout foo 2>stderr &&
  83        test_branch master &&
  84        status_uno_is_clean &&
  85        test_i18ngrep "^hint: " stderr &&
  86        test_must_fail git -c advice.checkoutAmbiguousRemoteBranchName=false \
  87                checkout foo 2>stderr &&
  88        test_branch master &&
  89        status_uno_is_clean &&
  90        test_i18ngrep ! "^hint: " stderr &&
  91        # Make sure the likes of checkout -p do not print this hint
  92        git checkout -p foo 2>stderr &&
  93        test_i18ngrep ! "^hint: " stderr &&
  94        status_uno_is_clean
  95'
  96
  97test_expect_success 'checkout of branch from multiple remotes succeeds with checkout.defaultRemote #1' '
  98        git checkout -B master &&
  99        status_uno_is_clean &&
 100        test_might_fail git branch -D foo &&
 101
 102        git -c checkout.defaultRemote=repo_a checkout foo &&
 103        status_uno_is_clean &&
 104        test_branch foo &&
 105        test_cmp_rev remotes/repo_a/foo HEAD &&
 106        test_branch_upstream foo repo_a foo
 107'
 108
 109test_expect_success 'checkout of branch from a single remote succeeds #1' '
 110        git checkout -B master &&
 111        test_might_fail git branch -D bar &&
 112
 113        git checkout bar &&
 114        status_uno_is_clean &&
 115        test_branch bar &&
 116        test_cmp_rev remotes/repo_a/bar HEAD &&
 117        test_branch_upstream bar repo_a bar
 118'
 119
 120test_expect_success 'checkout of branch from a single remote succeeds #2' '
 121        git checkout -B master &&
 122        test_might_fail git branch -D baz &&
 123
 124        git checkout baz &&
 125        status_uno_is_clean &&
 126        test_branch baz &&
 127        test_cmp_rev remotes/other_b/baz HEAD &&
 128        test_branch_upstream baz repo_b baz
 129'
 130
 131test_expect_success '--no-guess suppresses branch auto-vivification' '
 132        git checkout -B master &&
 133        status_uno_is_clean &&
 134        test_might_fail git branch -D bar &&
 135
 136        test_must_fail git checkout --no-guess bar &&
 137        test_must_fail git rev-parse --verify refs/heads/bar &&
 138        test_branch master
 139'
 140
 141test_expect_success 'setup more remotes with unconventional refspecs' '
 142        git checkout -B master &&
 143        status_uno_is_clean &&
 144        git init repo_c &&
 145        (
 146                cd repo_c &&
 147                test_commit c_master &&
 148                git checkout -b bar &&
 149                test_commit c_bar &&
 150                git checkout -b spam &&
 151                test_commit c_spam
 152        ) &&
 153        git init repo_d &&
 154        (
 155                cd repo_d &&
 156                test_commit d_master &&
 157                git checkout -b baz &&
 158                test_commit d_baz &&
 159                git checkout -b eggs &&
 160                test_commit d_eggs
 161        ) &&
 162        git remote add repo_c repo_c &&
 163        git config remote.repo_c.fetch \
 164                "+refs/heads/*:refs/remotes/extra_dir/repo_c/extra_dir/*" &&
 165        git remote add repo_d repo_d &&
 166        git config remote.repo_d.fetch \
 167                "+refs/heads/*:refs/repo_d/*" &&
 168        git fetch --all
 169'
 170
 171test_expect_success 'checkout of branch from multiple remotes fails #2' '
 172        git checkout -B master &&
 173        status_uno_is_clean &&
 174        test_might_fail git branch -D bar &&
 175
 176        test_must_fail git checkout bar &&
 177        status_uno_is_clean &&
 178        test_must_fail git rev-parse --verify refs/heads/bar &&
 179        test_branch master
 180'
 181
 182test_expect_success 'checkout of branch from multiple remotes fails #3' '
 183        git checkout -B master &&
 184        status_uno_is_clean &&
 185        test_might_fail git branch -D baz &&
 186
 187        test_must_fail git checkout baz &&
 188        status_uno_is_clean &&
 189        test_must_fail git rev-parse --verify refs/heads/baz &&
 190        test_branch master
 191'
 192
 193test_expect_success 'checkout of branch from a single remote succeeds #3' '
 194        git checkout -B master &&
 195        status_uno_is_clean &&
 196        test_might_fail git branch -D spam &&
 197
 198        git checkout spam &&
 199        status_uno_is_clean &&
 200        test_branch spam &&
 201        test_cmp_rev refs/remotes/extra_dir/repo_c/extra_dir/spam HEAD &&
 202        test_branch_upstream spam repo_c spam
 203'
 204
 205test_expect_success 'checkout of branch from a single remote succeeds #4' '
 206        git checkout -B master &&
 207        status_uno_is_clean &&
 208        test_might_fail git branch -D eggs &&
 209
 210        git checkout eggs &&
 211        status_uno_is_clean &&
 212        test_branch eggs &&
 213        test_cmp_rev refs/repo_d/eggs HEAD &&
 214        test_branch_upstream eggs repo_d eggs
 215'
 216
 217test_expect_success 'checkout of branch with a file having the same name fails' '
 218        git checkout -B master &&
 219        status_uno_is_clean &&
 220        test_might_fail git branch -D spam &&
 221
 222        >spam &&
 223        test_must_fail git checkout spam &&
 224        status_uno_is_clean &&
 225        test_must_fail git rev-parse --verify refs/heads/spam &&
 226        test_branch master
 227'
 228
 229test_expect_success 'checkout of branch with a file in subdir having the same name fails' '
 230        git checkout -B master &&
 231        status_uno_is_clean &&
 232        test_might_fail git branch -D spam &&
 233
 234        >spam &&
 235        mkdir sub &&
 236        mv spam sub/spam &&
 237        test_must_fail git -C sub checkout spam &&
 238        status_uno_is_clean &&
 239        test_must_fail git rev-parse --verify refs/heads/spam &&
 240        test_branch master
 241'
 242
 243test_expect_success 'checkout <branch> -- succeeds, even if a file with the same name exists' '
 244        git checkout -B master &&
 245        status_uno_is_clean &&
 246        test_might_fail git branch -D spam &&
 247
 248        >spam &&
 249        git checkout spam -- &&
 250        status_uno_is_clean &&
 251        test_branch spam &&
 252        test_cmp_rev refs/remotes/extra_dir/repo_c/extra_dir/spam HEAD &&
 253        test_branch_upstream spam repo_c spam
 254'
 255
 256test_expect_success 'loosely defined local base branch is reported correctly' '
 257
 258        git checkout master &&
 259        status_uno_is_clean &&
 260        git branch strict &&
 261        git branch loose &&
 262        git commit --allow-empty -m "a bit more" &&
 263
 264        test_config branch.strict.remote . &&
 265        test_config branch.loose.remote . &&
 266        test_config branch.strict.merge refs/heads/master &&
 267        test_config branch.loose.merge master &&
 268
 269        git checkout strict | sed -e "s/strict/BRANCHNAME/g" >expect &&
 270        status_uno_is_clean &&
 271        git checkout loose | sed -e "s/loose/BRANCHNAME/g" >actual &&
 272        status_uno_is_clean &&
 273
 274        test_cmp expect actual
 275'
 276
 277test_done