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