Sync with Git 2.30.2 for CVE-2021-21300
[git] / t / t5526-fetch-submodules.sh
1 #!/bin/sh
2 # Copyright (c) 2010, Jens Lehmann
3
4 test_description='Recursive "git fetch" for submodules'
5
6 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master
7 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
8
9 . ./test-lib.sh
10
11 pwd=$(pwd)
12
13 add_upstream_commit() {
14         (
15                 cd submodule &&
16                 head1=$(git rev-parse --short HEAD) &&
17                 echo new >> subfile &&
18                 test_tick &&
19                 git add subfile &&
20                 git commit -m new subfile &&
21                 head2=$(git rev-parse --short HEAD) &&
22                 echo "Fetching submodule submodule" > ../expect.err &&
23                 echo "From $pwd/submodule" >> ../expect.err &&
24                 echo "   $head1..$head2  sub        -> origin/sub" >> ../expect.err
25         ) &&
26         (
27                 cd deepsubmodule &&
28                 head1=$(git rev-parse --short HEAD) &&
29                 echo new >> deepsubfile &&
30                 test_tick &&
31                 git add deepsubfile &&
32                 git commit -m new deepsubfile &&
33                 head2=$(git rev-parse --short HEAD) &&
34                 echo "Fetching submodule submodule/subdir/deepsubmodule" >> ../expect.err
35                 echo "From $pwd/deepsubmodule" >> ../expect.err &&
36                 echo "   $head1..$head2  deep       -> origin/deep" >> ../expect.err
37         )
38 }
39
40 test_expect_success setup '
41         mkdir deepsubmodule &&
42         (
43                 cd deepsubmodule &&
44                 git init &&
45                 echo deepsubcontent > deepsubfile &&
46                 git add deepsubfile &&
47                 git commit -m new deepsubfile &&
48                 git branch -M deep
49         ) &&
50         mkdir submodule &&
51         (
52                 cd submodule &&
53                 git init &&
54                 echo subcontent > subfile &&
55                 git add subfile &&
56                 git submodule add "$pwd/deepsubmodule" subdir/deepsubmodule &&
57                 git commit -a -m new &&
58                 git branch -M sub
59         ) &&
60         git submodule add "$pwd/submodule" submodule &&
61         git commit -am initial &&
62         git branch -M super &&
63         git clone . downstream &&
64         (
65                 cd downstream &&
66                 git submodule update --init --recursive
67         )
68 '
69
70 test_expect_success "fetch --recurse-submodules recurses into submodules" '
71         add_upstream_commit &&
72         (
73                 cd downstream &&
74                 git fetch --recurse-submodules >../actual.out 2>../actual.err
75         ) &&
76         test_must_be_empty actual.out &&
77         test_cmp expect.err actual.err
78 '
79
80 test_expect_success "submodule.recurse option triggers recursive fetch" '
81         add_upstream_commit &&
82         (
83                 cd downstream &&
84                 git -c submodule.recurse fetch >../actual.out 2>../actual.err
85         ) &&
86         test_must_be_empty actual.out &&
87         test_cmp expect.err actual.err
88 '
89
90 test_expect_success "fetch --recurse-submodules -j2 has the same output behaviour" '
91         add_upstream_commit &&
92         (
93                 cd downstream &&
94                 GIT_TRACE="$TRASH_DIRECTORY/trace.out" git fetch --recurse-submodules -j2 2>../actual.err
95         ) &&
96         test_must_be_empty actual.out &&
97         test_cmp expect.err actual.err &&
98         grep "2 tasks" trace.out
99 '
100
101 test_expect_success "fetch alone only fetches superproject" '
102         add_upstream_commit &&
103         (
104                 cd downstream &&
105                 git fetch >../actual.out 2>../actual.err
106         ) &&
107         test_must_be_empty actual.out &&
108         test_must_be_empty actual.err
109 '
110
111 test_expect_success "fetch --no-recurse-submodules only fetches superproject" '
112         (
113                 cd downstream &&
114                 git fetch --no-recurse-submodules >../actual.out 2>../actual.err
115         ) &&
116         test_must_be_empty actual.out &&
117         test_must_be_empty actual.err
118 '
119
120 test_expect_success "using fetchRecurseSubmodules=true in .gitmodules recurses into submodules" '
121         (
122                 cd downstream &&
123                 git config -f .gitmodules submodule.submodule.fetchRecurseSubmodules true &&
124                 git fetch >../actual.out 2>../actual.err
125         ) &&
126         test_must_be_empty actual.out &&
127         test_cmp expect.err actual.err
128 '
129
130 test_expect_success "--no-recurse-submodules overrides .gitmodules config" '
131         add_upstream_commit &&
132         (
133                 cd downstream &&
134                 git fetch --no-recurse-submodules >../actual.out 2>../actual.err
135         ) &&
136         test_must_be_empty actual.out &&
137         test_must_be_empty actual.err
138 '
139
140 test_expect_success "using fetchRecurseSubmodules=false in .git/config overrides setting in .gitmodules" '
141         (
142                 cd downstream &&
143                 git config submodule.submodule.fetchRecurseSubmodules false &&
144                 git fetch >../actual.out 2>../actual.err
145         ) &&
146         test_must_be_empty actual.out &&
147         test_must_be_empty actual.err
148 '
149
150 test_expect_success "--recurse-submodules overrides fetchRecurseSubmodules setting from .git/config" '
151         (
152                 cd downstream &&
153                 git fetch --recurse-submodules >../actual.out 2>../actual.err &&
154                 git config --unset -f .gitmodules submodule.submodule.fetchRecurseSubmodules &&
155                 git config --unset submodule.submodule.fetchRecurseSubmodules
156         ) &&
157         test_must_be_empty actual.out &&
158         test_cmp expect.err actual.err
159 '
160
161 test_expect_success "--quiet propagates to submodules" '
162         (
163                 cd downstream &&
164                 git fetch --recurse-submodules --quiet >../actual.out 2>../actual.err
165         ) &&
166         test_must_be_empty actual.out &&
167         test_must_be_empty actual.err
168 '
169
170 test_expect_success "--quiet propagates to parallel submodules" '
171         (
172                 cd downstream &&
173                 git fetch --recurse-submodules -j 2 --quiet  >../actual.out 2>../actual.err
174         ) &&
175         test_must_be_empty actual.out &&
176         test_must_be_empty actual.err
177 '
178
179 test_expect_success "--dry-run propagates to submodules" '
180         add_upstream_commit &&
181         (
182                 cd downstream &&
183                 git fetch --recurse-submodules --dry-run >../actual.out 2>../actual.err
184         ) &&
185         test_must_be_empty actual.out &&
186         test_cmp expect.err actual.err
187 '
188
189 test_expect_success "Without --dry-run propagates to submodules" '
190         (
191                 cd downstream &&
192                 git fetch --recurse-submodules >../actual.out 2>../actual.err
193         ) &&
194         test_must_be_empty actual.out &&
195         test_cmp expect.err actual.err
196 '
197
198 test_expect_success "recurseSubmodules=true propagates into submodules" '
199         add_upstream_commit &&
200         (
201                 cd downstream &&
202                 git config fetch.recurseSubmodules true &&
203                 git fetch >../actual.out 2>../actual.err
204         ) &&
205         test_must_be_empty actual.out &&
206         test_cmp expect.err actual.err
207 '
208
209 test_expect_success "--recurse-submodules overrides config in submodule" '
210         add_upstream_commit &&
211         (
212                 cd downstream &&
213                 (
214                         cd submodule &&
215                         git config fetch.recurseSubmodules false
216                 ) &&
217                 git fetch --recurse-submodules >../actual.out 2>../actual.err
218         ) &&
219         test_must_be_empty actual.out &&
220         test_cmp expect.err actual.err
221 '
222
223 test_expect_success "--no-recurse-submodules overrides config setting" '
224         add_upstream_commit &&
225         (
226                 cd downstream &&
227                 git config fetch.recurseSubmodules true &&
228                 git fetch --no-recurse-submodules >../actual.out 2>../actual.err
229         ) &&
230         test_must_be_empty actual.out &&
231         test_must_be_empty actual.err
232 '
233
234 test_expect_success "Recursion doesn't happen when no new commits are fetched in the superproject" '
235         (
236                 cd downstream &&
237                 (
238                         cd submodule &&
239                         git config --unset fetch.recurseSubmodules
240                 ) &&
241                 git config --unset fetch.recurseSubmodules &&
242                 git fetch >../actual.out 2>../actual.err
243         ) &&
244         test_must_be_empty actual.out &&
245         test_must_be_empty actual.err
246 '
247
248 test_expect_success "Recursion stops when no new submodule commits are fetched" '
249         head1=$(git rev-parse --short HEAD) &&
250         git add submodule &&
251         git commit -m "new submodule" &&
252         head2=$(git rev-parse --short HEAD) &&
253         echo "From $pwd/." > expect.err.sub &&
254         echo "   $head1..$head2  super      -> origin/super" >>expect.err.sub &&
255         head -3 expect.err >> expect.err.sub &&
256         (
257                 cd downstream &&
258                 git fetch >../actual.out 2>../actual.err
259         ) &&
260         test_cmp expect.err.sub actual.err &&
261         test_must_be_empty actual.out
262 '
263
264 test_expect_success "Recursion doesn't happen when new superproject commits don't change any submodules" '
265         add_upstream_commit &&
266         head1=$(git rev-parse --short HEAD) &&
267         echo a > file &&
268         git add file &&
269         git commit -m "new file" &&
270         head2=$(git rev-parse --short HEAD) &&
271         echo "From $pwd/." > expect.err.file &&
272         echo "   $head1..$head2  super      -> origin/super" >> expect.err.file &&
273         (
274                 cd downstream &&
275                 git fetch >../actual.out 2>../actual.err
276         ) &&
277         test_must_be_empty actual.out &&
278         test_cmp expect.err.file actual.err
279 '
280
281 test_expect_success "Recursion picks up config in submodule" '
282         (
283                 cd downstream &&
284                 git fetch --recurse-submodules &&
285                 (
286                         cd submodule &&
287                         git config fetch.recurseSubmodules true
288                 )
289         ) &&
290         add_upstream_commit &&
291         head1=$(git rev-parse --short HEAD) &&
292         git add submodule &&
293         git commit -m "new submodule" &&
294         head2=$(git rev-parse --short HEAD) &&
295         echo "From $pwd/." > expect.err.sub &&
296         echo "   $head1..$head2  super      -> origin/super" >> expect.err.sub &&
297         cat expect.err >> expect.err.sub &&
298         (
299                 cd downstream &&
300                 git fetch >../actual.out 2>../actual.err &&
301                 (
302                         cd submodule &&
303                         git config --unset fetch.recurseSubmodules
304                 )
305         ) &&
306         test_cmp expect.err.sub actual.err &&
307         test_must_be_empty actual.out
308 '
309
310 test_expect_success "Recursion picks up all submodules when necessary" '
311         add_upstream_commit &&
312         (
313                 cd submodule &&
314                 (
315                         cd subdir/deepsubmodule &&
316                         git fetch &&
317                         git checkout -q FETCH_HEAD
318                 ) &&
319                 head1=$(git rev-parse --short HEAD^) &&
320                 git add subdir/deepsubmodule &&
321                 git commit -m "new deepsubmodule" &&
322                 head2=$(git rev-parse --short HEAD) &&
323                 echo "Fetching submodule submodule" > ../expect.err.sub &&
324                 echo "From $pwd/submodule" >> ../expect.err.sub &&
325                 echo "   $head1..$head2  sub        -> origin/sub" >> ../expect.err.sub
326         ) &&
327         head1=$(git rev-parse --short HEAD) &&
328         git add submodule &&
329         git commit -m "new submodule" &&
330         head2=$(git rev-parse --short HEAD) &&
331         echo "From $pwd/." > expect.err.2 &&
332         echo "   $head1..$head2  super      -> origin/super" >> expect.err.2 &&
333         cat expect.err.sub >> expect.err.2 &&
334         tail -3 expect.err >> expect.err.2 &&
335         (
336                 cd downstream &&
337                 git fetch >../actual.out 2>../actual.err
338         ) &&
339         test_cmp expect.err.2 actual.err &&
340         test_must_be_empty actual.out
341 '
342
343 test_expect_success "'--recurse-submodules=on-demand' doesn't recurse when no new commits are fetched in the superproject (and ignores config)" '
344         add_upstream_commit &&
345         (
346                 cd submodule &&
347                 (
348                         cd subdir/deepsubmodule &&
349                         git fetch &&
350                         git checkout -q FETCH_HEAD
351                 ) &&
352                 head1=$(git rev-parse --short HEAD^) &&
353                 git add subdir/deepsubmodule &&
354                 git commit -m "new deepsubmodule" &&
355                 head2=$(git rev-parse --short HEAD) &&
356                 echo Fetching submodule submodule > ../expect.err.sub &&
357                 echo "From $pwd/submodule" >> ../expect.err.sub &&
358                 echo "   $head1..$head2  sub        -> origin/sub" >> ../expect.err.sub
359         ) &&
360         (
361                 cd downstream &&
362                 git config fetch.recurseSubmodules true &&
363                 git fetch --recurse-submodules=on-demand >../actual.out 2>../actual.err &&
364                 git config --unset fetch.recurseSubmodules
365         ) &&
366         test_must_be_empty actual.out &&
367         test_must_be_empty actual.err
368 '
369
370 test_expect_success "'--recurse-submodules=on-demand' recurses as deep as necessary (and ignores config)" '
371         head1=$(git rev-parse --short HEAD) &&
372         git add submodule &&
373         git commit -m "new submodule" &&
374         head2=$(git rev-parse --short HEAD) &&
375         tail -3 expect.err > expect.err.deepsub &&
376         echo "From $pwd/." > expect.err &&
377         echo "   $head1..$head2  super      -> origin/super" >>expect.err &&
378         cat expect.err.sub >> expect.err &&
379         cat expect.err.deepsub >> expect.err &&
380         (
381                 cd downstream &&
382                 git config fetch.recurseSubmodules false &&
383                 (
384                         cd submodule &&
385                         git config -f .gitmodules submodule.subdir/deepsubmodule.fetchRecursive false
386                 ) &&
387                 git fetch --recurse-submodules=on-demand >../actual.out 2>../actual.err &&
388                 git config --unset fetch.recurseSubmodules &&
389                 (
390                         cd submodule &&
391                         git config --unset -f .gitmodules submodule.subdir/deepsubmodule.fetchRecursive
392                 )
393         ) &&
394         test_must_be_empty actual.out &&
395         test_cmp expect.err actual.err
396 '
397
398 test_expect_success "'--recurse-submodules=on-demand' stops when no new submodule commits are found in the superproject (and ignores config)" '
399         add_upstream_commit &&
400         head1=$(git rev-parse --short HEAD) &&
401         echo a >> file &&
402         git add file &&
403         git commit -m "new file" &&
404         head2=$(git rev-parse --short HEAD) &&
405         echo "From $pwd/." > expect.err.file &&
406         echo "   $head1..$head2  super      -> origin/super" >> expect.err.file &&
407         (
408                 cd downstream &&
409                 git fetch --recurse-submodules=on-demand >../actual.out 2>../actual.err
410         ) &&
411         test_must_be_empty actual.out &&
412         test_cmp expect.err.file actual.err
413 '
414
415 test_expect_success "'fetch.recurseSubmodules=on-demand' overrides global config" '
416         (
417                 cd downstream &&
418                 git fetch --recurse-submodules
419         ) &&
420         add_upstream_commit &&
421         git config --global fetch.recurseSubmodules false &&
422         head1=$(git rev-parse --short HEAD) &&
423         git add submodule &&
424         git commit -m "new submodule" &&
425         head2=$(git rev-parse --short HEAD) &&
426         echo "From $pwd/." > expect.err.2 &&
427         echo "   $head1..$head2  super      -> origin/super" >>expect.err.2 &&
428         head -3 expect.err >> expect.err.2 &&
429         (
430                 cd downstream &&
431                 git config fetch.recurseSubmodules on-demand &&
432                 git fetch >../actual.out 2>../actual.err
433         ) &&
434         git config --global --unset fetch.recurseSubmodules &&
435         (
436                 cd downstream &&
437                 git config --unset fetch.recurseSubmodules
438         ) &&
439         test_must_be_empty actual.out &&
440         test_cmp expect.err.2 actual.err
441 '
442
443 test_expect_success "'submodule.<sub>.fetchRecurseSubmodules=on-demand' overrides fetch.recurseSubmodules" '
444         (
445                 cd downstream &&
446                 git fetch --recurse-submodules
447         ) &&
448         add_upstream_commit &&
449         git config fetch.recurseSubmodules false &&
450         head1=$(git rev-parse --short HEAD) &&
451         git add submodule &&
452         git commit -m "new submodule" &&
453         head2=$(git rev-parse --short HEAD) &&
454         echo "From $pwd/." > expect.err.2 &&
455         echo "   $head1..$head2  super      -> origin/super" >>expect.err.2 &&
456         head -3 expect.err >> expect.err.2 &&
457         (
458                 cd downstream &&
459                 git config submodule.submodule.fetchRecurseSubmodules on-demand &&
460                 git fetch >../actual.out 2>../actual.err
461         ) &&
462         git config --unset fetch.recurseSubmodules &&
463         (
464                 cd downstream &&
465                 git config --unset submodule.submodule.fetchRecurseSubmodules
466         ) &&
467         test_must_be_empty actual.out &&
468         test_cmp expect.err.2 actual.err
469 '
470
471 test_expect_success "don't fetch submodule when newly recorded commits are already present" '
472         (
473                 cd submodule &&
474                 git checkout -q HEAD^^
475         ) &&
476         head1=$(git rev-parse --short HEAD) &&
477         git add submodule &&
478         git commit -m "submodule rewound" &&
479         head2=$(git rev-parse --short HEAD) &&
480         echo "From $pwd/." > expect.err &&
481         echo "   $head1..$head2  super      -> origin/super" >> expect.err &&
482         (
483                 cd downstream &&
484                 git fetch >../actual.out 2>../actual.err
485         ) &&
486         test_must_be_empty actual.out &&
487         test_cmp expect.err actual.err &&
488         (
489                 cd submodule &&
490                 git checkout -q sub
491         )
492 '
493
494 test_expect_success "'fetch.recurseSubmodules=on-demand' works also without .gitmodules entry" '
495         (
496                 cd downstream &&
497                 git fetch --recurse-submodules
498         ) &&
499         add_upstream_commit &&
500         head1=$(git rev-parse --short HEAD) &&
501         git add submodule &&
502         git rm .gitmodules &&
503         git commit -m "new submodule without .gitmodules" &&
504         head2=$(git rev-parse --short HEAD) &&
505         echo "From $pwd/." >expect.err.2 &&
506         echo "   $head1..$head2  super      -> origin/super" >>expect.err.2 &&
507         head -3 expect.err >>expect.err.2 &&
508         (
509                 cd downstream &&
510                 rm .gitmodules &&
511                 git config fetch.recurseSubmodules on-demand &&
512                 # fake submodule configuration to avoid skipping submodule handling
513                 git config -f .gitmodules submodule.fake.path fake &&
514                 git config -f .gitmodules submodule.fake.url fakeurl &&
515                 git add .gitmodules &&
516                 git config --unset submodule.submodule.url &&
517                 git fetch >../actual.out 2>../actual.err &&
518                 # cleanup
519                 git config --unset fetch.recurseSubmodules &&
520                 git reset --hard
521         ) &&
522         test_must_be_empty actual.out &&
523         test_cmp expect.err.2 actual.err &&
524         git checkout HEAD^ -- .gitmodules &&
525         git add .gitmodules &&
526         git commit -m "new submodule restored .gitmodules"
527 '
528
529 test_expect_success 'fetching submodules respects parallel settings' '
530         git config fetch.recurseSubmodules true &&
531         (
532                 cd downstream &&
533                 GIT_TRACE=$(pwd)/trace.out git fetch &&
534                 grep "1 tasks" trace.out &&
535                 GIT_TRACE=$(pwd)/trace.out git fetch --jobs 7 &&
536                 grep "7 tasks" trace.out &&
537                 git config submodule.fetchJobs 8 &&
538                 GIT_TRACE=$(pwd)/trace.out git fetch &&
539                 grep "8 tasks" trace.out &&
540                 GIT_TRACE=$(pwd)/trace.out git fetch --jobs 9 &&
541                 grep "9 tasks" trace.out
542         )
543 '
544
545 test_expect_success 'fetching submodule into a broken repository' '
546         # Prepare src and src/sub nested in it
547         git init src &&
548         (
549                 cd src &&
550                 git init sub &&
551                 git -C sub commit --allow-empty -m "initial in sub" &&
552                 git submodule add -- ./sub sub &&
553                 git commit -m "initial in top"
554         ) &&
555
556         # Clone the old-fashoned way
557         git clone src dst &&
558         git -C dst clone ../src/sub sub &&
559
560         # Make sure that old-fashoned layout is still supported
561         git -C dst status &&
562
563         # "diff" would find no change
564         git -C dst diff --exit-code &&
565
566         # Recursive-fetch works fine
567         git -C dst fetch --recurse-submodules &&
568
569         # Break the receiving submodule
570         rm -f dst/sub/.git/HEAD &&
571
572         # NOTE: without the fix the following tests will recurse forever!
573         # They should terminate with an error.
574
575         test_must_fail git -C dst status &&
576         test_must_fail git -C dst diff &&
577         test_must_fail git -C dst fetch --recurse-submodules
578 '
579
580 test_expect_success "fetch new commits when submodule got renamed" '
581         git clone . downstream_rename &&
582         (
583                 cd downstream_rename &&
584                 git submodule update --init --recursive &&
585                 git checkout -b rename &&
586                 git mv submodule submodule_renamed &&
587                 (
588                         cd submodule_renamed &&
589                         git checkout -b rename_sub &&
590                         echo a >a &&
591                         git add a &&
592                         git commit -ma &&
593                         git push origin rename_sub &&
594                         git rev-parse HEAD >../../expect
595                 ) &&
596                 git add submodule_renamed &&
597                 git commit -m "update renamed submodule" &&
598                 git push origin rename
599         ) &&
600         (
601                 cd downstream &&
602                 git fetch --recurse-submodules=on-demand &&
603                 (
604                         cd submodule &&
605                         git rev-parse origin/rename_sub >../../actual
606                 )
607         ) &&
608         test_cmp expect actual
609 '
610
611 test_expect_success "fetch new submodule commits on-demand outside standard refspec" '
612         # add a second submodule and ensure it is around in downstream first
613         git clone submodule sub1 &&
614         git submodule add ./sub1 &&
615         git commit -m "adding a second submodule" &&
616         git -C downstream pull &&
617         git -C downstream submodule update --init --recursive &&
618
619         git checkout --detach &&
620
621         C=$(git -C submodule commit-tree -m "new change outside refs/heads" HEAD^{tree}) &&
622         git -C submodule update-ref refs/changes/1 $C &&
623         git update-index --cacheinfo 160000 $C submodule &&
624         test_tick &&
625
626         D=$(git -C sub1 commit-tree -m "new change outside refs/heads" HEAD^{tree}) &&
627         git -C sub1 update-ref refs/changes/2 $D &&
628         git update-index --cacheinfo 160000 $D sub1 &&
629
630         git commit -m "updated submodules outside of refs/heads" &&
631         E=$(git rev-parse HEAD) &&
632         git update-ref refs/changes/3 $E &&
633         (
634                 cd downstream &&
635                 git fetch --recurse-submodules origin refs/changes/3:refs/heads/my_branch &&
636                 git -C submodule cat-file -t $C &&
637                 git -C sub1 cat-file -t $D &&
638                 git checkout --recurse-submodules FETCH_HEAD
639         )
640 '
641
642 test_expect_success 'fetch new submodule commit on-demand in FETCH_HEAD' '
643         # depends on the previous test for setup
644
645         C=$(git -C submodule commit-tree -m "another change outside refs/heads" HEAD^{tree}) &&
646         git -C submodule update-ref refs/changes/4 $C &&
647         git update-index --cacheinfo 160000 $C submodule &&
648         test_tick &&
649
650         D=$(git -C sub1 commit-tree -m "another change outside refs/heads" HEAD^{tree}) &&
651         git -C sub1 update-ref refs/changes/5 $D &&
652         git update-index --cacheinfo 160000 $D sub1 &&
653
654         git commit -m "updated submodules outside of refs/heads" &&
655         E=$(git rev-parse HEAD) &&
656         git update-ref refs/changes/6 $E &&
657         (
658                 cd downstream &&
659                 git fetch --recurse-submodules origin refs/changes/6 &&
660                 git -C submodule cat-file -t $C &&
661                 git -C sub1 cat-file -t $D &&
662                 git checkout --recurse-submodules FETCH_HEAD
663         )
664 '
665
666 test_expect_success 'fetch new submodule commits on-demand without .gitmodules entry' '
667         # depends on the previous test for setup
668
669         git config -f .gitmodules --remove-section submodule.sub1 &&
670         git add .gitmodules &&
671         git commit -m "delete gitmodules file" &&
672         git checkout -B super &&
673         git -C downstream fetch &&
674         git -C downstream checkout origin/super &&
675
676         C=$(git -C submodule commit-tree -m "yet another change outside refs/heads" HEAD^{tree}) &&
677         git -C submodule update-ref refs/changes/7 $C &&
678         git update-index --cacheinfo 160000 $C submodule &&
679         test_tick &&
680
681         D=$(git -C sub1 commit-tree -m "yet another change outside refs/heads" HEAD^{tree}) &&
682         git -C sub1 update-ref refs/changes/8 $D &&
683         git update-index --cacheinfo 160000 $D sub1 &&
684
685         git commit -m "updated submodules outside of refs/heads" &&
686         E=$(git rev-parse HEAD) &&
687         git update-ref refs/changes/9 $E &&
688         (
689                 cd downstream &&
690                 git fetch --recurse-submodules origin refs/changes/9 &&
691                 git -C submodule cat-file -t $C &&
692                 git -C sub1 cat-file -t $D &&
693                 git checkout --recurse-submodules FETCH_HEAD
694         )
695 '
696
697 test_expect_success 'fetch new submodule commit intermittently referenced by superproject' '
698         # depends on the previous test for setup
699
700         D=$(git -C sub1 commit-tree -m "change 10 outside refs/heads" HEAD^{tree}) &&
701         E=$(git -C sub1 commit-tree -m "change 11 outside refs/heads" HEAD^{tree}) &&
702         F=$(git -C sub1 commit-tree -m "change 12 outside refs/heads" HEAD^{tree}) &&
703
704         git -C sub1 update-ref refs/changes/10 $D &&
705         git update-index --cacheinfo 160000 $D sub1 &&
706         git commit -m "updated submodules outside of refs/heads" &&
707
708         git -C sub1 update-ref refs/changes/11 $E &&
709         git update-index --cacheinfo 160000 $E sub1 &&
710         git commit -m "updated submodules outside of refs/heads" &&
711
712         git -C sub1 update-ref refs/changes/12 $F &&
713         git update-index --cacheinfo 160000 $F sub1 &&
714         git commit -m "updated submodules outside of refs/heads" &&
715
716         G=$(git rev-parse HEAD) &&
717         git update-ref refs/changes/13 $G &&
718         (
719                 cd downstream &&
720                 git fetch --recurse-submodules origin refs/changes/13 &&
721
722                 git -C sub1 cat-file -t $D &&
723                 git -C sub1 cat-file -t $E &&
724                 git -C sub1 cat-file -t $F
725         )
726 '
727
728 add_commit_push () {
729         dir="$1" &&
730         msg="$2" &&
731         shift 2 &&
732         git -C "$dir" add "$@" &&
733         git -C "$dir" commit -a -m "$msg" &&
734         git -C "$dir" push
735 }
736
737 compare_refs_in_dir () {
738         fail= &&
739         if test "x$1" = 'x!'
740         then
741                 fail='!' &&
742                 shift
743         fi &&
744         git -C "$1" rev-parse --verify "$2" >expect &&
745         git -C "$3" rev-parse --verify "$4" >actual &&
746         eval $fail test_cmp expect actual
747 }
748
749
750 test_expect_success 'setup nested submodule fetch test' '
751         # does not depend on any previous test setups
752
753         for repo in outer middle inner
754         do
755                 git init --bare $repo &&
756                 git clone $repo ${repo}_content &&
757                 echo "$repo" >"${repo}_content/file" &&
758                 add_commit_push ${repo}_content "initial" file ||
759                 return 1
760         done &&
761
762         git clone outer A &&
763         git -C A submodule add "$pwd/middle" &&
764         git -C A/middle/ submodule add "$pwd/inner" &&
765         add_commit_push A/middle/ "adding inner sub" .gitmodules inner &&
766         add_commit_push A/ "adding middle sub" .gitmodules middle &&
767
768         git clone outer B &&
769         git -C B/ submodule update --init middle &&
770
771         compare_refs_in_dir A HEAD B HEAD &&
772         compare_refs_in_dir A/middle HEAD B/middle HEAD &&
773         test_path_is_file B/file &&
774         test_path_is_file B/middle/file &&
775         test_path_is_missing B/middle/inner/file &&
776
777         echo "change on inner repo of A" >"A/middle/inner/file" &&
778         add_commit_push A/middle/inner "change on inner" file &&
779         add_commit_push A/middle "change on inner" inner &&
780         add_commit_push A "change on inner" middle
781 '
782
783 test_expect_success 'fetching a superproject containing an uninitialized sub/sub project' '
784         # depends on previous test for setup
785
786         git -C B/ fetch &&
787         compare_refs_in_dir A origin/HEAD B origin/HEAD
788 '
789
790 fetch_with_recursion_abort () {
791         # In a regression the following git call will run into infinite recursion.
792         # To handle that, we connect the sed command to the git call by a pipe
793         # so that sed can kill the infinite recursion when detected.
794         # The recursion creates git output like:
795         # Fetching submodule sub
796         # Fetching submodule sub/sub              <-- [1]
797         # Fetching submodule sub/sub/sub
798         # ...
799         # [1] sed will stop reading and cause git to eventually stop and die
800
801         git -C "$1" fetch --recurse-submodules 2>&1 |
802                 sed "/Fetching submodule $2[^$]/q" >out &&
803         ! grep "Fetching submodule $2[^$]" out
804 }
805
806 test_expect_success 'setup recursive fetch with uninit submodule' '
807         # does not depend on any previous test setups
808
809         test_create_repo super &&
810         test_commit -C super initial &&
811         test_create_repo sub &&
812         test_commit -C sub initial &&
813         git -C sub rev-parse HEAD >expect &&
814
815         git -C super submodule add ../sub &&
816         git -C super commit -m "add sub" &&
817
818         git clone super superclone &&
819         git -C superclone submodule status >out &&
820         sed -e "s/^-//" -e "s/ sub.*$//" out >actual &&
821         test_cmp expect actual
822 '
823
824 test_expect_success 'recursive fetch with uninit submodule' '
825         # depends on previous test for setup
826
827         fetch_with_recursion_abort superclone sub &&
828         git -C superclone submodule status >out &&
829         sed -e "s/^-//" -e "s/ sub$//" out >actual &&
830         test_cmp expect actual
831 '
832
833 test_expect_success 'recursive fetch after deinit a submodule' '
834         # depends on previous test for setup
835
836         git -C superclone submodule update --init sub &&
837         git -C superclone submodule deinit -f sub &&
838
839         fetch_with_recursion_abort superclone sub &&
840         git -C superclone submodule status >out &&
841         sed -e "s/^-//" -e "s/ sub$//" out >actual &&
842         test_cmp expect actual
843 '
844
845 test_done