t7400: avoid path mangling issues
[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_expect_success 'update should fail when path is used by a file' '
262         echo hello >expect &&
263
264         echo "hello" >init &&
265         test_must_fail git submodule update &&
266
267         test_cmp expect init
268 '
269
270 test_expect_success 'update should fail when path is used by a nonempty directory' '
271         echo hello >expect &&
272
273         rm -fr init &&
274         mkdir init &&
275         echo "hello" >init/a &&
276
277         test_must_fail git submodule update &&
278
279         test_cmp expect init/a
280 '
281
282 test_expect_success 'update should work when path is an empty dir' '
283         rm -fr init &&
284         rm -f head-sha1 &&
285         echo "$rev1" >expect &&
286
287         mkdir init &&
288         git submodule update -q >update.out &&
289         test ! -s update.out &&
290
291         inspect init &&
292         test_cmp expect head-sha1
293 '
294
295 test_expect_success 'status should be "up-to-date" after update' '
296         git submodule status >list &&
297         grep "^ $rev1" list
298 '
299
300 test_expect_success 'status should be "modified" after submodule commit' '
301         (
302                 cd init &&
303                 echo b >b &&
304                 git add b &&
305                 git commit -m "submodule commit 2"
306         ) &&
307
308         rev2=$(cd init && git rev-parse HEAD) &&
309         test -n "$rev2" &&
310         git submodule status >list &&
311
312         grep "^+$rev2" list
313 '
314
315 test_expect_success 'the --cached sha1 should be rev1' '
316         git submodule --cached status >list &&
317         grep "^+$rev1" list
318 '
319
320 test_expect_success 'git diff should report the SHA1 of the new submodule commit' '
321         git diff >diff &&
322         grep "^+Subproject commit $rev2" diff
323 '
324
325 test_expect_success 'update should checkout rev1' '
326         rm -f head-sha1 &&
327         echo "$rev1" >expect &&
328
329         git submodule update init &&
330         inspect init &&
331
332         test_cmp expect head-sha1
333 '
334
335 test_expect_success 'status should be "up-to-date" after update' '
336         git submodule status >list &&
337         grep "^ $rev1" list
338 '
339
340 test_expect_success 'checkout superproject with subproject already present' '
341         git checkout initial &&
342         git checkout master
343 '
344
345 test_expect_success 'apply submodule diff' '
346         >empty &&
347
348         git branch second &&
349         (
350                 cd init &&
351                 echo s >s &&
352                 git add s &&
353                 git commit -m "change subproject"
354         ) &&
355         git update-index --add init &&
356         git commit -m "change init" &&
357         git format-patch -1 --stdout >P.diff &&
358         git checkout second &&
359         git apply --index P.diff &&
360
361         git diff --cached master >staged &&
362         test_cmp empty staged
363 '
364
365 test_expect_success 'update --init' '
366         mv init init2 &&
367         git config -f .gitmodules submodule.example.url "$(pwd)/init2" &&
368         git config --remove-section submodule.example &&
369         test_must_fail git config submodule.example.url &&
370
371         git submodule update init > update.out &&
372         cat update.out &&
373         test_i18ngrep "not initialized" update.out &&
374         test_must_fail git rev-parse --resolve-git-dir init/.git &&
375
376         git submodule update --init init &&
377         git rev-parse --resolve-git-dir init/.git
378 '
379
380 test_expect_success 'do not add files from a submodule' '
381
382         git reset --hard &&
383         test_must_fail git add init/a
384
385 '
386
387 test_expect_success 'gracefully add submodule with a trailing slash' '
388
389         git reset --hard &&
390         git commit -m "commit subproject" init &&
391         (cd init &&
392          echo b > a) &&
393         git add init/ &&
394         git diff --exit-code --cached init &&
395         commit=$(cd init &&
396          git commit -m update a >/dev/null &&
397          git rev-parse HEAD) &&
398         git add init/ &&
399         test_must_fail git diff --exit-code --cached init &&
400         test $commit = $(git ls-files --stage |
401                 sed -n "s/^160000 \([^ ]*\).*/\1/p")
402
403 '
404
405 test_expect_success 'ls-files gracefully handles trailing slash' '
406
407         test "init" = "$(git ls-files init/)"
408
409 '
410
411 test_expect_success 'moving to a commit without submodule does not leave empty dir' '
412         rm -rf init &&
413         mkdir init &&
414         git reset --hard &&
415         git checkout initial &&
416         test ! -d init &&
417         git checkout second
418 '
419
420 test_expect_success 'submodule <invalid-path> warns' '
421
422         git submodule no-such-submodule 2> output.err &&
423         grep "^error: .*no-such-submodule" output.err
424
425 '
426
427 test_expect_success 'add submodules without specifying an explicit path' '
428         mkdir repo &&
429         (
430                 cd repo &&
431                 git init &&
432                 echo r >r &&
433                 git add r &&
434                 git commit -m "repo commit 1"
435         ) &&
436         git clone --bare repo/ bare.git &&
437         (
438                 cd addtest &&
439                 git submodule add "$submodurl/repo" &&
440                 git config -f .gitmodules submodule.repo.path repo &&
441                 git submodule add "$submodurl/bare.git" &&
442                 git config -f .gitmodules submodule.bare.path bare
443         )
444 '
445
446 test_expect_success 'add should fail when path is used by a file' '
447         (
448                 cd addtest &&
449                 touch file &&
450                 test_must_fail  git submodule add "$submodurl/repo" file
451         )
452 '
453
454 test_expect_success 'add should fail when path is used by an existing directory' '
455         (
456                 cd addtest &&
457                 mkdir empty-dir &&
458                 test_must_fail git submodule add "$submodurl/repo" empty-dir
459         )
460 '
461
462 test_expect_success 'use superproject as upstream when path is relative and no url is set there' '
463         (
464                 cd addtest &&
465                 git submodule add ../repo relative &&
466                 test "$(git config -f .gitmodules submodule.relative.url)" = ../repo &&
467                 git submodule sync relative &&
468                 test "$(git config submodule.relative.url)" = "$submodurl/repo"
469         )
470 '
471
472 test_expect_success 'set up for relative path tests' '
473         mkdir reltest &&
474         (
475                 cd reltest &&
476                 git init &&
477                 mkdir sub &&
478                 (
479                         cd sub &&
480                         git init &&
481                         test_commit foo
482                 ) &&
483                 git add sub &&
484                 git config -f .gitmodules submodule.sub.path sub &&
485                 git config -f .gitmodules submodule.sub.url ../subrepo &&
486                 cp .git/config pristine-.git-config &&
487                 cp .gitmodules pristine-.gitmodules
488         )
489 '
490
491 test_expect_success '../subrepo works with URL - ssh://hostname/repo' '
492         (
493                 cd reltest &&
494                 cp pristine-.git-config .git/config &&
495                 cp pristine-.gitmodules .gitmodules &&
496                 git config remote.origin.url ssh://hostname/repo &&
497                 git submodule init &&
498                 test "$(git config submodule.sub.url)" = ssh://hostname/subrepo
499         )
500 '
501
502 test_expect_success '../subrepo works with port-qualified URL - ssh://hostname:22/repo' '
503         (
504                 cd reltest &&
505                 cp pristine-.git-config .git/config &&
506                 cp pristine-.gitmodules .gitmodules &&
507                 git config remote.origin.url ssh://hostname:22/repo &&
508                 git submodule init &&
509                 test "$(git config submodule.sub.url)" = ssh://hostname:22/subrepo
510         )
511 '
512
513 # About the choice of the path in the next test:
514 # - double-slash side-steps path mangling issues on Windows
515 # - it is still an absolute local path
516 # - there cannot be a server with a blank in its name just in case the
517 #   path is used erroneously to access a //server/share style path
518 test_expect_success '../subrepo path works with local path - //somewhere else/repo' '
519         (
520                 cd reltest &&
521                 cp pristine-.git-config .git/config &&
522                 cp pristine-.gitmodules .gitmodules &&
523                 git config remote.origin.url "//somewhere else/repo" &&
524                 git submodule init &&
525                 test "$(git config submodule.sub.url)" = "//somewhere else/subrepo"
526         )
527 '
528
529 test_expect_success '../subrepo works with file URL - file:///tmp/repo' '
530         (
531                 cd reltest &&
532                 cp pristine-.git-config .git/config &&
533                 cp pristine-.gitmodules .gitmodules &&
534                 git config remote.origin.url file:///tmp/repo &&
535                 git submodule init &&
536                 test "$(git config submodule.sub.url)" = file:///tmp/subrepo
537         )
538 '
539
540 test_expect_success '../subrepo works with helper URL- helper:://hostname/repo' '
541         (
542                 cd reltest &&
543                 cp pristine-.git-config .git/config &&
544                 cp pristine-.gitmodules .gitmodules &&
545                 git config remote.origin.url helper:://hostname/repo &&
546                 git submodule init &&
547                 test "$(git config submodule.sub.url)" = helper:://hostname/subrepo
548         )
549 '
550
551 test_expect_success '../subrepo works with scp-style URL - user@host:repo' '
552         (
553                 cd reltest &&
554                 cp pristine-.git-config .git/config &&
555                 git config remote.origin.url user@host:repo &&
556                 git submodule init &&
557                 test "$(git config submodule.sub.url)" = user@host:subrepo
558         )
559 '
560
561 test_expect_success '../subrepo works with scp-style URL - user@host:path/to/repo' '
562         (
563                 cd reltest &&
564                 cp pristine-.git-config .git/config &&
565                 cp pristine-.gitmodules .gitmodules &&
566                 git config remote.origin.url user@host:path/to/repo &&
567                 git submodule init &&
568                 test "$(git config submodule.sub.url)" = user@host:path/to/subrepo
569         )
570 '
571
572 test_expect_success '../subrepo works with relative local path - foo' '
573         (
574                 cd reltest &&
575                 cp pristine-.git-config .git/config &&
576                 cp pristine-.gitmodules .gitmodules &&
577                 git config remote.origin.url foo &&
578                 # actual: fails with an error
579                 git submodule init &&
580                 test "$(git config submodule.sub.url)" = subrepo
581         )
582 '
583
584 test_expect_success '../subrepo works with relative local path - foo/bar' '
585         (
586                 cd reltest &&
587                 cp pristine-.git-config .git/config &&
588                 cp pristine-.gitmodules .gitmodules &&
589                 git config remote.origin.url foo/bar &&
590                 git submodule init &&
591                 test "$(git config submodule.sub.url)" = foo/subrepo
592         )
593 '
594
595 test_expect_success '../subrepo works with relative local path - ./foo' '
596         (
597                 cd reltest &&
598                 cp pristine-.git-config .git/config &&
599                 cp pristine-.gitmodules .gitmodules &&
600                 git config remote.origin.url ./foo &&
601                 git submodule init &&
602                 test "$(git config submodule.sub.url)" = subrepo
603         )
604 '
605
606 test_expect_success '../subrepo works with relative local path - ./foo/bar' '
607         (
608                 cd reltest &&
609                 cp pristine-.git-config .git/config &&
610                 cp pristine-.gitmodules .gitmodules &&
611                 git config remote.origin.url ./foo/bar &&
612                 git submodule init &&
613                 test "$(git config submodule.sub.url)" = foo/subrepo
614         )
615 '
616
617 test_expect_success '../subrepo works with relative local path - ../foo' '
618         (
619                 cd reltest &&
620                 cp pristine-.git-config .git/config &&
621                 cp pristine-.gitmodules .gitmodules &&
622                 git config remote.origin.url ../foo &&
623                 git submodule init &&
624                 test "$(git config submodule.sub.url)" = ../subrepo
625         )
626 '
627
628 test_expect_success '../subrepo works with relative local path - ../foo/bar' '
629         (
630                 cd reltest &&
631                 cp pristine-.git-config .git/config &&
632                 cp pristine-.gitmodules .gitmodules &&
633                 git config remote.origin.url ../foo/bar &&
634                 git submodule init &&
635                 test "$(git config submodule.sub.url)" = ../foo/subrepo
636         )
637 '
638
639 test_expect_success '../bar/a/b/c works with relative local path - ../foo/bar.git' '
640         (
641                 cd reltest &&
642                 cp pristine-.git-config .git/config &&
643                 cp pristine-.gitmodules .gitmodules &&
644                 mkdir -p a/b/c &&
645                 (cd a/b/c; git init) &&
646                 git config remote.origin.url ../foo/bar.git &&
647                 git submodule add ../bar/a/b/c ./a/b/c &&
648                 git submodule init &&
649                 test "$(git config submodule.a/b/c.url)" = ../foo/bar/a/b/c
650         )
651 '
652
653 test_expect_success 'moving the superproject does not break submodules' '
654         (
655                 cd addtest &&
656                 git submodule status >expect
657         )
658         mv addtest addtest2 &&
659         (
660                 cd addtest2 &&
661                 git submodule status >actual &&
662                 test_cmp expect actual
663         )
664 '
665
666 test_done