Merge branch 'jk/no-more-pre-exec-callback'
[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                 git submodule init
137         ) &&
138
139         rm -f heads head untracked &&
140         inspect addtest/submod-branch ../.. &&
141         test_cmp expect-heads heads &&
142         test_cmp expect-head head &&
143         test_cmp empty untracked
144 '
145
146 test_expect_success 'submodule add with ./ in path' '
147         echo "refs/heads/master" >expect &&
148         >empty &&
149
150         (
151                 cd addtest &&
152                 git submodule add "$submodurl" ././dotsubmod/./frotz/./ &&
153                 git submodule init
154         ) &&
155
156         rm -f heads head untracked &&
157         inspect addtest/dotsubmod/frotz ../../.. &&
158         test_cmp expect heads &&
159         test_cmp expect head &&
160         test_cmp empty untracked
161 '
162
163 test_expect_success 'submodule add with // in path' '
164         echo "refs/heads/master" >expect &&
165         >empty &&
166
167         (
168                 cd addtest &&
169                 git submodule add "$submodurl" slashslashsubmod///frotz// &&
170                 git submodule init
171         ) &&
172
173         rm -f heads head untracked &&
174         inspect addtest/slashslashsubmod/frotz ../../.. &&
175         test_cmp expect heads &&
176         test_cmp expect head &&
177         test_cmp empty untracked
178 '
179
180 test_expect_success 'submodule add with /.. in path' '
181         echo "refs/heads/master" >expect &&
182         >empty &&
183
184         (
185                 cd addtest &&
186                 git submodule add "$submodurl" dotdotsubmod/../realsubmod/frotz/.. &&
187                 git submodule init
188         ) &&
189
190         rm -f heads head untracked &&
191         inspect addtest/realsubmod ../.. &&
192         test_cmp expect heads &&
193         test_cmp expect head &&
194         test_cmp empty untracked
195 '
196
197 test_expect_success 'submodule add with ./, /.. and // in path' '
198         echo "refs/heads/master" >expect &&
199         >empty &&
200
201         (
202                 cd addtest &&
203                 git submodule add "$submodurl" dot/dotslashsubmod/./../..////realsubmod2/a/b/c/d/../../../../frotz//.. &&
204                 git submodule init
205         ) &&
206
207         rm -f heads head untracked &&
208         inspect addtest/realsubmod2 ../.. &&
209         test_cmp expect heads &&
210         test_cmp expect head &&
211         test_cmp empty untracked
212 '
213
214 test_expect_success 'setup - add an example entry to .gitmodules' '
215         GIT_CONFIG=.gitmodules \
216         git config submodule.example.url git://example.com/init.git
217 '
218
219 test_expect_success 'status should fail for unmapped paths' '
220         test_must_fail git submodule status
221 '
222
223 test_expect_success 'setup - map path in .gitmodules' '
224         cat <<\EOF >expect &&
225 [submodule "example"]
226         url = git://example.com/init.git
227         path = init
228 EOF
229
230         GIT_CONFIG=.gitmodules git config submodule.example.path init &&
231
232         test_cmp expect .gitmodules
233 '
234
235 test_expect_success 'status should only print one line' '
236         git submodule status >lines &&
237         test_line_count = 1 lines
238 '
239
240 test_expect_success 'setup - fetch commit name from submodule' '
241         rev1=$(cd .subrepo && git rev-parse HEAD) &&
242         printf "rev1: %s\n" "$rev1" &&
243         test -n "$rev1"
244 '
245
246 test_expect_success 'status should initially be "missing"' '
247         git submodule status >lines &&
248         grep "^-$rev1" lines
249 '
250
251 test_expect_success 'init should register submodule url in .git/config' '
252         echo git://example.com/init.git >expect &&
253
254         git submodule init &&
255         git config submodule.example.url >url &&
256         git config submodule.example.url ./.subrepo &&
257
258         test_cmp expect url
259 '
260
261 test_failure_with_unknown_submodule () {
262         test_must_fail git submodule $1 no-such-submodule 2>output.err &&
263         grep "^error: .*no-such-submodule" output.err
264 }
265
266 test_expect_success 'init should fail with unknown submodule' '
267         test_failure_with_unknown_submodule init
268 '
269
270 test_expect_success 'update should fail with unknown submodule' '
271         test_failure_with_unknown_submodule update
272 '
273
274 test_expect_success 'status should fail with unknown submodule' '
275         test_failure_with_unknown_submodule status
276 '
277
278 test_expect_success 'sync should fail with unknown submodule' '
279         test_failure_with_unknown_submodule sync
280 '
281
282 test_expect_success 'update should fail when path is used by a file' '
283         echo hello >expect &&
284
285         echo "hello" >init &&
286         test_must_fail git submodule update &&
287
288         test_cmp expect init
289 '
290
291 test_expect_success 'update should fail when path is used by a nonempty directory' '
292         echo hello >expect &&
293
294         rm -fr init &&
295         mkdir init &&
296         echo "hello" >init/a &&
297
298         test_must_fail git submodule update &&
299
300         test_cmp expect init/a
301 '
302
303 test_expect_success 'update should work when path is an empty dir' '
304         rm -fr init &&
305         rm -f head-sha1 &&
306         echo "$rev1" >expect &&
307
308         mkdir init &&
309         git submodule update -q >update.out &&
310         test ! -s update.out &&
311
312         inspect init &&
313         test_cmp expect head-sha1
314 '
315
316 test_expect_success 'status should be "up-to-date" after update' '
317         git submodule status >list &&
318         grep "^ $rev1" list
319 '
320
321 test_expect_success 'status should be "modified" after submodule commit' '
322         (
323                 cd init &&
324                 echo b >b &&
325                 git add b &&
326                 git commit -m "submodule commit 2"
327         ) &&
328
329         rev2=$(cd init && git rev-parse HEAD) &&
330         test -n "$rev2" &&
331         git submodule status >list &&
332
333         grep "^+$rev2" list
334 '
335
336 test_expect_success 'the --cached sha1 should be rev1' '
337         git submodule --cached status >list &&
338         grep "^+$rev1" list
339 '
340
341 test_expect_success 'git diff should report the SHA1 of the new submodule commit' '
342         git diff >diff &&
343         grep "^+Subproject commit $rev2" diff
344 '
345
346 test_expect_success 'update should checkout rev1' '
347         rm -f head-sha1 &&
348         echo "$rev1" >expect &&
349
350         git submodule update init &&
351         inspect init &&
352
353         test_cmp expect head-sha1
354 '
355
356 test_expect_success 'status should be "up-to-date" after update' '
357         git submodule status >list &&
358         grep "^ $rev1" list
359 '
360
361 test_expect_success 'checkout superproject with subproject already present' '
362         git checkout initial &&
363         git checkout master
364 '
365
366 test_expect_success 'apply submodule diff' '
367         >empty &&
368
369         git branch second &&
370         (
371                 cd init &&
372                 echo s >s &&
373                 git add s &&
374                 git commit -m "change subproject"
375         ) &&
376         git update-index --add init &&
377         git commit -m "change init" &&
378         git format-patch -1 --stdout >P.diff &&
379         git checkout second &&
380         git apply --index P.diff &&
381
382         git diff --cached master >staged &&
383         test_cmp empty staged
384 '
385
386 test_expect_success 'update --init' '
387         mv init init2 &&
388         git config -f .gitmodules submodule.example.url "$(pwd)/init2" &&
389         git config --remove-section submodule.example &&
390         test_must_fail git config submodule.example.url &&
391
392         git submodule update init > update.out &&
393         cat update.out &&
394         test_i18ngrep "not initialized" update.out &&
395         test_must_fail git rev-parse --resolve-git-dir init/.git &&
396
397         git submodule update --init init &&
398         git rev-parse --resolve-git-dir init/.git
399 '
400
401 test_expect_success 'do not add files from a submodule' '
402
403         git reset --hard &&
404         test_must_fail git add init/a
405
406 '
407
408 test_expect_success 'gracefully add submodule with a trailing slash' '
409
410         git reset --hard &&
411         git commit -m "commit subproject" init &&
412         (cd init &&
413          echo b > a) &&
414         git add init/ &&
415         git diff --exit-code --cached init &&
416         commit=$(cd init &&
417          git commit -m update a >/dev/null &&
418          git rev-parse HEAD) &&
419         git add init/ &&
420         test_must_fail git diff --exit-code --cached init &&
421         test $commit = $(git ls-files --stage |
422                 sed -n "s/^160000 \([^ ]*\).*/\1/p")
423
424 '
425
426 test_expect_success 'ls-files gracefully handles trailing slash' '
427
428         test "init" = "$(git ls-files init/)"
429
430 '
431
432 test_expect_success 'moving to a commit without submodule does not leave empty dir' '
433         rm -rf init &&
434         mkdir init &&
435         git reset --hard &&
436         git checkout initial &&
437         test ! -d init &&
438         git checkout second
439 '
440
441 test_expect_success 'submodule <invalid-subcommand> fails' '
442         test_must_fail git submodule no-such-subcommand
443 '
444
445 test_expect_success 'add submodules without specifying an explicit path' '
446         mkdir repo &&
447         (
448                 cd repo &&
449                 git init &&
450                 echo r >r &&
451                 git add r &&
452                 git commit -m "repo commit 1"
453         ) &&
454         git clone --bare repo/ bare.git &&
455         (
456                 cd addtest &&
457                 git submodule add "$submodurl/repo" &&
458                 git config -f .gitmodules submodule.repo.path repo &&
459                 git submodule add "$submodurl/bare.git" &&
460                 git config -f .gitmodules submodule.bare.path bare
461         )
462 '
463
464 test_expect_success 'add should fail when path is used by a file' '
465         (
466                 cd addtest &&
467                 touch file &&
468                 test_must_fail  git submodule add "$submodurl/repo" file
469         )
470 '
471
472 test_expect_success 'add should fail when path is used by an existing directory' '
473         (
474                 cd addtest &&
475                 mkdir empty-dir &&
476                 test_must_fail git submodule add "$submodurl/repo" empty-dir
477         )
478 '
479
480 test_expect_success 'use superproject as upstream when path is relative and no url is set there' '
481         (
482                 cd addtest &&
483                 git submodule add ../repo relative &&
484                 test "$(git config -f .gitmodules submodule.relative.url)" = ../repo &&
485                 git submodule sync relative &&
486                 test "$(git config submodule.relative.url)" = "$submodurl/repo"
487         )
488 '
489
490 test_expect_success 'set up for relative path tests' '
491         mkdir reltest &&
492         (
493                 cd reltest &&
494                 git init &&
495                 mkdir sub &&
496                 (
497                         cd sub &&
498                         git init &&
499                         test_commit foo
500                 ) &&
501                 git add sub &&
502                 git config -f .gitmodules submodule.sub.path sub &&
503                 git config -f .gitmodules submodule.sub.url ../subrepo &&
504                 cp .git/config pristine-.git-config &&
505                 cp .gitmodules pristine-.gitmodules
506         )
507 '
508
509 test_expect_success '../subrepo works with URL - ssh://hostname/repo' '
510         (
511                 cd reltest &&
512                 cp pristine-.git-config .git/config &&
513                 cp pristine-.gitmodules .gitmodules &&
514                 git config remote.origin.url ssh://hostname/repo &&
515                 git submodule init &&
516                 test "$(git config submodule.sub.url)" = ssh://hostname/subrepo
517         )
518 '
519
520 test_expect_success '../subrepo works with port-qualified URL - ssh://hostname:22/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:22/repo &&
526                 git submodule init &&
527                 test "$(git config submodule.sub.url)" = ssh://hostname:22/subrepo
528         )
529 '
530
531 # About the choice of the path in the next test:
532 # - double-slash side-steps path mangling issues on Windows
533 # - it is still an absolute local path
534 # - there cannot be a server with a blank in its name just in case the
535 #   path is used erroneously to access a //server/share style path
536 test_expect_success '../subrepo path works with local path - //somewhere else/repo' '
537         (
538                 cd reltest &&
539                 cp pristine-.git-config .git/config &&
540                 cp pristine-.gitmodules .gitmodules &&
541                 git config remote.origin.url "//somewhere else/repo" &&
542                 git submodule init &&
543                 test "$(git config submodule.sub.url)" = "//somewhere else/subrepo"
544         )
545 '
546
547 test_expect_success '../subrepo works with file URL - file:///tmp/repo' '
548         (
549                 cd reltest &&
550                 cp pristine-.git-config .git/config &&
551                 cp pristine-.gitmodules .gitmodules &&
552                 git config remote.origin.url file:///tmp/repo &&
553                 git submodule init &&
554                 test "$(git config submodule.sub.url)" = file:///tmp/subrepo
555         )
556 '
557
558 test_expect_success '../subrepo works with helper URL- helper:://hostname/repo' '
559         (
560                 cd reltest &&
561                 cp pristine-.git-config .git/config &&
562                 cp pristine-.gitmodules .gitmodules &&
563                 git config remote.origin.url helper:://hostname/repo &&
564                 git submodule init &&
565                 test "$(git config submodule.sub.url)" = helper:://hostname/subrepo
566         )
567 '
568
569 test_expect_success '../subrepo works with scp-style URL - user@host:repo' '
570         (
571                 cd reltest &&
572                 cp pristine-.git-config .git/config &&
573                 git config remote.origin.url user@host:repo &&
574                 git submodule init &&
575                 test "$(git config submodule.sub.url)" = user@host:subrepo
576         )
577 '
578
579 test_expect_success '../subrepo works with scp-style URL - user@host:path/to/repo' '
580         (
581                 cd reltest &&
582                 cp pristine-.git-config .git/config &&
583                 cp pristine-.gitmodules .gitmodules &&
584                 git config remote.origin.url user@host:path/to/repo &&
585                 git submodule init &&
586                 test "$(git config submodule.sub.url)" = user@host:path/to/subrepo
587         )
588 '
589
590 test_expect_success '../subrepo works with relative local path - foo' '
591         (
592                 cd reltest &&
593                 cp pristine-.git-config .git/config &&
594                 cp pristine-.gitmodules .gitmodules &&
595                 git config remote.origin.url foo &&
596                 # actual: fails with an error
597                 git submodule init &&
598                 test "$(git config submodule.sub.url)" = subrepo
599         )
600 '
601
602 test_expect_success '../subrepo works with relative local path - foo/bar' '
603         (
604                 cd reltest &&
605                 cp pristine-.git-config .git/config &&
606                 cp pristine-.gitmodules .gitmodules &&
607                 git config remote.origin.url foo/bar &&
608                 git submodule init &&
609                 test "$(git config submodule.sub.url)" = foo/subrepo
610         )
611 '
612
613 test_expect_success '../subrepo works with relative local path - ./foo' '
614         (
615                 cd reltest &&
616                 cp pristine-.git-config .git/config &&
617                 cp pristine-.gitmodules .gitmodules &&
618                 git config remote.origin.url ./foo &&
619                 git submodule init &&
620                 test "$(git config submodule.sub.url)" = subrepo
621         )
622 '
623
624 test_expect_success '../subrepo works with relative local path - ./foo/bar' '
625         (
626                 cd reltest &&
627                 cp pristine-.git-config .git/config &&
628                 cp pristine-.gitmodules .gitmodules &&
629                 git config remote.origin.url ./foo/bar &&
630                 git submodule init &&
631                 test "$(git config submodule.sub.url)" = foo/subrepo
632         )
633 '
634
635 test_expect_success '../subrepo works with relative local path - ../foo' '
636         (
637                 cd reltest &&
638                 cp pristine-.git-config .git/config &&
639                 cp pristine-.gitmodules .gitmodules &&
640                 git config remote.origin.url ../foo &&
641                 git submodule init &&
642                 test "$(git config submodule.sub.url)" = ../subrepo
643         )
644 '
645
646 test_expect_success '../subrepo works with relative local path - ../foo/bar' '
647         (
648                 cd reltest &&
649                 cp pristine-.git-config .git/config &&
650                 cp pristine-.gitmodules .gitmodules &&
651                 git config remote.origin.url ../foo/bar &&
652                 git submodule init &&
653                 test "$(git config submodule.sub.url)" = ../foo/subrepo
654         )
655 '
656
657 test_expect_success '../bar/a/b/c works with relative local path - ../foo/bar.git' '
658         (
659                 cd reltest &&
660                 cp pristine-.git-config .git/config &&
661                 cp pristine-.gitmodules .gitmodules &&
662                 mkdir -p a/b/c &&
663                 (cd a/b/c; git init) &&
664                 git config remote.origin.url ../foo/bar.git &&
665                 git submodule add ../bar/a/b/c ./a/b/c &&
666                 git submodule init &&
667                 test "$(git config submodule.a/b/c.url)" = ../foo/bar/a/b/c
668         )
669 '
670
671 test_expect_success 'moving the superproject does not break submodules' '
672         (
673                 cd addtest &&
674                 git submodule status >expect
675         )
676         mv addtest addtest2 &&
677         (
678                 cd addtest2 &&
679                 git submodule status >actual &&
680                 test_cmp expect actual
681         )
682 '
683
684 test_done