builtin-remote: add set-head subcommand
[git] / t / t5505-remote.sh
1 #!/bin/sh
2
3 test_description='git remote porcelain-ish'
4
5 . ./test-lib.sh
6
7 setup_repository () {
8         mkdir "$1" && (
9         cd "$1" &&
10         git init &&
11         >file &&
12         git add file &&
13         test_tick &&
14         git commit -m "Initial" &&
15         git checkout -b side &&
16         >elif &&
17         git add elif &&
18         test_tick &&
19         git commit -m "Second" &&
20         git checkout master
21         )
22 }
23
24 tokens_match () {
25         echo "$1" | tr ' ' '\012' | sort | sed -e '/^$/d' >expect &&
26         echo "$2" | tr ' ' '\012' | sort | sed -e '/^$/d' >actual &&
27         test_cmp expect actual
28 }
29
30 check_remote_track () {
31         actual=$(git remote show "$1" | sed -e '1,/Tracked/d') &&
32         shift &&
33         tokens_match "$*" "$actual"
34 }
35
36 check_tracking_branch () {
37         f="" &&
38         r=$(git for-each-ref "--format=%(refname)" |
39                 sed -ne "s|^refs/remotes/$1/||p") &&
40         shift &&
41         tokens_match "$*" "$r"
42 }
43
44 test_expect_success setup '
45
46         setup_repository one &&
47         setup_repository two &&
48         (
49                 cd two && git branch another
50         ) &&
51         git clone one test
52
53 '
54
55 test_expect_success 'remote information for the origin' '
56 (
57         cd test &&
58         tokens_match origin "$(git remote)" &&
59         check_remote_track origin master side &&
60         check_tracking_branch origin HEAD master side
61 )
62 '
63
64 test_expect_success 'add another remote' '
65 (
66         cd test &&
67         git remote add -f second ../two &&
68         tokens_match "origin second" "$(git remote)" &&
69         check_remote_track origin master side &&
70         check_remote_track second master side another &&
71         check_tracking_branch second master side another &&
72         git for-each-ref "--format=%(refname)" refs/remotes |
73         sed -e "/^refs\/remotes\/origin\//d" \
74             -e "/^refs\/remotes\/second\//d" >actual &&
75         >expect &&
76         test_cmp expect actual
77 )
78 '
79
80 test_expect_success 'remote forces tracking branches' '
81 (
82         cd test &&
83         case `git config remote.second.fetch` in
84         +*) true ;;
85          *) false ;;
86         esac
87 )
88 '
89
90 test_expect_success 'remove remote' '
91 (
92         cd test &&
93         git symbolic-ref refs/remotes/second/HEAD refs/remotes/second/master &&
94         git remote rm second
95 )
96 '
97
98 test_expect_success 'remove remote' '
99 (
100         cd test &&
101         tokens_match origin "$(git remote)" &&
102         check_remote_track origin master side &&
103         git for-each-ref "--format=%(refname)" refs/remotes |
104         sed -e "/^refs\/remotes\/origin\//d" >actual &&
105         >expect &&
106         test_cmp expect actual
107 )
108 '
109
110 test_expect_success 'remove remote protects non-remote branches' '
111 (
112         cd test &&
113         (cat >expect1 <<EOF
114 Note: A non-remote branch was not removed; to delete it, use:
115   git branch -d master
116 EOF
117     cat >expect2 <<EOF
118 Note: Non-remote branches were not removed; to delete them, use:
119   git branch -d foobranch
120   git branch -d master
121 EOF
122 ) &&
123         git tag footag
124         git config --add remote.oops.fetch "+refs/*:refs/*" &&
125         git remote rm oops 2>actual1 &&
126         git branch foobranch &&
127         git config --add remote.oops.fetch "+refs/*:refs/*" &&
128         git remote rm oops 2>actual2 &&
129         git branch -d foobranch &&
130         git tag -d footag &&
131         test_cmp expect1 actual1 &&
132         test_cmp expect2 actual2
133 )
134 '
135
136 cat > test/expect << EOF
137 * remote origin
138   URL: $(pwd)/one
139   HEAD branch: master
140   Remote branch merged with 'git pull' while on branch master
141     master
142   New remote branch (next fetch will store in remotes/origin)
143     master
144   Tracked remote branches
145     master
146     side
147   Local branches pushed with 'git push'
148     master:upstream
149     +refs/tags/lastbackup
150 * remote two
151   URL: ../two
152   HEAD branch (remote HEAD is ambiguous, may be one of the following):
153     another
154     master
155 EOF
156
157 test_expect_success 'show' '
158         (cd test &&
159          git config --add remote.origin.fetch \
160                 refs/heads/master:refs/heads/upstream &&
161          git fetch &&
162          git branch -d -r origin/master &&
163          git config --add remote.two.url ../two &&
164          (cd ../one &&
165           echo 1 > file &&
166           test_tick &&
167           git commit -m update file) &&
168          git config remote.origin.push \
169                 refs/heads/master:refs/heads/upstream &&
170          git config --add remote.origin.push \
171                 +refs/tags/lastbackup &&
172          git remote show origin two > output &&
173          test_cmp expect output)
174 '
175
176 cat > test/expect << EOF
177 * remote origin
178   URL: $(pwd)/one
179   HEAD branch: (not queried)
180   Remote branch merged with 'git pull' while on branch master
181     master
182   Tracked remote branches
183     master
184     side
185   Local branches pushed with 'git push'
186     master:upstream
187     +refs/tags/lastbackup
188 EOF
189
190 test_expect_success 'show -n' '
191         (mv one one.unreachable &&
192          cd test &&
193          git remote show -n origin > output &&
194          mv ../one.unreachable ../one &&
195          test_cmp expect output)
196 '
197
198 test_expect_success 'prune' '
199         (cd one &&
200          git branch -m side side2) &&
201         (cd test &&
202          git fetch origin &&
203          git remote prune origin &&
204          git rev-parse refs/remotes/origin/side2 &&
205          test_must_fail git rev-parse refs/remotes/origin/side)
206 '
207
208 test_expect_success 'set-head --delete' '
209         (cd test &&
210          git symbolic-ref refs/remotes/origin/HEAD &&
211          git remote set-head --delete origin &&
212          test_must_fail git symbolic-ref refs/remotes/origin/HEAD)
213 '
214
215 test_expect_success 'set-head --auto' '
216         (cd test &&
217          git remote set-head --auto origin &&
218          echo refs/remotes/origin/master >expect &&
219          git symbolic-ref refs/remotes/origin/HEAD >output &&
220          test_cmp expect output
221         )
222 '
223
224 cat >test/expect <<EOF
225 error: Multiple remote HEAD branches. Please choose one explicitly with:
226   git remote set-head two another
227   git remote set-head two master
228 EOF
229
230 test_expect_success 'set-head --auto fails w/multiple HEADs' '
231         (cd test &&
232          test_must_fail git remote set-head --auto two >output 2>&1 &&
233         test_cmp expect output)
234 '
235
236 cat >test/expect <<EOF
237 refs/remotes/origin/side2
238 EOF
239
240 test_expect_success 'set-head explicit' '
241         (cd test &&
242          git remote set-head origin side2 &&
243          git symbolic-ref refs/remotes/origin/HEAD >output &&
244          git remote set-head origin master &&
245          test_cmp expect output)
246 '
247
248 cat > test/expect << EOF
249 Pruning origin
250 URL: $(pwd)/one
251  * [would prune] origin/side2
252 EOF
253
254 test_expect_success 'prune --dry-run' '
255         (cd one &&
256          git branch -m side2 side) &&
257         (cd test &&
258          git remote prune --dry-run origin > output &&
259          git rev-parse refs/remotes/origin/side2 &&
260          test_must_fail git rev-parse refs/remotes/origin/side &&
261         (cd ../one &&
262          git branch -m side side2) &&
263          test_cmp expect output)
264 '
265
266 test_expect_success 'add --mirror && prune' '
267         (mkdir mirror &&
268          cd mirror &&
269          git init --bare &&
270          git remote add --mirror -f origin ../one) &&
271         (cd one &&
272          git branch -m side2 side) &&
273         (cd mirror &&
274          git rev-parse --verify refs/heads/side2 &&
275          test_must_fail git rev-parse --verify refs/heads/side &&
276          git fetch origin &&
277          git remote prune origin &&
278          test_must_fail git rev-parse --verify refs/heads/side2 &&
279          git rev-parse --verify refs/heads/side)
280 '
281
282 test_expect_success 'add alt && prune' '
283         (mkdir alttst &&
284          cd alttst &&
285          git init &&
286          git remote add -f origin ../one &&
287          git config remote.alt.url ../one &&
288          git config remote.alt.fetch "+refs/heads/*:refs/remotes/origin/*") &&
289         (cd one &&
290          git branch -m side side2) &&
291         (cd alttst &&
292          git rev-parse --verify refs/remotes/origin/side &&
293          test_must_fail git rev-parse --verify refs/remotes/origin/side2 &&
294          git fetch alt &&
295          git remote prune alt &&
296          test_must_fail git rev-parse --verify refs/remotes/origin/side &&
297          git rev-parse --verify refs/remotes/origin/side2)
298 '
299
300 cat > one/expect << EOF
301   apis/master
302   apis/side
303   drosophila/another
304   drosophila/master
305   drosophila/side
306 EOF
307
308 test_expect_success 'update' '
309
310         (cd one &&
311          git remote add drosophila ../two &&
312          git remote add apis ../mirror &&
313          git remote update &&
314          git branch -r > output &&
315          test_cmp expect output)
316
317 '
318
319 cat > one/expect << EOF
320   drosophila/another
321   drosophila/master
322   drosophila/side
323   manduca/master
324   manduca/side
325   megaloprepus/master
326   megaloprepus/side
327 EOF
328
329 test_expect_success 'update with arguments' '
330
331         (cd one &&
332          for b in $(git branch -r)
333          do
334                 git branch -r -d $b || break
335          done &&
336          git remote add manduca ../mirror &&
337          git remote add megaloprepus ../mirror &&
338          git config remotes.phobaeticus "drosophila megaloprepus" &&
339          git config remotes.titanus manduca &&
340          git remote update phobaeticus titanus &&
341          git branch -r > output &&
342          test_cmp expect output)
343
344 '
345
346 cat > one/expect << EOF
347   apis/master
348   apis/side
349   manduca/master
350   manduca/side
351   megaloprepus/master
352   megaloprepus/side
353 EOF
354
355 test_expect_success 'update default' '
356
357         (cd one &&
358          for b in $(git branch -r)
359          do
360                 git branch -r -d $b || break
361          done &&
362          git config remote.drosophila.skipDefaultUpdate true &&
363          git remote update default &&
364          git branch -r > output &&
365          test_cmp expect output)
366
367 '
368
369 cat > one/expect << EOF
370   drosophila/another
371   drosophila/master
372   drosophila/side
373 EOF
374
375 test_expect_success 'update default (overridden, with funny whitespace)' '
376
377         (cd one &&
378          for b in $(git branch -r)
379          do
380                 git branch -r -d $b || break
381          done &&
382          git config remotes.default "$(printf "\t drosophila  \n")" &&
383          git remote update default &&
384          git branch -r > output &&
385          test_cmp expect output)
386
387 '
388
389 test_expect_success '"remote show" does not show symbolic refs' '
390
391         git clone one three &&
392         (cd three &&
393          git remote show origin > output &&
394          ! grep "^ *HEAD$" < output &&
395          ! grep -i stale < output)
396
397 '
398
399 test_expect_success 'reject adding remote with an invalid name' '
400
401         test_must_fail git remote add some:url desired-name
402
403 '
404
405 # The first three test if the tracking branches are properly renamed,
406 # the last two ones check if the config is updated.
407
408 test_expect_success 'rename a remote' '
409
410         git clone one four &&
411         (cd four &&
412          git remote rename origin upstream &&
413          rmdir .git/refs/remotes/origin &&
414          test "$(git symbolic-ref refs/remotes/upstream/HEAD)" = "refs/remotes/upstream/master" &&
415          test "$(git rev-parse upstream/master)" = "$(git rev-parse master)" &&
416          test "$(git config remote.upstream.fetch)" = "+refs/heads/*:refs/remotes/upstream/*" &&
417          test "$(git config branch.master.remote)" = "upstream")
418
419 '
420
421 cat > remotes_origin << EOF
422 URL: $(pwd)/one
423 Push: refs/heads/master:refs/heads/upstream
424 Pull: refs/heads/master:refs/heads/origin
425 EOF
426
427 test_expect_success 'migrate a remote from named file in $GIT_DIR/remotes' '
428         git clone one five &&
429         origin_url=$(pwd)/one &&
430         (cd five &&
431          git remote rm origin &&
432          mkdir -p .git/remotes &&
433          cat ../remotes_origin > .git/remotes/origin &&
434          git remote rename origin origin &&
435          ! test -f .git/remotes/origin &&
436          test "$(git config remote.origin.url)" = "$origin_url" &&
437          test "$(git config remote.origin.push)" = "refs/heads/master:refs/heads/upstream" &&
438          test "$(git config remote.origin.fetch)" = "refs/heads/master:refs/heads/origin")
439 '
440
441 test_expect_success 'migrate a remote from named file in $GIT_DIR/branches' '
442         git clone one six &&
443         origin_url=$(pwd)/one &&
444         (cd six &&
445          git remote rm origin &&
446          echo "$origin_url" > .git/branches/origin &&
447          git remote rename origin origin &&
448          ! test -f .git/branches/origin &&
449          test "$(git config remote.origin.url)" = "$origin_url" &&
450          test "$(git config remote.origin.fetch)" = "refs/heads/master:refs/heads/origin")
451 '
452
453 test_expect_success 'remote prune to cause a dangling symref' '
454         git clone one seven &&
455         (
456                 cd one &&
457                 git checkout side2 &&
458                 git branch -D master
459         ) &&
460         (
461                 cd seven &&
462                 git remote prune origin
463         ) 2>err &&
464         grep "has become dangling" err &&
465
466         : And the dangling symref will not cause other annoying errors
467         (
468                 cd seven &&
469                 git branch -a
470         ) 2>err &&
471         ! grep "points nowhere" err
472         (
473                 cd seven &&
474                 test_must_fail git branch nomore origin
475         ) 2>err &&
476         grep "dangling symref" err
477 '
478
479 test_done
480