t / t2024-checkout-dwim.shon commit t4000: make hash size independent (8cc5ff8)
   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        git status -uno --porcelain >status.actual &&
  28        test_must_be_empty status.actual
  29}
  30
  31test_expect_success 'setup' '
  32        test_commit my_master &&
  33        git init repo_a &&
  34        (
  35                cd repo_a &&
  36                test_commit a_master &&
  37                git checkout -b foo &&
  38                test_commit a_foo &&
  39                git checkout -b bar &&
  40                test_commit a_bar
  41        ) &&
  42        git init repo_b &&
  43        (
  44                cd repo_b &&
  45                test_commit b_master &&
  46                git checkout -b foo &&
  47                test_commit b_foo &&
  48                git checkout -b baz &&
  49                test_commit b_baz
  50        ) &&
  51        git remote add repo_a repo_a &&
  52        git remote add repo_b repo_b &&
  53        git config remote.repo_b.fetch \
  54                "+refs/heads/*:refs/remotes/other_b/*" &&
  55        git fetch --all
  56'
  57
  58test_expect_success 'checkout of non-existing branch fails' '
  59        git checkout -B master &&
  60        test_might_fail git branch -D xyzzy &&
  61
  62        test_must_fail git checkout xyzzy &&
  63        status_uno_is_clean &&
  64        test_must_fail git rev-parse --verify refs/heads/xyzzy &&
  65        test_branch master
  66'
  67
  68test_expect_success 'checkout of branch from multiple remotes fails #1' '
  69        git checkout -B master &&
  70        test_might_fail git branch -D foo &&
  71
  72        test_must_fail git checkout foo &&
  73        status_uno_is_clean &&
  74        test_must_fail git rev-parse --verify refs/heads/foo &&
  75        test_branch master
  76'
  77
  78test_expect_success 'checkout of branch from multiple remotes fails with advice' '
  79        git checkout -B master &&
  80        test_might_fail git branch -D foo &&
  81        test_must_fail git checkout foo 2>stderr &&
  82        test_branch master &&
  83        status_uno_is_clean &&
  84        test_i18ngrep "^hint: " stderr &&
  85        test_must_fail git -c advice.checkoutAmbiguousRemoteBranchName=false \
  86                checkout foo 2>stderr &&
  87        test_branch master &&
  88        status_uno_is_clean &&
  89        test_i18ngrep ! "^hint: " stderr
  90'
  91
  92test_expect_success PERL 'checkout -p with multiple remotes does not print advice' '
  93        git checkout -B master &&
  94        test_might_fail git branch -D foo &&
  95
  96        git checkout -p foo 2>stderr &&
  97        test_i18ngrep ! "^hint: " stderr &&
  98        status_uno_is_clean
  99'
 100
 101test_expect_success 'checkout of branch from multiple remotes succeeds with checkout.defaultRemote #1' '
 102        git checkout -B master &&
 103        status_uno_is_clean &&
 104        test_might_fail git branch -D foo &&
 105
 106        git -c checkout.defaultRemote=repo_a checkout foo &&
 107        status_uno_is_clean &&
 108        test_branch foo &&
 109        test_cmp_rev remotes/repo_a/foo HEAD &&
 110        test_branch_upstream foo repo_a foo
 111'
 112
 113test_expect_success 'checkout of branch from a single remote succeeds #1' '
 114        git checkout -B master &&
 115        test_might_fail git branch -D bar &&
 116
 117        git checkout bar &&
 118        status_uno_is_clean &&
 119        test_branch bar &&
 120        test_cmp_rev remotes/repo_a/bar HEAD &&
 121        test_branch_upstream bar repo_a bar
 122'
 123
 124test_expect_success 'checkout of branch from a single remote succeeds #2' '
 125        git checkout -B master &&
 126        test_might_fail git branch -D baz &&
 127
 128        git checkout baz &&
 129        status_uno_is_clean &&
 130        test_branch baz &&
 131        test_cmp_rev remotes/other_b/baz HEAD &&
 132        test_branch_upstream baz repo_b baz
 133'
 134
 135test_expect_success '--no-guess suppresses branch auto-vivification' '
 136        git checkout -B master &&
 137        status_uno_is_clean &&
 138        test_might_fail git branch -D bar &&
 139
 140        test_must_fail git checkout --no-guess bar &&
 141        test_must_fail git rev-parse --verify refs/heads/bar &&
 142        test_branch master
 143'
 144
 145test_expect_success 'setup more remotes with unconventional refspecs' '
 146        git checkout -B master &&
 147        status_uno_is_clean &&
 148        git init repo_c &&
 149        (
 150                cd repo_c &&
 151                test_commit c_master &&
 152                git checkout -b bar &&
 153                test_commit c_bar &&
 154                git checkout -b spam &&
 155                test_commit c_spam
 156        ) &&
 157        git init repo_d &&
 158        (
 159                cd repo_d &&
 160                test_commit d_master &&
 161                git checkout -b baz &&
 162                test_commit d_baz &&
 163                git checkout -b eggs &&
 164                test_commit d_eggs
 165        ) &&
 166        git remote add repo_c repo_c &&
 167        git config remote.repo_c.fetch \
 168                "+refs/heads/*:refs/remotes/extra_dir/repo_c/extra_dir/*" &&
 169        git remote add repo_d repo_d &&
 170        git config remote.repo_d.fetch \
 171                "+refs/heads/*:refs/repo_d/*" &&
 172        git fetch --all
 173'
 174
 175test_expect_success 'checkout of branch from multiple remotes fails #2' '
 176        git checkout -B master &&
 177        status_uno_is_clean &&
 178        test_might_fail git branch -D bar &&
 179
 180        test_must_fail git checkout bar &&
 181        status_uno_is_clean &&
 182        test_must_fail git rev-parse --verify refs/heads/bar &&
 183        test_branch master
 184'
 185
 186test_expect_success 'checkout of branch from multiple remotes fails #3' '
 187        git checkout -B master &&
 188        status_uno_is_clean &&
 189        test_might_fail git branch -D baz &&
 190
 191        test_must_fail git checkout baz &&
 192        status_uno_is_clean &&
 193        test_must_fail git rev-parse --verify refs/heads/baz &&
 194        test_branch master
 195'
 196
 197test_expect_success 'checkout of branch from a single remote succeeds #3' '
 198        git checkout -B master &&
 199        status_uno_is_clean &&
 200        test_might_fail git branch -D spam &&
 201
 202        git checkout spam &&
 203        status_uno_is_clean &&
 204        test_branch spam &&
 205        test_cmp_rev refs/remotes/extra_dir/repo_c/extra_dir/spam HEAD &&
 206        test_branch_upstream spam repo_c spam
 207'
 208
 209test_expect_success 'checkout of branch from a single remote succeeds #4' '
 210        git checkout -B master &&
 211        status_uno_is_clean &&
 212        test_might_fail git branch -D eggs &&
 213
 214        git checkout eggs &&
 215        status_uno_is_clean &&
 216        test_branch eggs &&
 217        test_cmp_rev refs/repo_d/eggs HEAD &&
 218        test_branch_upstream eggs repo_d eggs
 219'
 220
 221test_expect_success 'checkout of branch with a file having the same name fails' '
 222        git checkout -B master &&
 223        status_uno_is_clean &&
 224        test_might_fail git branch -D spam &&
 225
 226        >spam &&
 227        test_must_fail git checkout spam &&
 228        status_uno_is_clean &&
 229        test_must_fail git rev-parse --verify refs/heads/spam &&
 230        test_branch master
 231'
 232
 233test_expect_success 'checkout of branch with a file in subdir having the same name fails' '
 234        git checkout -B master &&
 235        status_uno_is_clean &&
 236        test_might_fail git branch -D spam &&
 237
 238        >spam &&
 239        mkdir sub &&
 240        mv spam sub/spam &&
 241        test_must_fail git -C sub checkout spam &&
 242        status_uno_is_clean &&
 243        test_must_fail git rev-parse --verify refs/heads/spam &&
 244        test_branch master
 245'
 246
 247test_expect_success 'checkout <branch> -- succeeds, even if a file with the same name exists' '
 248        git checkout -B master &&
 249        status_uno_is_clean &&
 250        test_might_fail git branch -D spam &&
 251
 252        >spam &&
 253        git checkout spam -- &&
 254        status_uno_is_clean &&
 255        test_branch spam &&
 256        test_cmp_rev refs/remotes/extra_dir/repo_c/extra_dir/spam HEAD &&
 257        test_branch_upstream spam repo_c spam
 258'
 259
 260test_expect_success 'loosely defined local base branch is reported correctly' '
 261
 262        git checkout master &&
 263        status_uno_is_clean &&
 264        git branch strict &&
 265        git branch loose &&
 266        git commit --allow-empty -m "a bit more" &&
 267
 268        test_config branch.strict.remote . &&
 269        test_config branch.loose.remote . &&
 270        test_config branch.strict.merge refs/heads/master &&
 271        test_config branch.loose.merge master &&
 272
 273        git checkout strict | sed -e "s/strict/BRANCHNAME/g" >expect &&
 274        status_uno_is_clean &&
 275        git checkout loose | sed -e "s/loose/BRANCHNAME/g" >actual &&
 276        status_uno_is_clean &&
 277
 278        test_cmp expect actual
 279'
 280
 281test_expect_success 'reject when arg could be part of dwim branch' '
 282        git remote add foo file://non-existent-place &&
 283        git update-ref refs/remotes/foo/dwim-arg HEAD &&
 284        echo foo >dwim-arg &&
 285        git add dwim-arg &&
 286        echo bar >dwim-arg &&
 287        test_must_fail git checkout dwim-arg &&
 288        test_must_fail git rev-parse refs/heads/dwim-arg -- &&
 289        grep bar dwim-arg
 290'
 291
 292test_expect_success 'disambiguate dwim branch and checkout path (1)' '
 293        git update-ref refs/remotes/foo/dwim-arg1 HEAD &&
 294        echo foo >dwim-arg1 &&
 295        git add dwim-arg1 &&
 296        echo bar >dwim-arg1 &&
 297        git checkout -- dwim-arg1 &&
 298        test_must_fail git rev-parse refs/heads/dwim-arg1 -- &&
 299        grep foo dwim-arg1
 300'
 301
 302test_expect_success 'disambiguate dwim branch and checkout path (2)' '
 303        git update-ref refs/remotes/foo/dwim-arg2 HEAD &&
 304        echo foo >dwim-arg2 &&
 305        git add dwim-arg2 &&
 306        echo bar >dwim-arg2 &&
 307        git checkout dwim-arg2 -- &&
 308        git rev-parse refs/heads/dwim-arg2 -- &&
 309        grep bar dwim-arg2
 310'
 311
 312test_done