remote: add camel-cased *.tagOpt key, like clone
[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 -b main &&
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 main
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 -ne 's|^    \(.*\) tracked$|\1|p')
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         setup_repository one &&
46         setup_repository two &&
47         (
48                 cd two &&
49                 git branch another
50         ) &&
51         git clone one test
52 '
53
54 test_expect_success 'add remote whose URL agrees with url.<...>.insteadOf' '
55         test_config url.git@host.com:team/repo.git.insteadOf myremote &&
56         git remote add myremote git@host.com:team/repo.git
57 '
58
59 test_expect_success C_LOCALE_OUTPUT 'remote information for the origin' '
60         (
61                 cd test &&
62                 tokens_match origin "$(git remote)" &&
63                 check_remote_track origin main side &&
64                 check_tracking_branch origin HEAD main side
65         )
66 '
67
68 test_expect_success 'add another remote' '
69         (
70                 cd test &&
71                 git remote add -f second ../two &&
72                 tokens_match "origin second" "$(git remote)" &&
73                 check_tracking_branch second main side another &&
74                 git for-each-ref "--format=%(refname)" refs/remotes |
75                 sed -e "/^refs\/remotes\/origin\//d" \
76                     -e "/^refs\/remotes\/second\//d" >actual &&
77                 test_must_be_empty actual
78         )
79 '
80
81 test_expect_success C_LOCALE_OUTPUT 'check remote-tracking' '
82         (
83                 cd test &&
84                 check_remote_track origin main side &&
85                 check_remote_track second main side another
86         )
87 '
88
89 test_expect_success 'remote forces tracking branches' '
90         (
91                 cd test &&
92                 case $(git config remote.second.fetch) in
93                 +*) true ;;
94                  *) false ;;
95                 esac
96         )
97 '
98
99 test_expect_success 'remove remote' '
100         (
101                 cd test &&
102                 git symbolic-ref refs/remotes/second/HEAD refs/remotes/second/main &&
103                 git remote rm second
104         )
105 '
106
107 test_expect_success C_LOCALE_OUTPUT 'remove remote' '
108         (
109                 cd test &&
110                 tokens_match origin "$(git remote)" &&
111                 check_remote_track origin main side &&
112                 git for-each-ref "--format=%(refname)" refs/remotes |
113                 sed -e "/^refs\/remotes\/origin\//d" >actual &&
114                 test_must_be_empty actual
115         )
116 '
117
118 test_expect_success 'remove remote protects local branches' '
119         (
120                 cd test &&
121                 cat >expect1 <<-\EOF &&
122                 Note: A branch outside the refs/remotes/ hierarchy was not removed;
123                 to delete it, use:
124                   git branch -d main
125                 EOF
126                 cat >expect2 <<-\EOF &&
127                 Note: Some branches outside the refs/remotes/ hierarchy were not removed;
128                 to delete them, use:
129                   git branch -d foobranch
130                   git branch -d main
131                 EOF
132                 git tag footag &&
133                 git config --add remote.oops.fetch "+refs/*:refs/*" &&
134                 git remote remove oops 2>actual1 &&
135                 git branch foobranch &&
136                 git config --add remote.oops.fetch "+refs/*:refs/*" &&
137                 git remote rm oops 2>actual2 &&
138                 git branch -d foobranch &&
139                 git tag -d footag &&
140                 test_i18ncmp expect1 actual1 &&
141                 test_i18ncmp expect2 actual2
142         )
143 '
144
145 test_expect_success 'remove errors out early when deleting non-existent branch' '
146         (
147                 cd test &&
148                 echo "error: No such remote: '\''foo'\''" >expect &&
149                 test_expect_code 2 git remote rm foo 2>actual &&
150                 test_i18ncmp expect actual
151         )
152 '
153
154 test_expect_success 'remove remote with a branch without configured merge' '
155         test_when_finished "(
156                 git -C test checkout main;
157                 git -C test branch -D two;
158                 git -C test config --remove-section remote.two;
159                 git -C test config --remove-section branch.second;
160                 true
161         )" &&
162         (
163                 cd test &&
164                 git remote add two ../two &&
165                 git fetch two &&
166                 git checkout -b second two/main^0 &&
167                 git config branch.second.remote two &&
168                 git checkout main &&
169                 git remote rm two
170         )
171 '
172
173 test_expect_success 'rename errors out early when deleting non-existent branch' '
174         (
175                 cd test &&
176                 echo "error: No such remote: '\''foo'\''" >expect &&
177                 test_expect_code 2 git remote rename foo bar 2>actual &&
178                 test_i18ncmp expect actual
179         )
180 '
181
182 test_expect_success 'rename errors out early when when new name is invalid' '
183         test_config remote.foo.vcs bar &&
184         echo "fatal: '\''invalid...name'\'' is not a valid remote name" >expect &&
185         test_must_fail git remote rename foo invalid...name 2>actual &&
186         test_i18ncmp expect actual
187 '
188
189 test_expect_success 'add existing foreign_vcs remote' '
190         test_config remote.foo.vcs bar &&
191         echo "error: remote foo already exists." >expect &&
192         test_expect_code 3 git remote add foo bar 2>actual &&
193         test_i18ncmp expect actual
194 '
195
196 test_expect_success 'add existing foreign_vcs remote' '
197         test_config remote.foo.vcs bar &&
198         test_config remote.bar.vcs bar &&
199         echo "error: remote bar already exists." >expect &&
200         test_expect_code 3 git remote rename foo bar 2>actual &&
201         test_i18ncmp expect actual
202 '
203
204 test_expect_success 'add invalid foreign_vcs remote' '
205         echo "fatal: '\''invalid...name'\'' is not a valid remote name" >expect &&
206         test_must_fail git remote add invalid...name bar 2>actual &&
207         test_i18ncmp expect actual
208 '
209
210 cat >test/expect <<EOF
211 * remote origin
212   Fetch URL: $(pwd)/one
213   Push  URL: $(pwd)/one
214   HEAD branch: main
215   Remote branches:
216     main new (next fetch will store in remotes/origin)
217     side tracked
218   Local branches configured for 'git pull':
219     ahead    merges with remote main
220     main     merges with remote main
221     octopus  merges with remote topic-a
222                 and with remote topic-b
223                 and with remote topic-c
224     rebase  rebases onto remote main
225   Local refs configured for 'git push':
226     main pushes to main     (local out of date)
227     main pushes to upstream (create)
228 * remote two
229   Fetch URL: ../two
230   Push  URL: ../three
231   HEAD branch: main
232   Local refs configured for 'git push':
233     ahead forces to main    (fast-forwardable)
234     main  pushes to another (up to date)
235 EOF
236
237 test_expect_success 'show' '
238         (
239                 cd test &&
240                 git config --add remote.origin.fetch refs/heads/main:refs/heads/upstream &&
241                 git fetch &&
242                 git checkout -b ahead origin/main &&
243                 echo 1 >>file &&
244                 test_tick &&
245                 git commit -m update file &&
246                 git checkout main &&
247                 git branch --track octopus origin/main &&
248                 git branch --track rebase origin/main &&
249                 git branch -d -r origin/main &&
250                 git config --add remote.two.url ../two &&
251                 git config --add remote.two.pushurl ../three &&
252                 git config branch.rebase.rebase true &&
253                 git config branch.octopus.merge "topic-a topic-b topic-c" &&
254                 (
255                         cd ../one &&
256                         echo 1 >file &&
257                         test_tick &&
258                         git commit -m update file
259                 ) &&
260                 git config --add remote.origin.push : &&
261                 git config --add remote.origin.push refs/heads/main:refs/heads/upstream &&
262                 git config --add remote.origin.push +refs/tags/lastbackup &&
263                 git config --add remote.two.push +refs/heads/ahead:refs/heads/main &&
264                 git config --add remote.two.push refs/heads/main:refs/heads/another &&
265                 git remote show origin two >output &&
266                 git branch -d rebase octopus &&
267                 test_i18ncmp expect output
268         )
269 '
270
271 cat >test/expect <<EOF
272 * remote origin
273   Fetch URL: $(pwd)/one
274   Push  URL: $(pwd)/one
275   HEAD branch: (not queried)
276   Remote branches: (status not queried)
277     main
278     side
279   Local branches configured for 'git pull':
280     ahead merges with remote main
281     main  merges with remote main
282   Local refs configured for 'git push' (status not queried):
283     (matching)           pushes to (matching)
284     refs/heads/main      pushes to refs/heads/upstream
285     refs/tags/lastbackup forces to refs/tags/lastbackup
286 EOF
287
288 test_expect_success 'show -n' '
289         mv one one.unreachable &&
290         (
291                 cd test &&
292                 git remote show -n origin >output &&
293                 mv ../one.unreachable ../one &&
294                 test_i18ncmp expect output
295         )
296 '
297
298 test_expect_success 'prune' '
299         (
300                 cd one &&
301                 git branch -m side side2
302         ) &&
303         (
304                 cd test &&
305                 git fetch origin &&
306                 git remote prune origin &&
307                 git rev-parse refs/remotes/origin/side2 &&
308                 test_must_fail git rev-parse refs/remotes/origin/side
309         )
310 '
311
312 test_expect_success 'set-head --delete' '
313         (
314                 cd test &&
315                 git symbolic-ref refs/remotes/origin/HEAD &&
316                 git remote set-head --delete origin &&
317                 test_must_fail git symbolic-ref refs/remotes/origin/HEAD
318         )
319 '
320
321 test_expect_success 'set-head --auto' '
322         (
323                 cd test &&
324                 git remote set-head --auto origin &&
325                 echo refs/remotes/origin/main >expect &&
326                 git symbolic-ref refs/remotes/origin/HEAD >output &&
327                 test_cmp expect output
328         )
329 '
330
331 test_expect_success 'set-head --auto has no problem w/multiple HEADs' '
332         (
333                 cd test &&
334                 git fetch two "refs/heads/*:refs/remotes/two/*" &&
335                 git remote set-head --auto two >output 2>&1 &&
336                 echo "two/HEAD set to main" >expect &&
337                 test_i18ncmp expect output
338         )
339 '
340
341 cat >test/expect <<\EOF
342 refs/remotes/origin/side2
343 EOF
344
345 test_expect_success 'set-head explicit' '
346         (
347                 cd test &&
348                 git remote set-head origin side2 &&
349                 git symbolic-ref refs/remotes/origin/HEAD >output &&
350                 git remote set-head origin main &&
351                 test_cmp expect output
352         )
353 '
354
355 cat >test/expect <<EOF
356 Pruning origin
357 URL: $(pwd)/one
358  * [would prune] origin/side2
359 EOF
360
361 test_expect_success 'prune --dry-run' '
362         git -C one branch -m side2 side &&
363         test_when_finished "git -C one branch -m side side2" &&
364         (
365                 cd test &&
366                 git remote prune --dry-run origin >output &&
367                 git rev-parse refs/remotes/origin/side2 &&
368                 test_must_fail git rev-parse refs/remotes/origin/side &&
369                 test_i18ncmp expect output
370         )
371 '
372
373 test_expect_success 'add --mirror && prune' '
374         mkdir mirror &&
375         (
376                 cd mirror &&
377                 git init --bare &&
378                 git remote add --mirror -f origin ../one
379         ) &&
380         (
381                 cd one &&
382                 git branch -m side2 side
383         ) &&
384         (
385                 cd mirror &&
386                 git rev-parse --verify refs/heads/side2 &&
387                 test_must_fail git rev-parse --verify refs/heads/side &&
388                 git fetch origin &&
389                 git remote prune origin &&
390                 test_must_fail git rev-parse --verify refs/heads/side2 &&
391                 git rev-parse --verify refs/heads/side
392         )
393 '
394
395 test_expect_success 'add --mirror=fetch' '
396         mkdir mirror-fetch &&
397         git init -b main mirror-fetch/parent &&
398         (
399                 cd mirror-fetch/parent &&
400                 test_commit one
401         ) &&
402         git init --bare mirror-fetch/child &&
403         (
404                 cd mirror-fetch/child &&
405                 git remote add --mirror=fetch -f parent ../parent
406         )
407 '
408
409 test_expect_success 'fetch mirrors act as mirrors during fetch' '
410         (
411                 cd mirror-fetch/parent &&
412                 git branch new &&
413                 git branch -m main renamed
414         ) &&
415         (
416                 cd mirror-fetch/child &&
417                 git fetch parent &&
418                 git rev-parse --verify refs/heads/new &&
419                 git rev-parse --verify refs/heads/renamed
420         )
421 '
422
423 test_expect_success 'fetch mirrors can prune' '
424         (
425                 cd mirror-fetch/child &&
426                 git remote prune parent &&
427                 test_must_fail git rev-parse --verify refs/heads/main
428         )
429 '
430
431 test_expect_success 'fetch mirrors do not act as mirrors during push' '
432         (
433                 cd mirror-fetch/parent &&
434                 git checkout HEAD^0
435         ) &&
436         (
437                 cd mirror-fetch/child &&
438                 git branch -m renamed renamed2 &&
439                 git push parent :
440         ) &&
441         (
442                 cd mirror-fetch/parent &&
443                 git rev-parse --verify renamed &&
444                 test_must_fail git rev-parse --verify refs/heads/renamed2
445         )
446 '
447
448 test_expect_success 'add fetch mirror with specific branches' '
449         git init --bare mirror-fetch/track &&
450         (
451                 cd mirror-fetch/track &&
452                 git remote add --mirror=fetch -t heads/new parent ../parent
453         )
454 '
455
456 test_expect_success 'fetch mirror respects specific branches' '
457         (
458                 cd mirror-fetch/track &&
459                 git fetch parent &&
460                 git rev-parse --verify refs/heads/new &&
461                 test_must_fail git rev-parse --verify refs/heads/renamed
462         )
463 '
464
465 test_expect_success 'add --mirror=push' '
466         mkdir mirror-push &&
467         git init --bare mirror-push/public &&
468         git init -b main mirror-push/private &&
469         (
470                 cd mirror-push/private &&
471                 test_commit one &&
472                 git remote add --mirror=push public ../public
473         )
474 '
475
476 test_expect_success 'push mirrors act as mirrors during push' '
477         (
478                 cd mirror-push/private &&
479                 git branch new &&
480                 git branch -m main renamed &&
481                 git push public
482         ) &&
483         (
484                 cd mirror-push/private &&
485                 git rev-parse --verify refs/heads/new &&
486                 git rev-parse --verify refs/heads/renamed &&
487                 test_must_fail git rev-parse --verify refs/heads/main
488         )
489 '
490
491 test_expect_success 'push mirrors do not act as mirrors during fetch' '
492         (
493                 cd mirror-push/public &&
494                 git branch -m renamed renamed2 &&
495                 git symbolic-ref HEAD refs/heads/renamed2
496         ) &&
497         (
498                 cd mirror-push/private &&
499                 git fetch public &&
500                 git rev-parse --verify refs/heads/renamed &&
501                 test_must_fail git rev-parse --verify refs/heads/renamed2
502         )
503 '
504
505 test_expect_success 'push mirrors do not allow you to specify refs' '
506         git init mirror-push/track &&
507         (
508                 cd mirror-push/track &&
509                 test_must_fail git remote add --mirror=push -t new public ../public
510         )
511 '
512
513 test_expect_success 'add alt && prune' '
514         mkdir alttst &&
515         (
516                 cd alttst &&
517                 git init &&
518                 git remote add -f origin ../one &&
519                 git config remote.alt.url ../one &&
520                 git config remote.alt.fetch "+refs/heads/*:refs/remotes/origin/*"
521         ) &&
522         (
523                 cd one &&
524                 git branch -m side side2
525         ) &&
526         (
527                 cd alttst &&
528                 git rev-parse --verify refs/remotes/origin/side &&
529                 test_must_fail git rev-parse --verify refs/remotes/origin/side2 &&
530                 git fetch alt &&
531                 git remote prune alt &&
532                 test_must_fail git rev-parse --verify refs/remotes/origin/side &&
533                 git rev-parse --verify refs/remotes/origin/side2
534         )
535 '
536
537 cat >test/expect <<\EOF
538 some-tag
539 EOF
540
541 test_expect_success 'add with reachable tags (default)' '
542         (
543                 cd one &&
544                 >foobar &&
545                 git add foobar &&
546                 git commit -m "Foobar" &&
547                 git tag -a -m "Foobar tag" foobar-tag &&
548                 git reset --hard HEAD~1 &&
549                 git tag -a -m "Some tag" some-tag
550         ) &&
551         mkdir add-tags &&
552         (
553                 cd add-tags &&
554                 git init &&
555                 git remote add -f origin ../one &&
556                 git tag -l some-tag >../test/output &&
557                 git tag -l foobar-tag >>../test/output &&
558                 test_must_fail git config remote.origin.tagopt
559         ) &&
560         test_cmp test/expect test/output
561 '
562
563 cat >test/expect <<\EOF
564 some-tag
565 foobar-tag
566 --tags
567 EOF
568
569 test_expect_success 'add --tags' '
570         rm -rf add-tags &&
571         (
572                 mkdir add-tags &&
573                 cd add-tags &&
574                 git init &&
575                 git remote add -f --tags origin ../one &&
576                 git tag -l some-tag >../test/output &&
577                 git tag -l foobar-tag >>../test/output &&
578                 git config remote.origin.tagopt >>../test/output
579         ) &&
580         test_cmp test/expect test/output
581 '
582
583 cat >test/expect <<\EOF
584 --no-tags
585 EOF
586
587 test_expect_success 'add --no-tags' '
588         rm -rf add-tags &&
589         (
590                 mkdir add-no-tags &&
591                 cd add-no-tags &&
592                 git init &&
593                 git remote add -f --no-tags origin ../one &&
594                 grep tagOpt .git/config &&
595                 git tag -l some-tag >../test/output &&
596                 git tag -l foobar-tag >../test/output &&
597                 git config remote.origin.tagopt >>../test/output
598         ) &&
599         (
600                 cd one &&
601                 git tag -d some-tag foobar-tag
602         ) &&
603         test_cmp test/expect test/output
604 '
605
606 test_expect_success 'reject --no-no-tags' '
607         (
608                 cd add-no-tags &&
609                 test_must_fail git remote add -f --no-no-tags neworigin ../one
610         )
611 '
612
613 cat >one/expect <<\EOF
614   apis/main
615   apis/side
616   drosophila/another
617   drosophila/main
618   drosophila/side
619 EOF
620
621 test_expect_success 'update' '
622         (
623                 cd one &&
624                 git remote add drosophila ../two &&
625                 git remote add apis ../mirror &&
626                 git remote update &&
627                 git branch -r >output &&
628                 test_cmp expect output
629         )
630 '
631
632 cat >one/expect <<\EOF
633   drosophila/another
634   drosophila/main
635   drosophila/side
636   manduca/main
637   manduca/side
638   megaloprepus/main
639   megaloprepus/side
640 EOF
641
642 test_expect_success 'update with arguments' '
643         (
644                 cd one &&
645                 for b in $(git branch -r)
646                 do
647                 git branch -r -d $b || exit 1
648                 done &&
649                 git remote add manduca ../mirror &&
650                 git remote add megaloprepus ../mirror &&
651                 git config remotes.phobaeticus "drosophila megaloprepus" &&
652                 git config remotes.titanus manduca &&
653                 git remote update phobaeticus titanus &&
654                 git branch -r >output &&
655                 test_cmp expect output
656         )
657 '
658
659 test_expect_success 'update --prune' '
660         (
661                 cd one &&
662                 git branch -m side2 side3
663         ) &&
664         (
665                 cd test &&
666                 git remote update --prune &&
667                 (
668                         cd ../one &&
669                         git branch -m side3 side2
670                 ) &&
671                 git rev-parse refs/remotes/origin/side3 &&
672                 test_must_fail git rev-parse refs/remotes/origin/side2
673         )
674 '
675
676 cat >one/expect <<-\EOF
677   apis/main
678   apis/side
679   manduca/main
680   manduca/side
681   megaloprepus/main
682   megaloprepus/side
683 EOF
684
685 test_expect_success 'update default' '
686         (
687                 cd one &&
688                 for b in $(git branch -r)
689                 do
690                 git branch -r -d $b || exit 1
691                 done &&
692                 git config remote.drosophila.skipDefaultUpdate true &&
693                 git remote update default &&
694                 git branch -r >output &&
695                 test_cmp expect output
696         )
697 '
698
699 cat >one/expect <<\EOF
700   drosophila/another
701   drosophila/main
702   drosophila/side
703 EOF
704
705 test_expect_success 'update default (overridden, with funny whitespace)' '
706         (
707                 cd one &&
708                 for b in $(git branch -r)
709                 do
710                 git branch -r -d $b || exit 1
711                 done &&
712                 git config remotes.default "$(printf "\t drosophila  \n")" &&
713                 git remote update default &&
714                 git branch -r >output &&
715                 test_cmp expect output
716         )
717 '
718
719 test_expect_success 'update (with remotes.default defined)' '
720         (
721                 cd one &&
722                 for b in $(git branch -r)
723                 do
724                 git branch -r -d $b || exit 1
725                 done &&
726                 git config remotes.default "drosophila" &&
727                 git remote update &&
728                 git branch -r >output &&
729                 test_cmp expect output
730         )
731 '
732
733 test_expect_success '"remote show" does not show symbolic refs' '
734         git clone one three &&
735         (
736                 cd three &&
737                 git remote show origin >output &&
738                 ! grep "^ *HEAD$" < output &&
739                 ! grep -i stale < output
740         )
741 '
742
743 test_expect_success 'reject adding remote with an invalid name' '
744         test_must_fail git remote add some:url desired-name
745 '
746
747 # The first three test if the tracking branches are properly renamed,
748 # the last two ones check if the config is updated.
749
750 test_expect_success 'rename a remote' '
751         test_config_global remote.pushDefault origin &&
752         git clone one four &&
753         (
754                 cd four &&
755                 git config branch.main.pushRemote origin &&
756                 git remote rename origin upstream &&
757                 test -z "$(git for-each-ref refs/remotes/origin)" &&
758                 test "$(git symbolic-ref refs/remotes/upstream/HEAD)" = "refs/remotes/upstream/main" &&
759                 test "$(git rev-parse upstream/main)" = "$(git rev-parse main)" &&
760                 test "$(git config remote.upstream.fetch)" = "+refs/heads/*:refs/remotes/upstream/*" &&
761                 test "$(git config branch.main.remote)" = "upstream" &&
762                 test "$(git config branch.main.pushRemote)" = "upstream" &&
763                 test "$(git config --global remote.pushDefault)" = "origin"
764         )
765 '
766
767 test_expect_success 'rename a remote renames repo remote.pushDefault' '
768         git clone one four.1 &&
769         (
770                 cd four.1 &&
771                 git config remote.pushDefault origin &&
772                 git remote rename origin upstream &&
773                 test "$(git config --local remote.pushDefault)" = "upstream"
774         )
775 '
776
777 test_expect_success 'rename a remote renames repo remote.pushDefault but ignores global' '
778         test_config_global remote.pushDefault other &&
779         git clone one four.2 &&
780         (
781                 cd four.2 &&
782                 git config remote.pushDefault origin &&
783                 git remote rename origin upstream &&
784                 test "$(git config --global remote.pushDefault)" = "other" &&
785                 test "$(git config --local remote.pushDefault)" = "upstream"
786         )
787 '
788
789 test_expect_success 'rename a remote renames repo remote.pushDefault but keeps global' '
790         test_config_global remote.pushDefault origin &&
791         git clone one four.3 &&
792         (
793                 cd four.3 &&
794                 git config remote.pushDefault origin &&
795                 git remote rename origin upstream &&
796                 test "$(git config --global remote.pushDefault)" = "origin" &&
797                 test "$(git config --local remote.pushDefault)" = "upstream"
798         )
799 '
800
801 test_expect_success 'rename does not update a non-default fetch refspec' '
802         git clone one four.one &&
803         (
804                 cd four.one &&
805                 git config remote.origin.fetch +refs/heads/*:refs/heads/origin/* &&
806                 git remote rename origin upstream &&
807                 test "$(git config remote.upstream.fetch)" = "+refs/heads/*:refs/heads/origin/*" &&
808                 git rev-parse -q origin/main
809         )
810 '
811
812 test_expect_success 'rename a remote with name part of fetch spec' '
813         git clone one four.two &&
814         (
815                 cd four.two &&
816                 git remote rename origin remote &&
817                 git remote rename remote upstream &&
818                 test "$(git config remote.upstream.fetch)" = "+refs/heads/*:refs/remotes/upstream/*"
819         )
820 '
821
822 test_expect_success 'rename a remote with name prefix of other remote' '
823         git clone one four.three &&
824         (
825                 cd four.three &&
826                 git remote add o git://example.com/repo.git &&
827                 git remote rename o upstream &&
828                 test "$(git rev-parse origin/main)" = "$(git rev-parse main)"
829         )
830 '
831
832 test_expect_success 'rename succeeds with existing remote.<target>.prune' '
833         git clone one four.four &&
834         test_when_finished git config --global --unset remote.upstream.prune &&
835         git config --global remote.upstream.prune true &&
836         git -C four.four remote rename origin upstream
837 '
838
839 test_expect_success 'remove a remote' '
840         test_config_global remote.pushDefault origin &&
841         git clone one four.five &&
842         (
843                 cd four.five &&
844                 git config branch.main.pushRemote origin &&
845                 git remote remove origin &&
846                 test -z "$(git for-each-ref refs/remotes/origin)" &&
847                 test_must_fail git config branch.main.remote &&
848                 test_must_fail git config branch.main.pushRemote &&
849                 test "$(git config --global remote.pushDefault)" = "origin"
850         )
851 '
852
853 test_expect_success 'remove a remote removes repo remote.pushDefault' '
854         git clone one four.five.1 &&
855         (
856                 cd four.five.1 &&
857                 git config remote.pushDefault origin &&
858                 git remote remove origin &&
859                 test_must_fail git config --local remote.pushDefault
860         )
861 '
862
863 test_expect_success 'remove a remote removes repo remote.pushDefault but ignores global' '
864         test_config_global remote.pushDefault other &&
865         git clone one four.five.2 &&
866         (
867                 cd four.five.2 &&
868                 git config remote.pushDefault origin &&
869                 git remote remove origin &&
870                 test "$(git config --global remote.pushDefault)" = "other" &&
871                 test_must_fail git config --local remote.pushDefault
872         )
873 '
874
875 test_expect_success 'remove a remote removes repo remote.pushDefault but keeps global' '
876         test_config_global remote.pushDefault origin &&
877         git clone one four.five.3 &&
878         (
879                 cd four.five.3 &&
880                 git config remote.pushDefault origin &&
881                 git remote remove origin &&
882                 test "$(git config --global remote.pushDefault)" = "origin" &&
883                 test_must_fail git config --local remote.pushDefault
884         )
885 '
886
887 cat >remotes_origin <<EOF
888 URL: $(pwd)/one
889 Push: refs/heads/main:refs/heads/upstream
890 Push: refs/heads/next:refs/heads/upstream2
891 Pull: refs/heads/main:refs/heads/origin
892 Pull: refs/heads/next:refs/heads/origin2
893 EOF
894
895 test_expect_success 'migrate a remote from named file in $GIT_DIR/remotes' '
896         git clone one five &&
897         origin_url=$(pwd)/one &&
898         (
899                 cd five &&
900                 git remote remove origin &&
901                 mkdir -p .git/remotes &&
902                 cat ../remotes_origin >.git/remotes/origin &&
903                 git remote rename origin origin &&
904                 test_path_is_missing .git/remotes/origin &&
905                 test "$(git config remote.origin.url)" = "$origin_url" &&
906                 cat >push_expected <<-\EOF &&
907                 refs/heads/main:refs/heads/upstream
908                 refs/heads/next:refs/heads/upstream2
909                 EOF
910                 cat >fetch_expected <<-\EOF &&
911                 refs/heads/main:refs/heads/origin
912                 refs/heads/next:refs/heads/origin2
913                 EOF
914                 git config --get-all remote.origin.push >push_actual &&
915                 git config --get-all remote.origin.fetch >fetch_actual &&
916                 test_cmp push_expected push_actual &&
917                 test_cmp fetch_expected fetch_actual
918         )
919 '
920
921 test_expect_success 'migrate a remote from named file in $GIT_DIR/branches' '
922         git clone one six &&
923         origin_url=$(pwd)/one &&
924         (
925                 cd six &&
926                 git remote rm origin &&
927                 echo "$origin_url#main" >.git/branches/origin &&
928                 git remote rename origin origin &&
929                 test_path_is_missing .git/branches/origin &&
930                 test "$(git config remote.origin.url)" = "$origin_url" &&
931                 test "$(git config remote.origin.fetch)" = "refs/heads/main:refs/heads/origin" &&
932                 test "$(git config remote.origin.push)" = "HEAD:refs/heads/main"
933         )
934 '
935
936 test_expect_success 'migrate a remote from named file in $GIT_DIR/branches (2)' '
937         git clone one seven &&
938         (
939                 cd seven &&
940                 git remote rm origin &&
941                 echo "quux#foom" > .git/branches/origin &&
942                 git remote rename origin origin &&
943                 test_path_is_missing .git/branches/origin &&
944                 test "$(git config remote.origin.url)" = "quux" &&
945                 test "$(git config remote.origin.fetch)" = "refs/heads/foom:refs/heads/origin" &&
946                 test "$(git config remote.origin.push)" = "HEAD:refs/heads/foom"
947         )
948 '
949
950 test_expect_success 'remote prune to cause a dangling symref' '
951         git clone one eight &&
952         (
953                 cd one &&
954                 git checkout side2 &&
955                 git branch -D main
956         ) &&
957         (
958                 cd eight &&
959                 git remote prune origin
960         ) >err 2>&1 &&
961         test_i18ngrep "has become dangling" err &&
962
963         : And the dangling symref will not cause other annoying errors &&
964         (
965                 cd eight &&
966                 git branch -a
967         ) 2>err &&
968         ! grep "points nowhere" err &&
969         (
970                 cd eight &&
971                 test_must_fail git branch nomore origin
972         ) 2>err &&
973         test_i18ngrep "dangling symref" err
974 '
975
976 test_expect_success 'show empty remote' '
977         test_create_repo empty &&
978         git clone empty empty-clone &&
979         (
980                 cd empty-clone &&
981                 git remote show origin
982         )
983 '
984
985 test_expect_success 'remote set-branches requires a remote' '
986         test_must_fail git remote set-branches &&
987         test_must_fail git remote set-branches --add
988 '
989
990 test_expect_success 'remote set-branches' '
991         echo "+refs/heads/*:refs/remotes/scratch/*" >expect.initial &&
992         sort <<-\EOF >expect.add &&
993         +refs/heads/*:refs/remotes/scratch/*
994         +refs/heads/other:refs/remotes/scratch/other
995         EOF
996         sort <<-\EOF >expect.replace &&
997         +refs/heads/maint:refs/remotes/scratch/maint
998         +refs/heads/main:refs/remotes/scratch/main
999         +refs/heads/next:refs/remotes/scratch/next
1000         EOF
1001         sort <<-\EOF >expect.add-two &&
1002         +refs/heads/maint:refs/remotes/scratch/maint
1003         +refs/heads/main:refs/remotes/scratch/main
1004         +refs/heads/next:refs/remotes/scratch/next
1005         +refs/heads/seen:refs/remotes/scratch/seen
1006         +refs/heads/t/topic:refs/remotes/scratch/t/topic
1007         EOF
1008         sort <<-\EOF >expect.setup-ffonly &&
1009         refs/heads/main:refs/remotes/scratch/main
1010         +refs/heads/next:refs/remotes/scratch/next
1011         EOF
1012         sort <<-\EOF >expect.respect-ffonly &&
1013         refs/heads/main:refs/remotes/scratch/main
1014         +refs/heads/next:refs/remotes/scratch/next
1015         +refs/heads/seen:refs/remotes/scratch/seen
1016         EOF
1017
1018         git clone .git/ setbranches &&
1019         (
1020                 cd setbranches &&
1021                 git remote rename origin scratch &&
1022                 git config --get-all remote.scratch.fetch >config-result &&
1023                 sort <config-result >../actual.initial &&
1024
1025                 git remote set-branches scratch --add other &&
1026                 git config --get-all remote.scratch.fetch >config-result &&
1027                 sort <config-result >../actual.add &&
1028
1029                 git remote set-branches scratch maint main next &&
1030                 git config --get-all remote.scratch.fetch >config-result &&
1031                 sort <config-result >../actual.replace &&
1032
1033                 git remote set-branches --add scratch seen t/topic &&
1034                 git config --get-all remote.scratch.fetch >config-result &&
1035                 sort <config-result >../actual.add-two &&
1036
1037                 git config --unset-all remote.scratch.fetch &&
1038                 git config remote.scratch.fetch \
1039                         refs/heads/main:refs/remotes/scratch/main &&
1040                 git config --add remote.scratch.fetch \
1041                         +refs/heads/next:refs/remotes/scratch/next &&
1042                 git config --get-all remote.scratch.fetch >config-result &&
1043                 sort <config-result >../actual.setup-ffonly &&
1044
1045                 git remote set-branches --add scratch seen &&
1046                 git config --get-all remote.scratch.fetch >config-result &&
1047                 sort <config-result >../actual.respect-ffonly
1048         ) &&
1049         test_cmp expect.initial actual.initial &&
1050         test_cmp expect.add actual.add &&
1051         test_cmp expect.replace actual.replace &&
1052         test_cmp expect.add-two actual.add-two &&
1053         test_cmp expect.setup-ffonly actual.setup-ffonly &&
1054         test_cmp expect.respect-ffonly actual.respect-ffonly
1055 '
1056
1057 test_expect_success 'remote set-branches with --mirror' '
1058         echo "+refs/*:refs/*" >expect.initial &&
1059         echo "+refs/heads/main:refs/heads/main" >expect.replace &&
1060         git clone --mirror .git/ setbranches-mirror &&
1061         (
1062                 cd setbranches-mirror &&
1063                 git remote rename origin scratch &&
1064                 git config --get-all remote.scratch.fetch >../actual.initial &&
1065
1066                 git remote set-branches scratch heads/main &&
1067                 git config --get-all remote.scratch.fetch >../actual.replace
1068         ) &&
1069         test_cmp expect.initial actual.initial &&
1070         test_cmp expect.replace actual.replace
1071 '
1072
1073 test_expect_success 'new remote' '
1074         git remote add someremote foo &&
1075         echo foo >expect &&
1076         git config --get-all remote.someremote.url >actual &&
1077         cmp expect actual
1078 '
1079
1080 get_url_test () {
1081         cat >expect &&
1082         git remote get-url "$@" >actual &&
1083         test_cmp expect actual
1084 }
1085
1086 test_expect_success 'get-url on new remote' '
1087         echo foo | get_url_test someremote &&
1088         echo foo | get_url_test --all someremote &&
1089         echo foo | get_url_test --push someremote &&
1090         echo foo | get_url_test --push --all someremote
1091 '
1092
1093 test_expect_success 'remote set-url with locked config' '
1094         test_when_finished "rm -f .git/config.lock" &&
1095         git config --get-all remote.someremote.url >expect &&
1096         >.git/config.lock &&
1097         test_must_fail git remote set-url someremote baz &&
1098         git config --get-all remote.someremote.url >actual &&
1099         cmp expect actual
1100 '
1101
1102 test_expect_success 'remote set-url bar' '
1103         git remote set-url someremote bar &&
1104         echo bar >expect &&
1105         git config --get-all remote.someremote.url >actual &&
1106         cmp expect actual
1107 '
1108
1109 test_expect_success 'remote set-url baz bar' '
1110         git remote set-url someremote baz bar &&
1111         echo baz >expect &&
1112         git config --get-all remote.someremote.url >actual &&
1113         cmp expect actual
1114 '
1115
1116 test_expect_success 'remote set-url zot bar' '
1117         test_must_fail git remote set-url someremote zot bar &&
1118         echo baz >expect &&
1119         git config --get-all remote.someremote.url >actual &&
1120         cmp expect actual
1121 '
1122
1123 test_expect_success 'remote set-url --push zot baz' '
1124         test_must_fail git remote set-url --push someremote zot baz &&
1125         echo "YYY" >expect &&
1126         echo baz >>expect &&
1127         test_must_fail git config --get-all remote.someremote.pushurl >actual &&
1128         echo "YYY" >>actual &&
1129         git config --get-all remote.someremote.url >>actual &&
1130         cmp expect actual
1131 '
1132
1133 test_expect_success 'remote set-url --push zot' '
1134         git remote set-url --push someremote zot &&
1135         echo zot >expect &&
1136         echo "YYY" >>expect &&
1137         echo baz >>expect &&
1138         git config --get-all remote.someremote.pushurl >actual &&
1139         echo "YYY" >>actual &&
1140         git config --get-all remote.someremote.url >>actual &&
1141         cmp expect actual
1142 '
1143
1144 test_expect_success 'get-url with different urls' '
1145         echo baz | get_url_test someremote &&
1146         echo baz | get_url_test --all someremote &&
1147         echo zot | get_url_test --push someremote &&
1148         echo zot | get_url_test --push --all someremote
1149 '
1150
1151 test_expect_success 'remote set-url --push qux zot' '
1152         git remote set-url --push someremote qux zot &&
1153         echo qux >expect &&
1154         echo "YYY" >>expect &&
1155         echo baz >>expect &&
1156         git config --get-all remote.someremote.pushurl >actual &&
1157         echo "YYY" >>actual &&
1158         git config --get-all remote.someremote.url >>actual &&
1159         cmp expect actual
1160 '
1161
1162 test_expect_success 'remote set-url --push foo qu+x' '
1163         git remote set-url --push someremote foo qu+x &&
1164         echo foo >expect &&
1165         echo "YYY" >>expect &&
1166         echo baz >>expect &&
1167         git config --get-all remote.someremote.pushurl >actual &&
1168         echo "YYY" >>actual &&
1169         git config --get-all remote.someremote.url >>actual &&
1170         cmp expect actual
1171 '
1172
1173 test_expect_success 'remote set-url --push --add aaa' '
1174         git remote set-url --push --add someremote aaa &&
1175         echo foo >expect &&
1176         echo aaa >>expect &&
1177         echo "YYY" >>expect &&
1178         echo baz >>expect &&
1179         git config --get-all remote.someremote.pushurl >actual &&
1180         echo "YYY" >>actual &&
1181         git config --get-all remote.someremote.url >>actual &&
1182         cmp expect actual
1183 '
1184
1185 test_expect_success 'get-url on multi push remote' '
1186         echo foo | get_url_test --push someremote &&
1187         get_url_test --push --all someremote <<-\EOF
1188         foo
1189         aaa
1190         EOF
1191 '
1192
1193 test_expect_success 'remote set-url --push bar aaa' '
1194         git remote set-url --push someremote bar aaa &&
1195         echo foo >expect &&
1196         echo bar >>expect &&
1197         echo "YYY" >>expect &&
1198         echo baz >>expect &&
1199         git config --get-all remote.someremote.pushurl >actual &&
1200         echo "YYY" >>actual &&
1201         git config --get-all remote.someremote.url >>actual &&
1202         cmp expect actual
1203 '
1204
1205 test_expect_success 'remote set-url --push --delete bar' '
1206         git remote set-url --push --delete someremote bar &&
1207         echo foo >expect &&
1208         echo "YYY" >>expect &&
1209         echo baz >>expect &&
1210         git config --get-all remote.someremote.pushurl >actual &&
1211         echo "YYY" >>actual &&
1212         git config --get-all remote.someremote.url >>actual &&
1213         cmp expect actual
1214 '
1215
1216 test_expect_success 'remote set-url --push --delete foo' '
1217         git remote set-url --push --delete someremote foo &&
1218         echo "YYY" >expect &&
1219         echo baz >>expect &&
1220         test_must_fail git config --get-all remote.someremote.pushurl >actual &&
1221         echo "YYY" >>actual &&
1222         git config --get-all remote.someremote.url >>actual &&
1223         cmp expect actual
1224 '
1225
1226 test_expect_success 'remote set-url --add bbb' '
1227         git remote set-url --add someremote bbb &&
1228         echo "YYY" >expect &&
1229         echo baz >>expect &&
1230         echo bbb >>expect &&
1231         test_must_fail git config --get-all remote.someremote.pushurl >actual &&
1232         echo "YYY" >>actual &&
1233         git config --get-all remote.someremote.url >>actual &&
1234         cmp expect actual
1235 '
1236
1237 test_expect_success 'get-url on multi fetch remote' '
1238         echo baz | get_url_test someremote &&
1239         get_url_test --all someremote <<-\EOF
1240         baz
1241         bbb
1242         EOF
1243 '
1244
1245 test_expect_success 'remote set-url --delete .*' '
1246         test_must_fail git remote set-url --delete someremote .\* &&
1247         echo "YYY" >expect &&
1248         echo baz >>expect &&
1249         echo bbb >>expect &&
1250         test_must_fail git config --get-all remote.someremote.pushurl >actual &&
1251         echo "YYY" >>actual &&
1252         git config --get-all remote.someremote.url >>actual &&
1253         cmp expect actual
1254 '
1255
1256 test_expect_success 'remote set-url --delete bbb' '
1257         git remote set-url --delete someremote bbb &&
1258         echo "YYY" >expect &&
1259         echo baz >>expect &&
1260         test_must_fail git config --get-all remote.someremote.pushurl >actual &&
1261         echo "YYY" >>actual &&
1262         git config --get-all remote.someremote.url >>actual &&
1263         cmp expect actual
1264 '
1265
1266 test_expect_success 'remote set-url --delete baz' '
1267         test_must_fail git remote set-url --delete someremote baz &&
1268         echo "YYY" >expect &&
1269         echo baz >>expect &&
1270         test_must_fail git config --get-all remote.someremote.pushurl >actual &&
1271         echo "YYY" >>actual &&
1272         git config --get-all remote.someremote.url >>actual &&
1273         cmp expect actual
1274 '
1275
1276 test_expect_success 'remote set-url --add ccc' '
1277         git remote set-url --add someremote ccc &&
1278         echo "YYY" >expect &&
1279         echo baz >>expect &&
1280         echo ccc >>expect &&
1281         test_must_fail git config --get-all remote.someremote.pushurl >actual &&
1282         echo "YYY" >>actual &&
1283         git config --get-all remote.someremote.url >>actual &&
1284         cmp expect actual
1285 '
1286
1287 test_expect_success 'remote set-url --delete baz' '
1288         git remote set-url --delete someremote baz &&
1289         echo "YYY" >expect &&
1290         echo ccc >>expect &&
1291         test_must_fail git config --get-all remote.someremote.pushurl >actual &&
1292         echo "YYY" >>actual &&
1293         git config --get-all remote.someremote.url >>actual &&
1294         cmp expect actual
1295 '
1296
1297 test_expect_success 'extra args: setup' '
1298         # add a dummy origin so that this does not trigger failure
1299         git remote add origin .
1300 '
1301
1302 test_extra_arg () {
1303         test_expect_success "extra args: $*" "
1304                 test_must_fail git remote $* bogus_extra_arg 2>actual &&
1305                 test_i18ngrep '^usage:' actual
1306         "
1307 }
1308
1309 test_extra_arg add nick url
1310 test_extra_arg rename origin newname
1311 test_extra_arg remove origin
1312 test_extra_arg set-head origin main
1313 # set-branches takes any number of args
1314 test_extra_arg get-url origin newurl
1315 test_extra_arg set-url origin newurl oldurl
1316 # show takes any number of args
1317 # prune takes any number of args
1318 # update takes any number of args
1319
1320 test_expect_success 'add remote matching the "insteadOf" URL' '
1321         git config url.xyz@example.com.insteadOf backup &&
1322         git remote add backup xyz@example.com
1323 '
1324
1325 test_expect_success 'unqualified <dst> refspec DWIM and advice' '
1326         test_when_finished "(cd test && git tag -d some-tag)" &&
1327         (
1328                 cd test &&
1329                 git tag -a -m "Some tag" some-tag main &&
1330                 exit_with=true &&
1331                 for type in commit tag tree blob
1332                 do
1333                         if test "$type" = "blob"
1334                         then
1335                                 oid=$(git rev-parse some-tag:file)
1336                         else
1337                                 oid=$(git rev-parse some-tag^{$type})
1338                         fi &&
1339                         test_must_fail git push origin $oid:dst 2>err &&
1340                         test_i18ngrep "error: The destination you" err &&
1341                         test_i18ngrep "hint: Did you mean" err &&
1342                         test_must_fail git -c advice.pushUnqualifiedRefName=false \
1343                                 push origin $oid:dst 2>err &&
1344                         test_i18ngrep "error: The destination you" err &&
1345                         test_i18ngrep ! "hint: Did you mean" err ||
1346                         exit_with=false
1347                 done &&
1348                 $exit_with
1349         )
1350 '
1351
1352 test_expect_success 'refs/remotes/* <src> refspec and unqualified <dst> DWIM and advice' '
1353         (
1354                 cd two &&
1355                 git tag -a -m "Some tag" my-tag main &&
1356                 git update-ref refs/trees/my-head-tree HEAD^{tree} &&
1357                 git update-ref refs/blobs/my-file-blob HEAD:file
1358         ) &&
1359         (
1360                 cd test &&
1361                 git config --add remote.two.fetch "+refs/tags/*:refs/remotes/tags-from-two/*" &&
1362                 git config --add remote.two.fetch "+refs/trees/*:refs/remotes/trees-from-two/*" &&
1363                 git config --add remote.two.fetch "+refs/blobs/*:refs/remotes/blobs-from-two/*" &&
1364                 git fetch --no-tags two &&
1365
1366                 test_must_fail git push origin refs/remotes/two/another:dst 2>err &&
1367                 test_i18ngrep "error: The destination you" err &&
1368
1369                 test_must_fail git push origin refs/remotes/tags-from-two/my-tag:dst-tag 2>err &&
1370                 test_i18ngrep "error: The destination you" err &&
1371
1372                 test_must_fail git push origin refs/remotes/trees-from-two/my-head-tree:dst-tree 2>err &&
1373                 test_i18ngrep "error: The destination you" err &&
1374
1375                 test_must_fail git push origin refs/remotes/blobs-from-two/my-file-blob:dst-blob 2>err &&
1376                 test_i18ngrep "error: The destination you" err
1377         )
1378 '
1379
1380 test_done