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