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