describe: teach --match to handle branches and remotes
[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 . ./test-lib.sh
7
8 pwd=$(pwd)
9
10 add_upstream_commit() {
11         (
12                 cd submodule &&
13                 head1=$(git rev-parse --short HEAD) &&
14                 echo new >> subfile &&
15                 test_tick &&
16                 git add subfile &&
17                 git commit -m new subfile &&
18                 head2=$(git rev-parse --short HEAD) &&
19                 echo "Fetching submodule submodule" > ../expect.err &&
20                 echo "From $pwd/submodule" >> ../expect.err &&
21                 echo "   $head1..$head2  master     -> origin/master" >> ../expect.err
22         ) &&
23         (
24                 cd deepsubmodule &&
25                 head1=$(git rev-parse --short HEAD) &&
26                 echo new >> deepsubfile &&
27                 test_tick &&
28                 git add deepsubfile &&
29                 git commit -m new deepsubfile &&
30                 head2=$(git rev-parse --short HEAD) &&
31                 echo "Fetching submodule submodule/subdir/deepsubmodule" >> ../expect.err
32                 echo "From $pwd/deepsubmodule" >> ../expect.err &&
33                 echo "   $head1..$head2  master     -> origin/master" >> ../expect.err
34         )
35 }
36
37 test_expect_success setup '
38         mkdir deepsubmodule &&
39         (
40                 cd deepsubmodule &&
41                 git init &&
42                 echo deepsubcontent > deepsubfile &&
43                 git add deepsubfile &&
44                 git commit -m new deepsubfile
45         ) &&
46         mkdir submodule &&
47         (
48                 cd submodule &&
49                 git init &&
50                 echo subcontent > subfile &&
51                 git add subfile &&
52                 git submodule add "$pwd/deepsubmodule" subdir/deepsubmodule &&
53                 git commit -a -m new
54         ) &&
55         git submodule add "$pwd/submodule" submodule &&
56         git commit -am initial &&
57         git clone . downstream &&
58         (
59                 cd downstream &&
60                 git submodule update --init --recursive
61         )
62 '
63
64 test_expect_success "fetch --recurse-submodules recurses into submodules" '
65         add_upstream_commit &&
66         (
67                 cd downstream &&
68                 git fetch --recurse-submodules >../actual.out 2>../actual.err
69         ) &&
70         test_must_be_empty actual.out &&
71         test_i18ncmp expect.err actual.err
72 '
73
74 test_expect_success "submodule.recurse option triggers recursive fetch" '
75         add_upstream_commit &&
76         (
77                 cd downstream &&
78                 git -c submodule.recurse fetch >../actual.out 2>../actual.err
79         ) &&
80         test_must_be_empty actual.out &&
81         test_i18ncmp expect.err actual.err
82 '
83
84 test_expect_success "fetch --recurse-submodules -j2 has the same output behaviour" '
85         add_upstream_commit &&
86         (
87                 cd downstream &&
88                 GIT_TRACE=$(pwd)/../trace.out git fetch --recurse-submodules -j2 2>../actual.err
89         ) &&
90         test_must_be_empty actual.out &&
91         test_i18ncmp expect.err actual.err &&
92         grep "2 tasks" trace.out
93 '
94
95 test_expect_success "fetch alone only fetches superproject" '
96         add_upstream_commit &&
97         (
98                 cd downstream &&
99                 git fetch >../actual.out 2>../actual.err
100         ) &&
101         ! test -s actual.out &&
102         ! test -s actual.err
103 '
104
105 test_expect_success "fetch --no-recurse-submodules only fetches superproject" '
106         (
107                 cd downstream &&
108                 git fetch --no-recurse-submodules >../actual.out 2>../actual.err
109         ) &&
110         ! test -s actual.out &&
111         ! test -s actual.err
112 '
113
114 test_expect_success "using fetchRecurseSubmodules=true in .gitmodules recurses into submodules" '
115         (
116                 cd downstream &&
117                 git config -f .gitmodules submodule.submodule.fetchRecurseSubmodules true &&
118                 git fetch >../actual.out 2>../actual.err
119         ) &&
120         test_must_be_empty actual.out &&
121         test_i18ncmp expect.err actual.err
122 '
123
124 test_expect_success "--no-recurse-submodules overrides .gitmodules config" '
125         add_upstream_commit &&
126         (
127                 cd downstream &&
128                 git fetch --no-recurse-submodules >../actual.out 2>../actual.err
129         ) &&
130         ! test -s actual.out &&
131         ! test -s actual.err
132 '
133
134 test_expect_success "using fetchRecurseSubmodules=false in .git/config overrides setting in .gitmodules" '
135         (
136                 cd downstream &&
137                 git config submodule.submodule.fetchRecurseSubmodules false &&
138                 git fetch >../actual.out 2>../actual.err
139         ) &&
140         ! test -s actual.out &&
141         ! test -s actual.err
142 '
143
144 test_expect_success "--recurse-submodules overrides fetchRecurseSubmodules setting from .git/config" '
145         (
146                 cd downstream &&
147                 git fetch --recurse-submodules >../actual.out 2>../actual.err &&
148                 git config --unset -f .gitmodules submodule.submodule.fetchRecurseSubmodules &&
149                 git config --unset submodule.submodule.fetchRecurseSubmodules
150         ) &&
151         test_must_be_empty actual.out &&
152         test_i18ncmp expect.err actual.err
153 '
154
155 test_expect_success "--quiet propagates to submodules" '
156         (
157                 cd downstream &&
158                 git fetch --recurse-submodules --quiet >../actual.out 2>../actual.err
159         ) &&
160         ! test -s actual.out &&
161         ! test -s actual.err
162 '
163
164 test_expect_success "--quiet propagates to parallel submodules" '
165         (
166                 cd downstream &&
167                 git fetch --recurse-submodules -j 2 --quiet  >../actual.out 2>../actual.err
168         ) &&
169         ! test -s actual.out &&
170         ! test -s actual.err
171 '
172
173 test_expect_success "--dry-run propagates to submodules" '
174         add_upstream_commit &&
175         (
176                 cd downstream &&
177                 git fetch --recurse-submodules --dry-run >../actual.out 2>../actual.err
178         ) &&
179         test_must_be_empty actual.out &&
180         test_i18ncmp expect.err actual.err
181 '
182
183 test_expect_success "Without --dry-run propagates to submodules" '
184         (
185                 cd downstream &&
186                 git fetch --recurse-submodules >../actual.out 2>../actual.err
187         ) &&
188         test_must_be_empty actual.out &&
189         test_i18ncmp expect.err actual.err
190 '
191
192 test_expect_success "recurseSubmodules=true propagates into submodules" '
193         add_upstream_commit &&
194         (
195                 cd downstream &&
196                 git config fetch.recurseSubmodules true &&
197                 git fetch >../actual.out 2>../actual.err
198         ) &&
199         test_must_be_empty actual.out &&
200         test_i18ncmp expect.err actual.err
201 '
202
203 test_expect_success "--recurse-submodules overrides config in submodule" '
204         add_upstream_commit &&
205         (
206                 cd downstream &&
207                 (
208                         cd submodule &&
209                         git config fetch.recurseSubmodules false
210                 ) &&
211                 git fetch --recurse-submodules >../actual.out 2>../actual.err
212         ) &&
213         test_must_be_empty actual.out &&
214         test_i18ncmp expect.err actual.err
215 '
216
217 test_expect_success "--no-recurse-submodules overrides config setting" '
218         add_upstream_commit &&
219         (
220                 cd downstream &&
221                 git config fetch.recurseSubmodules true &&
222                 git fetch --no-recurse-submodules >../actual.out 2>../actual.err
223         ) &&
224         ! test -s actual.out &&
225         ! test -s actual.err
226 '
227
228 test_expect_success "Recursion doesn't happen when no new commits are fetched in the superproject" '
229         (
230                 cd downstream &&
231                 (
232                         cd submodule &&
233                         git config --unset fetch.recurseSubmodules
234                 ) &&
235                 git config --unset fetch.recurseSubmodules &&
236                 git fetch >../actual.out 2>../actual.err
237         ) &&
238         ! test -s actual.out &&
239         ! test -s actual.err
240 '
241
242 test_expect_success "Recursion stops when no new submodule commits are fetched" '
243         head1=$(git rev-parse --short HEAD) &&
244         git add submodule &&
245         git commit -m "new submodule" &&
246         head2=$(git rev-parse --short HEAD) &&
247         echo "From $pwd/." > expect.err.sub &&
248         echo "   $head1..$head2  master     -> origin/master" >>expect.err.sub &&
249         head -3 expect.err >> expect.err.sub &&
250         (
251                 cd downstream &&
252                 git fetch >../actual.out 2>../actual.err
253         ) &&
254         test_i18ncmp expect.err.sub actual.err &&
255         test_must_be_empty actual.out
256 '
257
258 test_expect_success "Recursion doesn't happen when new superproject commits don't change any submodules" '
259         add_upstream_commit &&
260         head1=$(git rev-parse --short HEAD) &&
261         echo a > file &&
262         git add file &&
263         git commit -m "new file" &&
264         head2=$(git rev-parse --short HEAD) &&
265         echo "From $pwd/." > expect.err.file &&
266         echo "   $head1..$head2  master     -> origin/master" >> expect.err.file &&
267         (
268                 cd downstream &&
269                 git fetch >../actual.out 2>../actual.err
270         ) &&
271         ! test -s actual.out &&
272         test_i18ncmp expect.err.file actual.err
273 '
274
275 test_expect_success "Recursion picks up config in submodule" '
276         (
277                 cd downstream &&
278                 git fetch --recurse-submodules &&
279                 (
280                         cd submodule &&
281                         git config fetch.recurseSubmodules true
282                 )
283         ) &&
284         add_upstream_commit &&
285         head1=$(git rev-parse --short HEAD) &&
286         git add submodule &&
287         git commit -m "new submodule" &&
288         head2=$(git rev-parse --short HEAD) &&
289         echo "From $pwd/." > expect.err.sub &&
290         echo "   $head1..$head2  master     -> origin/master" >> expect.err.sub &&
291         cat expect.err >> expect.err.sub &&
292         (
293                 cd downstream &&
294                 git fetch >../actual.out 2>../actual.err &&
295                 (
296                         cd submodule &&
297                         git config --unset fetch.recurseSubmodules
298                 )
299         ) &&
300         test_i18ncmp expect.err.sub actual.err &&
301         test_must_be_empty actual.out
302 '
303
304 test_expect_success "Recursion picks up all submodules when necessary" '
305         add_upstream_commit &&
306         (
307                 cd submodule &&
308                 (
309                         cd subdir/deepsubmodule &&
310                         git fetch &&
311                         git checkout -q FETCH_HEAD
312                 ) &&
313                 head1=$(git rev-parse --short HEAD^) &&
314                 git add subdir/deepsubmodule &&
315                 git commit -m "new deepsubmodule" &&
316                 head2=$(git rev-parse --short HEAD) &&
317                 echo "Fetching submodule submodule" > ../expect.err.sub &&
318                 echo "From $pwd/submodule" >> ../expect.err.sub &&
319                 echo "   $head1..$head2  master     -> origin/master" >> ../expect.err.sub
320         ) &&
321         head1=$(git rev-parse --short HEAD) &&
322         git add submodule &&
323         git commit -m "new submodule" &&
324         head2=$(git rev-parse --short HEAD) &&
325         echo "From $pwd/." > expect.err.2 &&
326         echo "   $head1..$head2  master     -> origin/master" >> expect.err.2 &&
327         cat expect.err.sub >> expect.err.2 &&
328         tail -3 expect.err >> expect.err.2 &&
329         (
330                 cd downstream &&
331                 git fetch >../actual.out 2>../actual.err
332         ) &&
333         test_i18ncmp expect.err.2 actual.err &&
334         test_must_be_empty actual.out
335 '
336
337 test_expect_success "'--recurse-submodules=on-demand' doesn't recurse when no new commits are fetched in the superproject (and ignores config)" '
338         add_upstream_commit &&
339         (
340                 cd submodule &&
341                 (
342                         cd subdir/deepsubmodule &&
343                         git fetch &&
344                         git checkout -q FETCH_HEAD
345                 ) &&
346                 head1=$(git rev-parse --short HEAD^) &&
347                 git add subdir/deepsubmodule &&
348                 git commit -m "new deepsubmodule" &&
349                 head2=$(git rev-parse --short HEAD) &&
350                 echo Fetching submodule submodule > ../expect.err.sub &&
351                 echo "From $pwd/submodule" >> ../expect.err.sub &&
352                 echo "   $head1..$head2  master     -> origin/master" >> ../expect.err.sub
353         ) &&
354         (
355                 cd downstream &&
356                 git config fetch.recurseSubmodules true &&
357                 git fetch --recurse-submodules=on-demand >../actual.out 2>../actual.err &&
358                 git config --unset fetch.recurseSubmodules
359         ) &&
360         ! test -s actual.out &&
361         ! test -s actual.err
362 '
363
364 test_expect_success "'--recurse-submodules=on-demand' recurses as deep as necessary (and ignores config)" '
365         head1=$(git rev-parse --short HEAD) &&
366         git add submodule &&
367         git commit -m "new submodule" &&
368         head2=$(git rev-parse --short HEAD) &&
369         tail -3 expect.err > expect.err.deepsub &&
370         echo "From $pwd/." > expect.err &&
371         echo "   $head1..$head2  master     -> origin/master" >>expect.err &&
372         cat expect.err.sub >> expect.err &&
373         cat expect.err.deepsub >> expect.err &&
374         (
375                 cd downstream &&
376                 git config fetch.recurseSubmodules false &&
377                 (
378                         cd submodule &&
379                         git config -f .gitmodules submodule.subdir/deepsubmodule.fetchRecursive false
380                 ) &&
381                 git fetch --recurse-submodules=on-demand >../actual.out 2>../actual.err &&
382                 git config --unset fetch.recurseSubmodules
383                 (
384                         cd submodule &&
385                         git config --unset -f .gitmodules submodule.subdir/deepsubmodule.fetchRecursive
386                 )
387         ) &&
388         test_must_be_empty actual.out &&
389         test_i18ncmp expect.err actual.err
390 '
391
392 test_expect_success "'--recurse-submodules=on-demand' stops when no new submodule commits are found in the superproject (and ignores config)" '
393         add_upstream_commit &&
394         head1=$(git rev-parse --short HEAD) &&
395         echo a >> file &&
396         git add file &&
397         git commit -m "new file" &&
398         head2=$(git rev-parse --short HEAD) &&
399         echo "From $pwd/." > expect.err.file &&
400         echo "   $head1..$head2  master     -> origin/master" >> expect.err.file &&
401         (
402                 cd downstream &&
403                 git fetch --recurse-submodules=on-demand >../actual.out 2>../actual.err
404         ) &&
405         ! test -s actual.out &&
406         test_i18ncmp expect.err.file actual.err
407 '
408
409 test_expect_success "'fetch.recurseSubmodules=on-demand' overrides global config" '
410         (
411                 cd downstream &&
412                 git fetch --recurse-submodules
413         ) &&
414         add_upstream_commit &&
415         git config --global fetch.recurseSubmodules false &&
416         head1=$(git rev-parse --short HEAD) &&
417         git add submodule &&
418         git commit -m "new submodule" &&
419         head2=$(git rev-parse --short HEAD) &&
420         echo "From $pwd/." > expect.err.2 &&
421         echo "   $head1..$head2  master     -> origin/master" >>expect.err.2 &&
422         head -3 expect.err >> expect.err.2 &&
423         (
424                 cd downstream &&
425                 git config fetch.recurseSubmodules on-demand &&
426                 git fetch >../actual.out 2>../actual.err
427         ) &&
428         git config --global --unset fetch.recurseSubmodules &&
429         (
430                 cd downstream &&
431                 git config --unset fetch.recurseSubmodules
432         ) &&
433         test_must_be_empty actual.out &&
434         test_i18ncmp expect.err.2 actual.err
435 '
436
437 test_expect_success "'submodule.<sub>.fetchRecurseSubmodules=on-demand' overrides fetch.recurseSubmodules" '
438         (
439                 cd downstream &&
440                 git fetch --recurse-submodules
441         ) &&
442         add_upstream_commit &&
443         git config fetch.recurseSubmodules false &&
444         head1=$(git rev-parse --short HEAD) &&
445         git add submodule &&
446         git commit -m "new submodule" &&
447         head2=$(git rev-parse --short HEAD) &&
448         echo "From $pwd/." > expect.err.2 &&
449         echo "   $head1..$head2  master     -> origin/master" >>expect.err.2 &&
450         head -3 expect.err >> expect.err.2 &&
451         (
452                 cd downstream &&
453                 git config submodule.submodule.fetchRecurseSubmodules on-demand &&
454                 git fetch >../actual.out 2>../actual.err
455         ) &&
456         git config --unset fetch.recurseSubmodules &&
457         (
458                 cd downstream &&
459                 git config --unset submodule.submodule.fetchRecurseSubmodules
460         ) &&
461         test_must_be_empty actual.out &&
462         test_i18ncmp expect.err.2 actual.err
463 '
464
465 test_expect_success "don't fetch submodule when newly recorded commits are already present" '
466         (
467                 cd submodule &&
468                 git checkout -q HEAD^^
469         ) &&
470         head1=$(git rev-parse --short HEAD) &&
471         git add submodule &&
472         git commit -m "submodule rewound" &&
473         head2=$(git rev-parse --short HEAD) &&
474         echo "From $pwd/." > expect.err &&
475         echo "   $head1..$head2  master     -> origin/master" >> expect.err &&
476         (
477                 cd downstream &&
478                 git fetch >../actual.out 2>../actual.err
479         ) &&
480         ! test -s actual.out &&
481         test_i18ncmp expect.err actual.err
482 '
483
484 test_expect_success 'fetching submodules respects parallel settings' '
485         git config fetch.recurseSubmodules true &&
486         (
487                 cd downstream &&
488                 GIT_TRACE=$(pwd)/trace.out git fetch --jobs 7 &&
489                 grep "7 tasks" trace.out &&
490                 git config submodule.fetchJobs 8 &&
491                 GIT_TRACE=$(pwd)/trace.out git fetch &&
492                 grep "8 tasks" trace.out &&
493                 GIT_TRACE=$(pwd)/trace.out git fetch --jobs 9 &&
494                 grep "9 tasks" trace.out
495         )
496 '
497
498 test_expect_success 'fetching submodule into a broken repository' '
499         # Prepare src and src/sub nested in it
500         git init src &&
501         (
502                 cd src &&
503                 git init sub &&
504                 git -C sub commit --allow-empty -m "initial in sub" &&
505                 git submodule add -- ./sub sub &&
506                 git commit -m "initial in top"
507         ) &&
508
509         # Clone the old-fashoned way
510         git clone src dst &&
511         git -C dst clone ../src/sub sub &&
512
513         # Make sure that old-fashoned layout is still supported
514         git -C dst status &&
515
516         # "diff" would find no change
517         git -C dst diff --exit-code &&
518
519         # Recursive-fetch works fine
520         git -C dst fetch --recurse-submodules &&
521
522         # Break the receiving submodule
523         rm -f dst/sub/.git/HEAD &&
524
525         # NOTE: without the fix the following tests will recurse forever!
526         # They should terminate with an error.
527
528         test_must_fail git -C dst status &&
529         test_must_fail git -C dst diff &&
530         test_must_fail git -C dst fetch --recurse-submodules
531 '
532
533 test_done