Sync with 'maint'
[git] / t / t5510-fetch.sh
1 #!/bin/sh
2 # Copyright (c) 2006, Junio C Hamano.
3
4 test_description='Per branch config variables affects "git fetch".
5
6 '
7
8 . ./test-lib.sh
9
10 D=`pwd`
11
12 test_bundle_object_count () {
13         git verify-pack -v "$1" >verify.out &&
14         test "$2" = $(grep '^[0-9a-f]\{40\} ' verify.out | wc -l)
15 }
16
17 convert_bundle_to_pack () {
18         while read x && test -n "$x"
19         do
20                 :;
21         done
22         cat
23 }
24
25 test_expect_success setup '
26         echo >file original &&
27         git add file &&
28         git commit -a -m original'
29
30 test_expect_success "clone and setup child repos" '
31         git clone . one &&
32         (
33                 cd one &&
34                 echo >file updated by one &&
35                 git commit -a -m "updated by one"
36         ) &&
37         git clone . two &&
38         (
39                 cd two &&
40                 git config branch.master.remote one &&
41                 git config remote.one.url ../one/.git/ &&
42                 git config remote.one.fetch refs/heads/master:refs/heads/one
43         ) &&
44         git clone . three &&
45         (
46                 cd three &&
47                 git config branch.master.remote two &&
48                 git config branch.master.merge refs/heads/one &&
49                 mkdir -p .git/remotes &&
50                 {
51                         echo "URL: ../two/.git/"
52                         echo "Pull: refs/heads/master:refs/heads/two"
53                         echo "Pull: refs/heads/one:refs/heads/one"
54                 } >.git/remotes/two
55         ) &&
56         git clone . bundle &&
57         git clone . seven
58 '
59
60 test_expect_success "fetch test" '
61         cd "$D" &&
62         echo >file updated by origin &&
63         git commit -a -m "updated by origin" &&
64         cd two &&
65         git fetch &&
66         test -f .git/refs/heads/one &&
67         mine=`git rev-parse refs/heads/one` &&
68         his=`cd ../one && git rev-parse refs/heads/master` &&
69         test "z$mine" = "z$his"
70 '
71
72 test_expect_success "fetch test for-merge" '
73         cd "$D" &&
74         cd three &&
75         git fetch &&
76         test -f .git/refs/heads/two &&
77         test -f .git/refs/heads/one &&
78         master_in_two=`cd ../two && git rev-parse master` &&
79         one_in_two=`cd ../two && git rev-parse one` &&
80         {
81                 echo "$one_in_two       "
82                 echo "$master_in_two    not-for-merge"
83         } >expected &&
84         cut -f -2 .git/FETCH_HEAD >actual &&
85         test_cmp expected actual'
86
87 test_expect_success 'fetch --prune on its own works as expected' '
88         cd "$D" &&
89         git clone . prune &&
90         cd prune &&
91         git fetch origin refs/heads/master:refs/remotes/origin/extrabranch &&
92
93         git fetch --prune origin &&
94         test_must_fail git rev-parse origin/extrabranch
95 '
96
97 test_expect_success 'fetch --prune with a branch name keeps branches' '
98         cd "$D" &&
99         git clone . prune-branch &&
100         cd prune-branch &&
101         git fetch origin refs/heads/master:refs/remotes/origin/extrabranch &&
102
103         git fetch --prune origin master &&
104         git rev-parse origin/extrabranch
105 '
106
107 test_expect_success 'fetch --prune with a namespace keeps other namespaces' '
108         cd "$D" &&
109         git clone . prune-namespace &&
110         cd prune-namespace &&
111
112         git fetch --prune origin refs/heads/a/*:refs/remotes/origin/a/* &&
113         git rev-parse origin/master
114 '
115
116 test_expect_success 'fetch --prune --tags does not delete the remote-tracking branches' '
117         cd "$D" &&
118         git clone . prune-tags &&
119         cd prune-tags &&
120         git fetch origin refs/heads/master:refs/tags/sometag &&
121
122         git fetch --prune --tags origin &&
123         git rev-parse origin/master &&
124         test_must_fail git rev-parse somebranch
125 '
126
127 test_expect_success 'fetch --prune --tags with branch does not delete other remote-tracking branches' '
128         cd "$D" &&
129         git clone . prune-tags-branch &&
130         cd prune-tags-branch &&
131         git fetch origin refs/heads/master:refs/remotes/origin/extrabranch &&
132
133         git fetch --prune --tags origin master &&
134         git rev-parse origin/extrabranch
135 '
136
137 test_expect_success 'fetch tags when there is no tags' '
138
139     cd "$D" &&
140
141     mkdir notags &&
142     cd notags &&
143     git init &&
144
145     git fetch -t ..
146
147 '
148
149 test_expect_success 'fetch following tags' '
150
151         cd "$D" &&
152         git tag -a -m 'annotated' anno HEAD &&
153         git tag light HEAD &&
154
155         mkdir four &&
156         cd four &&
157         git init &&
158
159         git fetch .. :track &&
160         git show-ref --verify refs/tags/anno &&
161         git show-ref --verify refs/tags/light
162
163 '
164
165 test_expect_success 'fetch uses remote ref names to describe new refs' '
166         cd "$D" &&
167         git init descriptive &&
168         (
169                 cd descriptive &&
170                 git config remote.o.url .. &&
171                 git config remote.o.fetch "refs/heads/*:refs/crazyheads/*" &&
172                 git config --add remote.o.fetch "refs/others/*:refs/heads/*" &&
173                 git fetch o
174         ) &&
175         git tag -a -m "Descriptive tag" descriptive-tag &&
176         git branch descriptive-branch &&
177         git checkout descriptive-branch &&
178         echo "Nuts" >crazy &&
179         git add crazy &&
180         git commit -a -m "descriptive commit" &&
181         git update-ref refs/others/crazy HEAD &&
182         (
183                 cd descriptive &&
184                 git fetch o 2>actual &&
185                 grep " -> refs/crazyheads/descriptive-branch$" actual |
186                 test_i18ngrep "new branch" &&
187                 grep " -> descriptive-tag$" actual |
188                 test_i18ngrep "new tag" &&
189                 grep " -> crazy$" actual |
190                 test_i18ngrep "new ref"
191         ) &&
192         git checkout master
193 '
194
195 test_expect_success 'fetch must not resolve short tag name' '
196
197         cd "$D" &&
198
199         mkdir five &&
200         cd five &&
201         git init &&
202
203         test_must_fail git fetch .. anno:five
204
205 '
206
207 test_expect_success 'fetch can now resolve short remote name' '
208
209         cd "$D" &&
210         git update-ref refs/remotes/six/HEAD HEAD &&
211
212         mkdir six &&
213         cd six &&
214         git init &&
215
216         git fetch .. six:six
217 '
218
219 test_expect_success 'create bundle 1' '
220         cd "$D" &&
221         echo >file updated again by origin &&
222         git commit -a -m "tip" &&
223         git bundle create bundle1 master^..master
224 '
225
226 test_expect_success 'header of bundle looks right' '
227         head -n 1 "$D"/bundle1 | grep "^#" &&
228         head -n 2 "$D"/bundle1 | grep "^-[0-9a-f]\{40\} " &&
229         head -n 3 "$D"/bundle1 | grep "^[0-9a-f]\{40\} " &&
230         head -n 4 "$D"/bundle1 | grep "^$"
231 '
232
233 test_expect_success 'create bundle 2' '
234         cd "$D" &&
235         git bundle create bundle2 master~2..master
236 '
237
238 test_expect_success 'unbundle 1' '
239         cd "$D/bundle" &&
240         git checkout -b some-branch &&
241         test_must_fail git fetch "$D/bundle1" master:master
242 '
243
244
245 test_expect_success 'bundle 1 has only 3 files ' '
246         cd "$D" &&
247         convert_bundle_to_pack <bundle1 >bundle.pack &&
248         git index-pack bundle.pack &&
249         test_bundle_object_count bundle.pack 3
250 '
251
252 test_expect_success 'unbundle 2' '
253         cd "$D/bundle" &&
254         git fetch ../bundle2 master:master &&
255         test "tip" = "$(git log -1 --pretty=oneline master | cut -b42-)"
256 '
257
258 test_expect_success 'bundle does not prerequisite objects' '
259         cd "$D" &&
260         touch file2 &&
261         git add file2 &&
262         git commit -m add.file2 file2 &&
263         git bundle create bundle3 -1 HEAD &&
264         convert_bundle_to_pack <bundle3 >bundle.pack &&
265         git index-pack bundle.pack &&
266         test_bundle_object_count bundle.pack 3
267 '
268
269 test_expect_success 'bundle should be able to create a full history' '
270
271         cd "$D" &&
272         git tag -a -m '1.0' v1.0 master &&
273         git bundle create bundle4 v1.0
274
275 '
276
277 ! rsync --help > /dev/null 2> /dev/null &&
278 say 'Skipping rsync tests because rsync was not found' || {
279 test_expect_success 'fetch via rsync' '
280         git pack-refs &&
281         mkdir rsynced &&
282         (cd rsynced &&
283          git init --bare &&
284          git fetch "rsync:$(pwd)/../.git" master:refs/heads/master &&
285          git gc --prune &&
286          test $(git rev-parse master) = $(cd .. && git rev-parse master) &&
287          git fsck --full)
288 '
289
290 test_expect_success 'push via rsync' '
291         mkdir rsynced2 &&
292         (cd rsynced2 &&
293          git init) &&
294         (cd rsynced &&
295          git push "rsync:$(pwd)/../rsynced2/.git" master) &&
296         (cd rsynced2 &&
297          git gc --prune &&
298          test $(git rev-parse master) = $(cd .. && git rev-parse master) &&
299          git fsck --full)
300 '
301
302 test_expect_success 'push via rsync' '
303         mkdir rsynced3 &&
304         (cd rsynced3 &&
305          git init) &&
306         git push --all "rsync:$(pwd)/rsynced3/.git" &&
307         (cd rsynced3 &&
308          test $(git rev-parse master) = $(cd .. && git rev-parse master) &&
309          git fsck --full)
310 '
311 }
312
313 test_expect_success 'fetch with a non-applying branch.<name>.merge' '
314         git config branch.master.remote yeti &&
315         git config branch.master.merge refs/heads/bigfoot &&
316         git config remote.blub.url one &&
317         git config remote.blub.fetch "refs/heads/*:refs/remotes/one/*" &&
318         git fetch blub
319 '
320
321 # URL supplied to fetch does not match the url of the configured branch's remote
322 test_expect_success 'fetch from GIT URL with a non-applying branch.<name>.merge [1]' '
323         one_head=$(cd one && git rev-parse HEAD) &&
324         this_head=$(git rev-parse HEAD) &&
325         git update-ref -d FETCH_HEAD &&
326         git fetch one &&
327         test $one_head = "$(git rev-parse --verify FETCH_HEAD)" &&
328         test $this_head = "$(git rev-parse --verify HEAD)"
329 '
330
331 # URL supplied to fetch matches the url of the configured branch's remote and
332 # the merge spec matches the branch the remote HEAD points to
333 test_expect_success 'fetch from GIT URL with a non-applying branch.<name>.merge [2]' '
334         one_ref=$(cd one && git symbolic-ref HEAD) &&
335         git config branch.master.remote blub &&
336         git config branch.master.merge "$one_ref" &&
337         git update-ref -d FETCH_HEAD &&
338         git fetch one &&
339         test $one_head = "$(git rev-parse --verify FETCH_HEAD)" &&
340         test $this_head = "$(git rev-parse --verify HEAD)"
341 '
342
343 # URL supplied to fetch matches the url of the configured branch's remote, but
344 # the merge spec does not match the branch the remote HEAD points to
345 test_expect_success 'fetch from GIT URL with a non-applying branch.<name>.merge [3]' '
346         git config branch.master.merge "${one_ref}_not" &&
347         git update-ref -d FETCH_HEAD &&
348         git fetch one &&
349         test $one_head = "$(git rev-parse --verify FETCH_HEAD)" &&
350         test $this_head = "$(git rev-parse --verify HEAD)"
351 '
352
353 # the strange name is: a\!'b
354 test_expect_success 'quoting of a strangely named repo' '
355         test_must_fail git fetch "a\\!'\''b" > result 2>&1 &&
356         cat result &&
357         grep "fatal: '\''a\\\\!'\''b'\''" result
358 '
359
360 test_expect_success 'bundle should record HEAD correctly' '
361
362         cd "$D" &&
363         git bundle create bundle5 HEAD master &&
364         git bundle list-heads bundle5 >actual &&
365         for h in HEAD refs/heads/master
366         do
367                 echo "$(git rev-parse --verify $h) $h"
368         done >expect &&
369         test_cmp expect actual
370
371 '
372
373 test_expect_success 'mark initial state of origin/master' '
374         (
375                 cd three &&
376                 git tag base-origin-master refs/remotes/origin/master
377         )
378 '
379
380 test_expect_success 'explicit fetch should update tracking' '
381
382         cd "$D" &&
383         git branch -f side &&
384         (
385                 cd three &&
386                 git update-ref refs/remotes/origin/master base-origin-master &&
387                 o=$(git rev-parse --verify refs/remotes/origin/master) &&
388                 git fetch origin master &&
389                 n=$(git rev-parse --verify refs/remotes/origin/master) &&
390                 test "$o" != "$n" &&
391                 test_must_fail git rev-parse --verify refs/remotes/origin/side
392         )
393 '
394
395 test_expect_success 'explicit pull should update tracking' '
396
397         cd "$D" &&
398         git branch -f side &&
399         (
400                 cd three &&
401                 git update-ref refs/remotes/origin/master base-origin-master &&
402                 o=$(git rev-parse --verify refs/remotes/origin/master) &&
403                 git pull origin master &&
404                 n=$(git rev-parse --verify refs/remotes/origin/master) &&
405                 test "$o" != "$n" &&
406                 test_must_fail git rev-parse --verify refs/remotes/origin/side
407         )
408 '
409
410 test_expect_success 'configured fetch updates tracking' '
411
412         cd "$D" &&
413         git branch -f side &&
414         (
415                 cd three &&
416                 git update-ref refs/remotes/origin/master base-origin-master &&
417                 o=$(git rev-parse --verify refs/remotes/origin/master) &&
418                 git fetch origin &&
419                 n=$(git rev-parse --verify refs/remotes/origin/master) &&
420                 test "$o" != "$n" &&
421                 git rev-parse --verify refs/remotes/origin/side
422         )
423 '
424
425 test_expect_success 'non-matching refspecs do not confuse tracking update' '
426         cd "$D" &&
427         git update-ref refs/odd/location HEAD &&
428         (
429                 cd three &&
430                 git update-ref refs/remotes/origin/master base-origin-master &&
431                 git config --add remote.origin.fetch \
432                         refs/odd/location:refs/remotes/origin/odd &&
433                 o=$(git rev-parse --verify refs/remotes/origin/master) &&
434                 git fetch origin master &&
435                 n=$(git rev-parse --verify refs/remotes/origin/master) &&
436                 test "$o" != "$n" &&
437                 test_must_fail git rev-parse --verify refs/remotes/origin/odd
438         )
439 '
440
441 test_expect_success 'pushing nonexistent branch by mistake should not segv' '
442
443         cd "$D" &&
444         test_must_fail git push seven no:no
445
446 '
447
448 test_expect_success 'auto tag following fetches minimum' '
449
450         cd "$D" &&
451         git clone .git follow &&
452         git checkout HEAD^0 &&
453         (
454                 for i in 1 2 3 4 5 6 7
455                 do
456                         echo $i >>file &&
457                         git commit -m $i -a &&
458                         git tag -a -m $i excess-$i || exit 1
459                 done
460         ) &&
461         git checkout master &&
462         (
463                 cd follow &&
464                 git fetch
465         )
466 '
467
468 test_expect_success 'refuse to fetch into the current branch' '
469
470         test_must_fail git fetch . side:master
471
472 '
473
474 test_expect_success 'fetch into the current branch with --update-head-ok' '
475
476         git fetch --update-head-ok . side:master
477
478 '
479
480 test_expect_success 'fetch --dry-run' '
481
482         rm -f .git/FETCH_HEAD &&
483         git fetch --dry-run . &&
484         ! test -f .git/FETCH_HEAD
485 '
486
487 test_expect_success "should be able to fetch with duplicate refspecs" '
488         mkdir dups &&
489         (
490                 cd dups &&
491                 git init &&
492                 git config branch.master.remote three &&
493                 git config remote.three.url ../three/.git &&
494                 git config remote.three.fetch +refs/heads/*:refs/remotes/origin/* &&
495                 git config --add remote.three.fetch +refs/heads/*:refs/remotes/origin/* &&
496                 git fetch three
497         )
498 '
499
500 # configured prune tests
501
502 set_config_tristate () {
503         # var=$1 val=$2
504         case "$2" in
505         unset)  test_unconfig "$1" ;;
506         *)      git config "$1" "$2" ;;
507         esac
508 }
509
510 test_configured_prune () {
511         fetch_prune=$1 remote_origin_prune=$2 cmdline=$3 expected=$4
512
513         test_expect_success "prune fetch.prune=$1 remote.origin.prune=$2${3:+ $3}; $4" '
514                 # make sure a newbranch is there in . and also in one
515                 git branch -f newbranch &&
516                 (
517                         cd one &&
518                         test_unconfig fetch.prune &&
519                         test_unconfig remote.origin.prune &&
520                         git fetch &&
521                         git rev-parse --verify refs/remotes/origin/newbranch
522                 )
523
524                 # now remove it
525                 git branch -d newbranch &&
526
527                 # then test
528                 (
529                         cd one &&
530                         set_config_tristate fetch.prune $fetch_prune &&
531                         set_config_tristate remote.origin.prune $remote_origin_prune &&
532
533                         git fetch $cmdline &&
534                         case "$expected" in
535                         pruned)
536                                 test_must_fail git rev-parse --verify refs/remotes/origin/newbranch
537                                 ;;
538                         kept)
539                                 git rev-parse --verify refs/remotes/origin/newbranch
540                                 ;;
541                         esac
542                 )
543         '
544 }
545
546 test_configured_prune unset unset ""            kept
547 test_configured_prune unset unset "--no-prune"  kept
548 test_configured_prune unset unset "--prune"     pruned
549
550 test_configured_prune false unset ""            kept
551 test_configured_prune false unset "--no-prune"  kept
552 test_configured_prune false unset "--prune"     pruned
553
554 test_configured_prune true  unset ""            pruned
555 test_configured_prune true  unset "--prune"     pruned
556 test_configured_prune true  unset "--no-prune"  kept
557
558 test_configured_prune unset false ""            kept
559 test_configured_prune unset false "--no-prune"  kept
560 test_configured_prune unset false "--prune"     pruned
561
562 test_configured_prune false false ""            kept
563 test_configured_prune false false "--no-prune"  kept
564 test_configured_prune false false "--prune"     pruned
565
566 test_configured_prune true  false ""            kept
567 test_configured_prune true  false "--prune"     pruned
568 test_configured_prune true  false "--no-prune"  kept
569
570 test_configured_prune unset true  ""            pruned
571 test_configured_prune unset true  "--no-prune"  kept
572 test_configured_prune unset true  "--prune"     pruned
573
574 test_configured_prune false true  ""            pruned
575 test_configured_prune false true  "--no-prune"  kept
576 test_configured_prune false true  "--prune"     pruned
577
578 test_configured_prune true  true  ""            pruned
579 test_configured_prune true  true  "--prune"     pruned
580 test_configured_prune true  true  "--no-prune"  kept
581
582 test_expect_success 'all boundary commits are excluded' '
583         test_commit base &&
584         test_commit oneside &&
585         git checkout HEAD^ &&
586         test_commit otherside &&
587         git checkout master &&
588         test_tick &&
589         git merge otherside &&
590         ad=$(git log --no-walk --format=%ad HEAD) &&
591         git bundle create twoside-boundary.bdl master --since="$ad" &&
592         convert_bundle_to_pack <twoside-boundary.bdl >twoside-boundary.pack &&
593         pack=$(git index-pack --fix-thin --stdin <twoside-boundary.pack) &&
594         test_bundle_object_count .git/objects/pack/pack-${pack##pack    }.pack 3
595 '
596
597 test_done