fc08647bfa330a377cf8c9e04c0d2e03f4902b54
[git.git] / t / t7400-submodule-basic.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2007 Lars Hjemli
4 #
5
6 test_description='Basic porcelain support for submodules
7
8 This test tries to verify basic sanity of the init, update and status
9 subcommands of git submodule.
10 '
11
12 . ./test-lib.sh
13
14 test_expect_success 'setup - initial commit' '
15         >t &&
16         git add t &&
17         git commit -m "initial commit" &&
18         git branch initial
19 '
20
21 test_expect_success 'setup - repository in init subdirectory' '
22         mkdir init &&
23         (
24                 cd init &&
25                 git init &&
26                 echo a >a &&
27                 git add a &&
28                 git commit -m "submodule commit 1" &&
29                 git tag -a -m "rev-1" rev-1
30         )
31 '
32
33 test_expect_success 'setup - commit with gitlink' '
34         echo a >a &&
35         echo z >z &&
36         git add a init z &&
37         git commit -m "super commit 1"
38 '
39
40 test_expect_success 'setup - hide init subdirectory' '
41         mv init .subrepo
42 '
43
44 test_expect_success 'setup - repository to add submodules to' '
45         git init addtest &&
46         git init addtest-ignore
47 '
48
49 # The 'submodule add' tests need some repository to add as a submodule.
50 # The trash directory is a good one as any. We need to canonicalize
51 # the name, though, as some tests compare it to the absolute path git
52 # generates, which will expand symbolic links.
53 submodurl=$(pwd -P)
54
55 listbranches() {
56         git for-each-ref --format='%(refname)' 'refs/heads/*'
57 }
58
59 inspect() {
60         dir=$1 &&
61         dotdot="${2:-..}" &&
62
63         (
64                 cd "$dir" &&
65                 listbranches >"$dotdot/heads" &&
66                 { git symbolic-ref HEAD || :; } >"$dotdot/head" &&
67                 git rev-parse HEAD >"$dotdot/head-sha1" &&
68                 git update-index --refresh &&
69                 git diff-files --exit-code &&
70                 git clean -n -d -x >"$dotdot/untracked"
71         )
72 }
73
74 test_expect_success 'submodule add' '
75         echo "refs/heads/master" >expect &&
76         >empty &&
77
78         (
79                 cd addtest &&
80                 git submodule add -q "$submodurl" submod >actual &&
81                 test ! -s actual &&
82                 echo "gitdir: ../.git/modules/submod" >expect &&
83                 test_cmp expect submod/.git &&
84                 (
85                         cd submod &&
86                         git config core.worktree >actual &&
87                         echo "../../../submod" >expect &&
88                         test_cmp expect actual &&
89                         rm -f actual expect
90                 ) &&
91                 git submodule init
92         ) &&
93
94         rm -f heads head untracked &&
95         inspect addtest/submod ../.. &&
96         test_cmp expect heads &&
97         test_cmp expect head &&
98         test_cmp empty untracked
99 '
100
101 test_expect_success 'submodule add to .gitignored path fails' '
102         (
103                 cd addtest-ignore &&
104                 cat <<-\EOF >expect &&
105                 The following path is ignored by one of your .gitignore files:
106                 submod
107                 Use -f if you really want to add it.
108                 EOF
109                 # Does not use test_commit due to the ignore
110                 echo "*" > .gitignore &&
111                 git add --force .gitignore &&
112                 git commit -m"Ignore everything" &&
113                 ! git submodule add "$submodurl" submod >actual 2>&1 &&
114                 test_i18ncmp expect actual
115         )
116 '
117
118 test_expect_success 'submodule add to .gitignored path with --force' '
119         (
120                 cd addtest-ignore &&
121                 git submodule add --force "$submodurl" submod
122         )
123 '
124
125 test_expect_success 'submodule add --branch' '
126         echo "refs/heads/initial" >expect-head &&
127         cat <<-\EOF >expect-heads &&
128         refs/heads/initial
129         refs/heads/master
130         EOF
131         >empty &&
132
133         (
134                 cd addtest &&
135                 git submodule add -b initial "$submodurl" submod-branch &&
136                 test -z "$(git config -f .gitmodules submodule.submod-branch.branch)" &&
137                 git submodule init
138         ) &&
139
140         rm -f heads head untracked &&
141         inspect addtest/submod-branch ../.. &&
142         test_cmp expect-heads heads &&
143         test_cmp expect-head head &&
144         test_cmp empty untracked
145 '
146
147 test_expect_success 'submodule add with ./ in path' '
148         echo "refs/heads/master" >expect &&
149         >empty &&
150
151         (
152                 cd addtest &&
153                 git submodule add "$submodurl" ././dotsubmod/./frotz/./ &&
154                 git submodule init
155         ) &&
156
157         rm -f heads head untracked &&
158         inspect addtest/dotsubmod/frotz ../../.. &&
159         test_cmp expect heads &&
160         test_cmp expect head &&
161         test_cmp empty untracked
162 '
163
164 test_expect_success 'submodule add with // in path' '
165         echo "refs/heads/master" >expect &&
166         >empty &&
167
168         (
169                 cd addtest &&
170                 git submodule add "$submodurl" slashslashsubmod///frotz// &&
171                 git submodule init
172         ) &&
173
174         rm -f heads head untracked &&
175         inspect addtest/slashslashsubmod/frotz ../../.. &&
176         test_cmp expect heads &&
177         test_cmp expect head &&
178         test_cmp empty untracked
179 '
180
181 test_expect_success 'submodule add with /.. in path' '
182         echo "refs/heads/master" >expect &&
183         >empty &&
184
185         (
186                 cd addtest &&
187                 git submodule add "$submodurl" dotdotsubmod/../realsubmod/frotz/.. &&
188                 git submodule init
189         ) &&
190
191         rm -f heads head untracked &&
192         inspect addtest/realsubmod ../.. &&
193         test_cmp expect heads &&
194         test_cmp expect head &&
195         test_cmp empty untracked
196 '
197
198 test_expect_success 'submodule add with ./, /.. and // in path' '
199         echo "refs/heads/master" >expect &&
200         >empty &&
201
202         (
203                 cd addtest &&
204                 git submodule add "$submodurl" dot/dotslashsubmod/./../..////realsubmod2/a/b/c/d/../../../../frotz//.. &&
205                 git submodule init
206         ) &&
207
208         rm -f heads head untracked &&
209         inspect addtest/realsubmod2 ../.. &&
210         test_cmp expect heads &&
211         test_cmp expect head &&
212         test_cmp empty untracked
213 '
214
215 test_expect_success 'submodule add --local-branch' '
216         (
217                 cd addtest &&
218                 git submodule add --local-branch "$submodurl" submod-follow-head &&
219                 test "$(git config -f .gitmodules submodule.submod-follow-head.branch)" = "HEAD"
220         )
221 '
222
223 test_expect_success 'submodule add --local-branch --branch' '
224         (
225                 cd addtest &&
226                 git submodule add --local-branch -b initial "$submodurl" submod-auto-follow &&
227                 test "$(git config -f .gitmodules submodule.submod-auto-follow.branch)" = "initial"
228         )
229 '
230
231 test_expect_success 'submodule add --local-branch=<name> --branch' '
232         (
233                 cd addtest &&
234                 git submodule add --local-branch=final -b initial "$submodurl" submod-follow &&
235                 test "$(git config -f .gitmodules submodule.submod-follow.branch)" = "final"
236         )
237 '
238
239 test_expect_success 'setup - add an example entry to .gitmodules' '
240         GIT_CONFIG=.gitmodules \
241         git config submodule.example.url git://example.com/init.git
242 '
243
244 test_expect_success 'status should fail for unmapped paths' '
245         test_must_fail git submodule status
246 '
247
248 test_expect_success 'setup - map path in .gitmodules' '
249         cat <<\EOF >expect &&
250 [submodule "example"]
251         url = git://example.com/init.git
252         path = init
253 EOF
254
255         GIT_CONFIG=.gitmodules git config submodule.example.path init &&
256
257         test_cmp expect .gitmodules
258 '
259
260 test_expect_success 'status should only print one line' '
261         git submodule status >lines &&
262         test_line_count = 1 lines
263 '
264
265 test_expect_success 'setup - fetch commit name from submodule' '
266         rev1=$(cd .subrepo && git rev-parse HEAD) &&
267         printf "rev1: %s\n" "$rev1" &&
268         test -n "$rev1"
269 '
270
271 test_expect_success 'status should initially be "missing"' '
272         git submodule status >lines &&
273         grep "^-$rev1" lines
274 '
275
276 test_expect_success 'init should register submodule url in .git/config' '
277         echo git://example.com/init.git >expect &&
278
279         git submodule init &&
280         git config submodule.example.url >url &&
281         git config submodule.example.url ./.subrepo &&
282
283         test_cmp expect url
284 '
285
286 test_failure_with_unknown_submodule () {
287         test_must_fail git submodule $1 no-such-submodule 2>output.err &&
288         grep "^error: .*no-such-submodule" output.err
289 }
290
291 test_expect_success 'init should fail with unknown submodule' '
292         test_failure_with_unknown_submodule init
293 '
294
295 test_expect_success 'update should fail with unknown submodule' '
296         test_failure_with_unknown_submodule update
297 '
298
299 test_expect_success 'status should fail with unknown submodule' '
300         test_failure_with_unknown_submodule status
301 '
302
303 test_expect_success 'sync should fail with unknown submodule' '
304         test_failure_with_unknown_submodule sync
305 '
306
307 test_expect_success 'update should fail when path is used by a file' '
308         echo hello >expect &&
309
310         echo "hello" >init &&
311         test_must_fail git submodule update &&
312
313         test_cmp expect init
314 '
315
316 test_expect_success 'update should fail when path is used by a nonempty directory' '
317         echo hello >expect &&
318
319         rm -fr init &&
320         mkdir init &&
321         echo "hello" >init/a &&
322
323         test_must_fail git submodule update &&
324
325         test_cmp expect init/a
326 '
327
328 test_expect_success 'update should work when path is an empty dir' '
329         rm -fr init &&
330         rm -f head-sha1 &&
331         echo "$rev1" >expect &&
332
333         mkdir init &&
334         git submodule update -q >update.out &&
335         test ! -s update.out &&
336
337         inspect init &&
338         test_cmp expect head-sha1
339 '
340
341 test_expect_success 'status should be "up-to-date" after update' '
342         git submodule status >list &&
343         grep "^ $rev1" list
344 '
345
346 test_expect_success 'status should be "modified" after submodule commit' '
347         (
348                 cd init &&
349                 echo b >b &&
350                 git add b &&
351                 git commit -m "submodule commit 2"
352         ) &&
353
354         rev2=$(cd init && git rev-parse HEAD) &&
355         test -n "$rev2" &&
356         git submodule status >list &&
357
358         grep "^+$rev2" list
359 '
360
361 test_expect_success 'the --cached sha1 should be rev1' '
362         git submodule --cached status >list &&
363         grep "^+$rev1" list
364 '
365
366 test_expect_success 'git diff should report the SHA1 of the new submodule commit' '
367         git diff >diff &&
368         grep "^+Subproject commit $rev2" diff
369 '
370
371 test_expect_success 'update should checkout rev1' '
372         rm -f head-sha1 &&
373         echo "$rev1" >expect &&
374
375         git submodule update init &&
376         inspect init &&
377
378         test_cmp expect head-sha1
379 '
380
381 test_expect_success 'status should be "up-to-date" after update' '
382         git submodule status >list &&
383         grep "^ $rev1" list
384 '
385
386 test_expect_success 'checkout superproject with subproject already present' '
387         git checkout initial &&
388         git checkout master
389 '
390
391 test_expect_success 'apply submodule diff' '
392         >empty &&
393
394         git branch second &&
395         (
396                 cd init &&
397                 echo s >s &&
398                 git add s &&
399                 git commit -m "change subproject"
400         ) &&
401         git update-index --add init &&
402         git commit -m "change init" &&
403         git format-patch -1 --stdout >P.diff &&
404         git checkout second &&
405         git apply --index P.diff &&
406
407         git diff --cached master >staged &&
408         test_cmp empty staged
409 '
410
411 test_expect_success 'update --init' '
412         mv init init2 &&
413         git config -f .gitmodules submodule.example.url "$(pwd)/init2" &&
414         git config --remove-section submodule.example &&
415         test_must_fail git config submodule.example.url &&
416
417         git submodule update init > update.out &&
418         cat update.out &&
419         test_i18ngrep "not initialized" update.out &&
420         test_must_fail git rev-parse --resolve-git-dir init/.git &&
421
422         git submodule update --init init &&
423         git rev-parse --resolve-git-dir init/.git
424 '
425
426 test_expect_success 'do not add files from a submodule' '
427
428         git reset --hard &&
429         test_must_fail git add init/a
430
431 '
432
433 test_expect_success 'gracefully add submodule with a trailing slash' '
434
435         git reset --hard &&
436         git commit -m "commit subproject" init &&
437         (cd init &&
438          echo b > a) &&
439         git add init/ &&
440         git diff --exit-code --cached init &&
441         commit=$(cd init &&
442          git commit -m update a >/dev/null &&
443          git rev-parse HEAD) &&
444         git add init/ &&
445         test_must_fail git diff --exit-code --cached init &&
446         test $commit = $(git ls-files --stage |
447                 sed -n "s/^160000 \([^ ]*\).*/\1/p")
448
449 '
450
451 test_expect_success 'ls-files gracefully handles trailing slash' '
452
453         test "init" = "$(git ls-files init/)"
454
455 '
456
457 test_expect_success 'moving to a commit without submodule does not leave empty dir' '
458         rm -rf init &&
459         mkdir init &&
460         git reset --hard &&
461         git checkout initial &&
462         test ! -d init &&
463         git checkout second
464 '
465
466 test_expect_success 'submodule <invalid-subcommand> fails' '
467         test_must_fail git submodule no-such-subcommand
468 '
469
470 test_expect_success 'add submodules without specifying an explicit path' '
471         mkdir repo &&
472         (
473                 cd repo &&
474                 git init &&
475                 echo r >r &&
476                 git add r &&
477                 git commit -m "repo commit 1"
478         ) &&
479         git clone --bare repo/ bare.git &&
480         (
481                 cd addtest &&
482                 git submodule add "$submodurl/repo" &&
483                 git config -f .gitmodules submodule.repo.path repo &&
484                 git submodule add "$submodurl/bare.git" &&
485                 git config -f .gitmodules submodule.bare.path bare
486         )
487 '
488
489 test_expect_success 'add should fail when path is used by a file' '
490         (
491                 cd addtest &&
492                 touch file &&
493                 test_must_fail  git submodule add "$submodurl/repo" file
494         )
495 '
496
497 test_expect_success 'add should fail when path is used by an existing directory' '
498         (
499                 cd addtest &&
500                 mkdir empty-dir &&
501                 test_must_fail git submodule add "$submodurl/repo" empty-dir
502         )
503 '
504
505 test_expect_success 'use superproject as upstream when path is relative and no url is set there' '
506         (
507                 cd addtest &&
508                 git submodule add ../repo relative &&
509                 test "$(git config -f .gitmodules submodule.relative.url)" = ../repo &&
510                 git submodule sync relative &&
511                 test "$(git config submodule.relative.url)" = "$submodurl/repo"
512         )
513 '
514
515 test_expect_success 'set up for relative path tests' '
516         mkdir reltest &&
517         (
518                 cd reltest &&
519                 git init &&
520                 mkdir sub &&
521                 (
522                         cd sub &&
523                         git init &&
524                         test_commit foo
525                 ) &&
526                 git add sub &&
527                 git config -f .gitmodules submodule.sub.path sub &&
528                 git config -f .gitmodules submodule.sub.url ../subrepo &&
529                 cp .git/config pristine-.git-config &&
530                 cp .gitmodules pristine-.gitmodules
531         )
532 '
533
534 test_expect_success '../subrepo works with URL - ssh://hostname/repo' '
535         (
536                 cd reltest &&
537                 cp pristine-.git-config .git/config &&
538                 cp pristine-.gitmodules .gitmodules &&
539                 git config remote.origin.url ssh://hostname/repo &&
540                 git submodule init &&
541                 test "$(git config submodule.sub.url)" = ssh://hostname/subrepo
542         )
543 '
544
545 test_expect_success '../subrepo works with port-qualified URL - ssh://hostname:22/repo' '
546         (
547                 cd reltest &&
548                 cp pristine-.git-config .git/config &&
549                 cp pristine-.gitmodules .gitmodules &&
550                 git config remote.origin.url ssh://hostname:22/repo &&
551                 git submodule init &&
552                 test "$(git config submodule.sub.url)" = ssh://hostname:22/subrepo
553         )
554 '
555
556 # About the choice of the path in the next test:
557 # - double-slash side-steps path mangling issues on Windows
558 # - it is still an absolute local path
559 # - there cannot be a server with a blank in its name just in case the
560 #   path is used erroneously to access a //server/share style path
561 test_expect_success '../subrepo path works with local path - //somewhere else/repo' '
562         (
563                 cd reltest &&
564                 cp pristine-.git-config .git/config &&
565                 cp pristine-.gitmodules .gitmodules &&
566                 git config remote.origin.url "//somewhere else/repo" &&
567                 git submodule init &&
568                 test "$(git config submodule.sub.url)" = "//somewhere else/subrepo"
569         )
570 '
571
572 test_expect_success '../subrepo works with file URL - file:///tmp/repo' '
573         (
574                 cd reltest &&
575                 cp pristine-.git-config .git/config &&
576                 cp pristine-.gitmodules .gitmodules &&
577                 git config remote.origin.url file:///tmp/repo &&
578                 git submodule init &&
579                 test "$(git config submodule.sub.url)" = file:///tmp/subrepo
580         )
581 '
582
583 test_expect_success '../subrepo works with helper URL- helper:://hostname/repo' '
584         (
585                 cd reltest &&
586                 cp pristine-.git-config .git/config &&
587                 cp pristine-.gitmodules .gitmodules &&
588                 git config remote.origin.url helper:://hostname/repo &&
589                 git submodule init &&
590                 test "$(git config submodule.sub.url)" = helper:://hostname/subrepo
591         )
592 '
593
594 test_expect_success '../subrepo works with scp-style URL - user@host:repo' '
595         (
596                 cd reltest &&
597                 cp pristine-.git-config .git/config &&
598                 git config remote.origin.url user@host:repo &&
599                 git submodule init &&
600                 test "$(git config submodule.sub.url)" = user@host:subrepo
601         )
602 '
603
604 test_expect_success '../subrepo works with scp-style URL - user@host:path/to/repo' '
605         (
606                 cd reltest &&
607                 cp pristine-.git-config .git/config &&
608                 cp pristine-.gitmodules .gitmodules &&
609                 git config remote.origin.url user@host:path/to/repo &&
610                 git submodule init &&
611                 test "$(git config submodule.sub.url)" = user@host:path/to/subrepo
612         )
613 '
614
615 test_expect_success '../subrepo works with relative local path - foo' '
616         (
617                 cd reltest &&
618                 cp pristine-.git-config .git/config &&
619                 cp pristine-.gitmodules .gitmodules &&
620                 git config remote.origin.url foo &&
621                 # actual: fails with an error
622                 git submodule init &&
623                 test "$(git config submodule.sub.url)" = subrepo
624         )
625 '
626
627 test_expect_success '../subrepo works with relative local path - foo/bar' '
628         (
629                 cd reltest &&
630                 cp pristine-.git-config .git/config &&
631                 cp pristine-.gitmodules .gitmodules &&
632                 git config remote.origin.url foo/bar &&
633                 git submodule init &&
634                 test "$(git config submodule.sub.url)" = foo/subrepo
635         )
636 '
637
638 test_expect_success '../subrepo works with relative local path - ./foo' '
639         (
640                 cd reltest &&
641                 cp pristine-.git-config .git/config &&
642                 cp pristine-.gitmodules .gitmodules &&
643                 git config remote.origin.url ./foo &&
644                 git submodule init &&
645                 test "$(git config submodule.sub.url)" = subrepo
646         )
647 '
648
649 test_expect_success '../subrepo works with relative local path - ./foo/bar' '
650         (
651                 cd reltest &&
652                 cp pristine-.git-config .git/config &&
653                 cp pristine-.gitmodules .gitmodules &&
654                 git config remote.origin.url ./foo/bar &&
655                 git submodule init &&
656                 test "$(git config submodule.sub.url)" = foo/subrepo
657         )
658 '
659
660 test_expect_success '../subrepo works with relative local path - ../foo' '
661         (
662                 cd reltest &&
663                 cp pristine-.git-config .git/config &&
664                 cp pristine-.gitmodules .gitmodules &&
665                 git config remote.origin.url ../foo &&
666                 git submodule init &&
667                 test "$(git config submodule.sub.url)" = ../subrepo
668         )
669 '
670
671 test_expect_success '../subrepo works with relative local path - ../foo/bar' '
672         (
673                 cd reltest &&
674                 cp pristine-.git-config .git/config &&
675                 cp pristine-.gitmodules .gitmodules &&
676                 git config remote.origin.url ../foo/bar &&
677                 git submodule init &&
678                 test "$(git config submodule.sub.url)" = ../foo/subrepo
679         )
680 '
681
682 test_expect_success '../bar/a/b/c works with relative local path - ../foo/bar.git' '
683         (
684                 cd reltest &&
685                 cp pristine-.git-config .git/config &&
686                 cp pristine-.gitmodules .gitmodules &&
687                 mkdir -p a/b/c &&
688                 (cd a/b/c; git init) &&
689                 git config remote.origin.url ../foo/bar.git &&
690                 git submodule add ../bar/a/b/c ./a/b/c &&
691                 git submodule init &&
692                 test "$(git config submodule.a/b/c.url)" = ../foo/bar/a/b/c
693         )
694 '
695
696 test_expect_success 'moving the superproject does not break submodules' '
697         (
698                 cd addtest &&
699                 git submodule status >expect
700         )
701         mv addtest addtest2 &&
702         (
703                 cd addtest2 &&
704                 git submodule status >actual &&
705                 test_cmp expect actual
706         )
707 '
708
709 test_done