]> git.ipfire.org Git - thirdparty/git.git/blob - t/t2024-checkout-dwim.sh
Merge branch 'jc/add-i-use-builtin-experimental'
[thirdparty/git.git] / t / t2024-checkout-dwim.sh
1 #!/bin/sh
2
3 test_description='checkout <branch>
4
5 Ensures 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"?
10 test_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"?
17 test_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
26 status_uno_is_clean () {
27 git status -uno --porcelain >status.actual &&
28 test_must_be_empty status.actual
29 }
30
31 test_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 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_master &&
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
62 test_expect_success 'checkout of non-existing branch fails' '
63 git checkout -B master &&
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 master
70 '
71
72 test_expect_success 'checkout of branch from multiple remotes fails #1' '
73 git checkout -B master &&
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 master
80 '
81
82 test_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
102 test_expect_success 'checkout of branch from multiple remotes fails with advice' '
103 git checkout -B master &&
104 test_might_fail git branch -D foo &&
105 test_must_fail git checkout foo 2>stderr &&
106 test_branch master &&
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 master &&
112 status_uno_is_clean &&
113 test_i18ngrep ! "^hint: " stderr
114 '
115
116 test_expect_success PERL 'checkout -p with multiple remotes does not print advice' '
117 git checkout -B master &&
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
125 test_expect_success 'checkout of branch from multiple remotes succeeds with checkout.defaultRemote #1' '
126 git checkout -B master &&
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
137 test_expect_success 'checkout of branch from a single remote succeeds #1' '
138 git checkout -B master &&
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
148 test_expect_success 'checkout of branch from a single remote succeeds #2' '
149 git checkout -B master &&
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
159 test_expect_success '--no-guess suppresses branch auto-vivification' '
160 git checkout -B master &&
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 master
167 '
168
169 test_expect_success 'setup more remotes with unconventional refspecs' '
170 git checkout -B master &&
171 status_uno_is_clean &&
172 git init repo_c &&
173 (
174 cd repo_c &&
175 test_commit c_master &&
176 git checkout -b bar &&
177 test_commit c_bar &&
178 git checkout -b spam &&
179 test_commit c_spam
180 ) &&
181 git init repo_d &&
182 (
183 cd repo_d &&
184 test_commit d_master &&
185 git checkout -b baz &&
186 test_commit d_baz &&
187 git checkout -b eggs &&
188 test_commit d_eggs
189 ) &&
190 git remote add repo_c repo_c &&
191 git config remote.repo_c.fetch \
192 "+refs/heads/*:refs/remotes/extra_dir/repo_c/extra_dir/*" &&
193 git remote add repo_d repo_d &&
194 git config remote.repo_d.fetch \
195 "+refs/heads/*:refs/repo_d/*" &&
196 git fetch --all
197 '
198
199 test_expect_success 'checkout of branch from multiple remotes fails #2' '
200 git checkout -B master &&
201 status_uno_is_clean &&
202 test_might_fail git branch -D bar &&
203
204 test_must_fail git checkout bar &&
205 status_uno_is_clean &&
206 test_must_fail git rev-parse --verify refs/heads/bar &&
207 test_branch master
208 '
209
210 test_expect_success 'checkout of branch from multiple remotes fails #3' '
211 git checkout -B master &&
212 status_uno_is_clean &&
213 test_might_fail git branch -D baz &&
214
215 test_must_fail git checkout baz &&
216 status_uno_is_clean &&
217 test_must_fail git rev-parse --verify refs/heads/baz &&
218 test_branch master
219 '
220
221 test_expect_success 'checkout of branch from a single remote succeeds #3' '
222 git checkout -B master &&
223 status_uno_is_clean &&
224 test_might_fail git branch -D spam &&
225
226 git checkout spam &&
227 status_uno_is_clean &&
228 test_branch spam &&
229 test_cmp_rev refs/remotes/extra_dir/repo_c/extra_dir/spam HEAD &&
230 test_branch_upstream spam repo_c spam
231 '
232
233 test_expect_success 'checkout of branch from a single remote succeeds #4' '
234 git checkout -B master &&
235 status_uno_is_clean &&
236 test_might_fail git branch -D eggs &&
237
238 git checkout eggs &&
239 status_uno_is_clean &&
240 test_branch eggs &&
241 test_cmp_rev refs/repo_d/eggs HEAD &&
242 test_branch_upstream eggs repo_d eggs
243 '
244
245 test_expect_success 'checkout of branch with a file having the same name fails' '
246 git checkout -B master &&
247 status_uno_is_clean &&
248 test_might_fail git branch -D spam &&
249
250 >spam &&
251 test_must_fail git checkout spam &&
252 status_uno_is_clean &&
253 test_must_fail git rev-parse --verify refs/heads/spam &&
254 test_branch master
255 '
256
257 test_expect_success 'checkout of branch with a file in subdir having the same name fails' '
258 git checkout -B master &&
259 status_uno_is_clean &&
260 test_might_fail git branch -D spam &&
261
262 >spam &&
263 mkdir sub &&
264 mv spam sub/spam &&
265 test_must_fail git -C sub checkout spam &&
266 status_uno_is_clean &&
267 test_must_fail git rev-parse --verify refs/heads/spam &&
268 test_branch master
269 '
270
271 test_expect_success 'checkout <branch> -- succeeds, even if a file with the same name exists' '
272 git checkout -B master &&
273 status_uno_is_clean &&
274 test_might_fail git branch -D spam &&
275
276 >spam &&
277 git checkout spam -- &&
278 status_uno_is_clean &&
279 test_branch spam &&
280 test_cmp_rev refs/remotes/extra_dir/repo_c/extra_dir/spam HEAD &&
281 test_branch_upstream spam repo_c spam
282 '
283
284 test_expect_success 'loosely defined local base branch is reported correctly' '
285
286 git checkout master &&
287 status_uno_is_clean &&
288 git branch strict &&
289 git branch loose &&
290 git commit --allow-empty -m "a bit more" &&
291
292 test_config branch.strict.remote . &&
293 test_config branch.loose.remote . &&
294 test_config branch.strict.merge refs/heads/master &&
295 test_config branch.loose.merge master &&
296
297 git checkout strict | sed -e "s/strict/BRANCHNAME/g" >expect &&
298 status_uno_is_clean &&
299 git checkout loose | sed -e "s/loose/BRANCHNAME/g" >actual &&
300 status_uno_is_clean &&
301
302 test_cmp expect actual
303 '
304
305 test_expect_success 'reject when arg could be part of dwim branch' '
306 git remote add foo file://non-existent-place &&
307 git update-ref refs/remotes/foo/dwim-arg HEAD &&
308 echo foo >dwim-arg &&
309 git add dwim-arg &&
310 echo bar >dwim-arg &&
311 test_must_fail git checkout dwim-arg &&
312 test_must_fail git rev-parse refs/heads/dwim-arg -- &&
313 grep bar dwim-arg
314 '
315
316 test_expect_success 'disambiguate dwim branch and checkout path (1)' '
317 git update-ref refs/remotes/foo/dwim-arg1 HEAD &&
318 echo foo >dwim-arg1 &&
319 git add dwim-arg1 &&
320 echo bar >dwim-arg1 &&
321 git checkout -- dwim-arg1 &&
322 test_must_fail git rev-parse refs/heads/dwim-arg1 -- &&
323 grep foo dwim-arg1
324 '
325
326 test_expect_success 'disambiguate dwim branch and checkout path (2)' '
327 git update-ref refs/remotes/foo/dwim-arg2 HEAD &&
328 echo foo >dwim-arg2 &&
329 git add dwim-arg2 &&
330 echo bar >dwim-arg2 &&
331 git checkout dwim-arg2 -- &&
332 git rev-parse refs/heads/dwim-arg2 -- &&
333 grep bar dwim-arg2
334 '
335
336 test_done