bundle: framework for options before bundle file
[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         ) &&
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
58 test_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
68 test_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
78 test_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
92 test_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
101 test_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
113 test_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
124 test_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
135 test_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
145 test_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
175 test_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
186 test_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
197 test_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
209 test_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
221 test_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
233 test_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
247 test_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
260 test_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
281 test_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
292 test_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
302 test_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
312 test_done