1 # Create a submodule layout used for all tests below.
3 # The following use cases are covered:
4 # - New submodule (no_submodule => add_sub1)
5 # - Removed submodule (add_sub1 => remove_sub1)
6 # - Updated submodule (add_sub1 => modify_sub1)
7 # - Submodule updated to invalid commit (add_sub1 => invalid_sub1)
8 # - Submodule updated from invalid commit (invalid_sub1 => valid_sub1)
9 # - Submodule replaced by tracked files in directory (add_sub1 =>
10 # replace_sub1_with_directory)
11 # - Directory containing tracked files replaced by submodule
12 # (replace_sub1_with_directory => replace_directory_with_sub1)
13 # - Submodule replaced by tracked file with the same name (add_sub1 =>
14 # replace_sub1_with_file)
15 # - Tracked file replaced by submodule (replace_sub1_with_file =>
16 # replace_file_with_sub1)
19 # / ^ replace_directory_with_sub1
20 # / replace_sub1_with_directory
28 # | | \ ^ replace_file_with_sub1
29 # | | \ replace_sub1_with_file
30 # | add_sub1 --O-----O
31 # no_submodule ^ valid_sub1
34 create_lib_submodule_repo
() {
35 git init submodule_update_repo
&&
37 cd submodule_update_repo
&&
38 echo "expect" >>.gitignore
&&
39 echo "actual" >>.gitignore
&&
42 git add .gitignore file1 file2
&&
43 git commit
-m "Base" &&
44 git branch
"no_submodule" &&
46 git checkout
-b "add_sub1" &&
47 git submodule add .
/. sub1
&&
48 git config
-f .gitmodules submodule.sub1.ignore all
&&
49 git config submodule.sub1.ignore all
&&
50 git add .gitmodules
&&
51 git commit
-m "Add sub1" &&
52 git checkout
-b remove_sub1
&&
55 git checkout
-b "modify_sub1" "add_sub1" &&
56 git submodule update
&&
60 git checkout
-b "modifications" &&
63 git add file2 file3
&&
64 git commit
-m "modified file2 and added file3" &&
65 git push origin modifications
68 git commit
-m "Modify sub1" &&
70 git checkout
-b "replace_sub1_with_directory" "add_sub1" &&
71 git submodule update
&&
72 git
-C sub1 checkout modifications
&&
73 git
rm --cached sub1
&&
75 git config
-f .gitmodules
--remove-section "submodule.sub1" &&
76 git add .gitmodules sub
1/* &&
77 git commit
-m "Replace sub1 with directory" &&
78 git checkout
-b replace_directory_with_sub1
&&
81 git checkout
-b "replace_sub1_with_file" "add_sub1" &&
83 echo "content" >sub1
&&
85 git commit
-m "Replace sub1 with file" &&
86 git checkout
-b replace_file_with_sub1
&&
89 git checkout
-b "invalid_sub1" "add_sub1" &&
90 git update-index
--cacheinfo 160000 0123456789012345678901234567890123456789 sub1
&&
91 git commit
-m "Invalid sub1 commit" &&
92 git checkout
-b valid_sub1
&&
98 # Helper function to replace gitfile with .git directory
99 replace_gitfile_with_git_dir
() {
102 git_dir
="$(git rev-parse --git-dir)" &&
104 cp -R "$git_dir" .git
&&
105 GIT_WORK_TREE
=. git config
--unset core.worktree
109 # Test that the .git directory in the submodule is unchanged (except for the
110 # core.worktree setting, which appears only in $GIT_DIR/modules/$1/config).
111 # Call this function before test_submodule_content as the latter might
112 # write the index file leading to false positive index differences.
114 # Note that this only supports submodules at the root level of the
115 # superproject, with the default name, i.e. same as its path.
116 test_git_directory_is_unchanged
() {
118 cd ".git/modules/$1" &&
119 # does core.worktree point at the right place?
120 test "$(git config core.worktree)" = "../../../$1" &&
121 # remove it temporarily before comparing, as
122 # "$1/.git/config" lacks it...
123 git config
--unset core.worktree
125 diff -r ".git/modules/$1" "$1/.git" &&
127 # ... and then restore.
128 cd ".git/modules/$1" &&
129 git config core.worktree
"../../../$1"
133 # Helper function to be executed at the start of every test below, it sets up
134 # the submodule repo if it doesn't exist and configures the most problematic
135 # settings for diff.ignoreSubmodules.
137 (test -d submodule_update_repo || create_lib_submodule_repo
) &&
138 test_config_global
diff.ignoreSubmodules all
&&
139 test_config
diff.ignoreSubmodules all
142 # Helper function to bring work tree back into the state given by the
143 # commit. This includes trying to populate sub1 accordingly if it exists and
144 # should be updated to an existing commit.
145 reset_work_tree_to
() {
146 rm -rf submodule_update
&&
147 git clone submodule_update_repo submodule_update
&&
149 cd submodule_update
&&
151 git checkout
-f "$1" &&
152 git status
-u -s >actual
&&
153 test_must_be_empty actual
&&
154 sha1
=$
(git rev-parse
--revs-only HEAD
:sub1
) &&
155 if test -n "$sha1" &&
156 test $
(cd "sub1" && git rev-parse
--verify "$sha1^{commit}")
158 git submodule update
--init --recursive "sub1"
163 # Test that the superproject contains the content according to commit "$1"
164 # (the work tree must match the index for everything but submodules but the
165 # index must exactly match the given commit including any submodule SHA-1s).
166 test_superproject_content
() {
167 git diff-index
--cached "$1" >actual
&&
168 test_must_be_empty actual
&&
169 git diff-files
--ignore-submodules >actual
&&
170 test_must_be_empty actual
173 # Test that the given submodule at path "$1" contains the content according
174 # to the submodule commit recorded in the superproject's commit "$2"
175 test_submodule_content
() {
178 echo "test_submodule_content needs two arguments"
183 test -d "$submodule"/ &&
184 if ! test -f "$submodule"/.git
&& ! test -d "$submodule"/.git
186 echo "Submodule $submodule is not populated"
189 sha1
=$
(git rev-parse
--verify "$commit:$submodule") &&
192 echo "Couldn't retrieve SHA-1 of $submodule for $commit"
197 git status
-u -s >actual
&&
198 test_must_be_empty actual
&&
199 git
diff "$sha1" >actual
&&
200 test_must_be_empty actual
204 # Test that the following transitions are correctly handled:
205 # - Updated submodule
207 # - Removed submodule
208 # - Directory containing tracked files replaced by submodule
209 # - Submodule replaced by tracked files in directory
210 # - Submodule replaced by tracked file with the same name
211 # - tracked file replaced by submodule
213 # The default is that submodule contents aren't changed until "git submodule
214 # update" is run. And even then that command doesn't delete the work tree of
215 # a removed submodule.
217 # Removing a submodule containing a .git directory must fail even when forced
218 # to protect the history!
221 # Test that submodule contents are currently not updated when switching
222 # between commits that change a submodule.
223 test_submodule_switch
() {
225 ######################### Appearing submodule #########################
226 # Switching to a commit letting a submodule appear creates empty dir ...
227 if test "$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES" = 1
229 # Restoring stash fails to restore submodule index entry
234 test_expect_
$RESULT "$command: added submodule creates empty directory" '
236 reset_work_tree_to no_submodule &&
238 cd submodule_update &&
239 git branch -t add_sub1 origin/add_sub1 &&
241 test_superproject_content origin/add_sub1 &&
242 test_dir_is_empty sub1 &&
243 git submodule update --init --recursive &&
244 test_submodule_content sub1 origin/add_sub1
247 # ... and doesn't care if it already exists ...
248 test_expect_
$RESULT "$command: added submodule leaves existing empty directory alone" '
250 reset_work_tree_to no_submodule &&
252 cd submodule_update &&
254 git branch -t add_sub1 origin/add_sub1 &&
256 test_superproject_content origin/add_sub1 &&
257 test_dir_is_empty sub1 &&
258 git submodule update --init --recursive &&
259 test_submodule_content sub1 origin/add_sub1
262 # ... unless there is an untracked file in its place.
263 test_expect_success
"$command: added submodule doesn't remove untracked unignored file with same name" '
265 reset_work_tree_to no_submodule &&
267 cd submodule_update &&
268 git branch -t add_sub1 origin/add_sub1 &&
270 test_must_fail $command add_sub1 &&
271 test_superproject_content origin/no_submodule &&
272 test_must_be_empty sub1
275 # Replacing a tracked file with a submodule produces an empty
277 test_expect_
$RESULT "$command: replace tracked file with submodule creates empty directory" '
279 reset_work_tree_to replace_sub1_with_file &&
281 cd submodule_update &&
282 git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&
283 $command replace_file_with_sub1 &&
284 test_superproject_content origin/replace_file_with_sub1 &&
285 test_dir_is_empty sub1 &&
286 git submodule update --init --recursive &&
287 test_submodule_content sub1 origin/replace_file_with_sub1
290 # ... as does removing a directory with tracked files with a
292 if test "$KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR" = 1
294 # Non fast-forward merges fail with "Directory sub1 doesn't
295 # exist. sub1" because the empty submodule directory is not
301 test_expect_
$RESULT "$command: replace directory with submodule" '
303 reset_work_tree_to replace_sub1_with_directory &&
305 cd submodule_update &&
306 git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
307 $command replace_directory_with_sub1 &&
308 test_superproject_content origin/replace_directory_with_sub1 &&
309 test_dir_is_empty sub1 &&
310 git submodule update --init --recursive &&
311 test_submodule_content sub1 origin/replace_directory_with_sub1
315 ######################## Disappearing submodule #######################
316 # Removing a submodule doesn't remove its work tree ...
317 if test "$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES" = 1
323 test_expect_
$RESULT "$command: removed submodule leaves submodule directory and its contents in place" '
325 reset_work_tree_to add_sub1 &&
327 cd submodule_update &&
328 git branch -t remove_sub1 origin/remove_sub1 &&
329 $command remove_sub1 &&
330 test_superproject_content origin/remove_sub1 &&
331 test_submodule_content sub1 origin/add_sub1
334 # ... especially when it contains a .git directory.
335 test_expect_
$RESULT "$command: removed submodule leaves submodule containing a .git directory alone" '
337 reset_work_tree_to add_sub1 &&
339 cd submodule_update &&
340 git branch -t remove_sub1 origin/remove_sub1 &&
341 replace_gitfile_with_git_dir sub1 &&
342 $command remove_sub1 &&
343 test_superproject_content origin/remove_sub1 &&
344 test_git_directory_is_unchanged sub1 &&
345 test_submodule_content sub1 origin/add_sub1
348 # Replacing a submodule with files in a directory must fail as the
349 # submodule work tree isn't removed ...
350 if test "$KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES" = 1
352 # Non fast-forward merges attempt to merge the former
353 # submodule files with the newly checked out ones in the
354 # directory of the same name while it shouldn't.
359 test_expect_
$RESULT "$command: replace submodule with a directory must fail" '
361 reset_work_tree_to add_sub1 &&
363 cd submodule_update &&
364 git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
365 test_must_fail $command replace_sub1_with_directory &&
366 test_superproject_content origin/add_sub1 &&
367 test_submodule_content sub1 origin/add_sub1
370 # ... especially when it contains a .git directory.
371 test_expect_
$RESULT "$command: replace submodule containing a .git directory with a directory must fail" '
373 reset_work_tree_to add_sub1 &&
375 cd submodule_update &&
376 git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
377 replace_gitfile_with_git_dir sub1 &&
378 test_must_fail $command replace_sub1_with_directory &&
379 test_superproject_content origin/add_sub1 &&
380 test_git_directory_is_unchanged sub1 &&
381 test_submodule_content sub1 origin/add_sub1
384 # Replacing it with a file must fail as it could throw away any local
385 # work tree changes ...
386 test_expect_failure
"$command: replace submodule with a file must fail" '
388 reset_work_tree_to add_sub1 &&
390 cd submodule_update &&
391 git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
392 test_must_fail $command replace_sub1_with_file &&
393 test_superproject_content origin/add_sub1 &&
394 test_submodule_content sub1 origin/add_sub1
397 # ... or even destroy unpushed parts of submodule history if that
398 # still uses a .git directory.
399 test_expect_failure
"$command: replace submodule containing a .git directory with a file must fail" '
401 reset_work_tree_to add_sub1 &&
403 cd submodule_update &&
404 git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
405 replace_gitfile_with_git_dir sub1 &&
406 test_must_fail $command replace_sub1_with_file &&
407 test_superproject_content origin/add_sub1 &&
408 test_git_directory_is_unchanged sub1 &&
409 test_submodule_content sub1 origin/add_sub1
413 ########################## Modified submodule #########################
414 # Updating a submodule sha1 doesn't update the submodule's work tree
415 if test "$KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT" = 1
417 # When cherry picking a SHA-1 update for an ignored submodule
418 # the commit incorrectly fails with "The previous cherry-pick
419 # is now empty, possibly due to conflict resolution."
424 test_expect_
$RESULT "$command: modified submodule does not update submodule work tree" '
426 reset_work_tree_to add_sub1 &&
428 cd submodule_update &&
429 git branch -t modify_sub1 origin/modify_sub1 &&
430 $command modify_sub1 &&
431 test_superproject_content origin/modify_sub1 &&
432 test_submodule_content sub1 origin/add_sub1 &&
433 git submodule update &&
434 test_submodule_content sub1 origin/modify_sub1
438 # Updating a submodule to an invalid sha1 doesn't update the
439 # submodule's work tree, subsequent update will fail
440 test_expect_
$RESULT "$command: modified submodule does not update submodule work tree to invalid commit" '
442 reset_work_tree_to add_sub1 &&
444 cd submodule_update &&
445 git branch -t invalid_sub1 origin/invalid_sub1 &&
446 $command invalid_sub1 &&
447 test_superproject_content origin/invalid_sub1 &&
448 test_submodule_content sub1 origin/add_sub1 &&
449 test_must_fail git submodule update &&
450 test_submodule_content sub1 origin/add_sub1
453 # Updating a submodule from an invalid sha1 doesn't update the
454 # submodule's work tree, subsequent update will succeed
455 test_expect_
$RESULT "$command: modified submodule does not update submodule work tree from invalid commit" '
457 reset_work_tree_to invalid_sub1 &&
459 cd submodule_update &&
460 git branch -t valid_sub1 origin/valid_sub1 &&
461 $command valid_sub1 &&
462 test_superproject_content origin/valid_sub1 &&
463 test_dir_is_empty sub1 &&
464 git submodule update --init --recursive &&
465 test_submodule_content sub1 origin/valid_sub1
470 # Test that submodule contents are currently not updated when switching
471 # between commits that change a submodule, but throwing away local changes in
472 # the superproject is allowed.
473 test_submodule_forced_switch
() {
475 ######################### Appearing submodule #########################
476 # Switching to a commit letting a submodule appear creates empty dir ...
477 test_expect_success
"$command: added submodule creates empty directory" '
479 reset_work_tree_to no_submodule &&
481 cd submodule_update &&
482 git branch -t add_sub1 origin/add_sub1 &&
484 test_superproject_content origin/add_sub1 &&
485 test_dir_is_empty sub1 &&
486 git submodule update --init --recursive &&
487 test_submodule_content sub1 origin/add_sub1
490 # ... and doesn't care if it already exists ...
491 test_expect_success
"$command: added submodule leaves existing empty directory alone" '
493 reset_work_tree_to no_submodule &&
495 cd submodule_update &&
496 git branch -t add_sub1 origin/add_sub1 &&
499 test_superproject_content origin/add_sub1 &&
500 test_dir_is_empty sub1 &&
501 git submodule update --init --recursive &&
502 test_submodule_content sub1 origin/add_sub1
505 # ... unless there is an untracked file in its place.
506 test_expect_success
"$command: added submodule does remove untracked unignored file with same name when forced" '
508 reset_work_tree_to no_submodule &&
510 cd submodule_update &&
511 git branch -t add_sub1 origin/add_sub1 &&
514 test_superproject_content origin/add_sub1 &&
515 test_dir_is_empty sub1
518 # Replacing a tracked file with a submodule produces an empty
520 test_expect_success
"$command: replace tracked file with submodule creates empty directory" '
522 reset_work_tree_to replace_sub1_with_file &&
524 cd submodule_update &&
525 git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&
526 $command replace_file_with_sub1 &&
527 test_superproject_content origin/replace_file_with_sub1 &&
528 test_dir_is_empty sub1 &&
529 git submodule update --init --recursive &&
530 test_submodule_content sub1 origin/replace_file_with_sub1
533 # ... as does removing a directory with tracked files with a
535 test_expect_success
"$command: replace directory with submodule" '
537 reset_work_tree_to replace_sub1_with_directory &&
539 cd submodule_update &&
540 git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
541 $command replace_directory_with_sub1 &&
542 test_superproject_content origin/replace_directory_with_sub1 &&
543 test_dir_is_empty sub1 &&
544 git submodule update --init --recursive &&
545 test_submodule_content sub1 origin/replace_directory_with_sub1
549 ######################## Disappearing submodule #######################
550 # Removing a submodule doesn't remove its work tree ...
551 test_expect_success
"$command: removed submodule leaves submodule directory and its contents in place" '
553 reset_work_tree_to add_sub1 &&
555 cd submodule_update &&
556 git branch -t remove_sub1 origin/remove_sub1 &&
557 $command remove_sub1 &&
558 test_superproject_content origin/remove_sub1 &&
559 test_submodule_content sub1 origin/add_sub1
562 # ... especially when it contains a .git directory.
563 test_expect_success
"$command: removed submodule leaves submodule containing a .git directory alone" '
565 reset_work_tree_to add_sub1 &&
567 cd submodule_update &&
568 git branch -t remove_sub1 origin/remove_sub1 &&
569 replace_gitfile_with_git_dir sub1 &&
570 $command remove_sub1 &&
571 test_superproject_content origin/remove_sub1 &&
572 test_git_directory_is_unchanged sub1 &&
573 test_submodule_content sub1 origin/add_sub1
576 # Replacing a submodule with files in a directory must fail as the
577 # submodule work tree isn't removed ...
578 test_expect_failure
"$command: replace submodule with a directory must fail" '
580 reset_work_tree_to add_sub1 &&
582 cd submodule_update &&
583 git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
584 test_must_fail $command replace_sub1_with_directory &&
585 test_superproject_content origin/add_sub1 &&
586 test_submodule_content sub1 origin/add_sub1
589 # ... especially when it contains a .git directory.
590 test_expect_failure
"$command: replace submodule containing a .git directory with a directory must fail" '
592 reset_work_tree_to add_sub1 &&
594 cd submodule_update &&
595 git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
596 replace_gitfile_with_git_dir sub1 &&
597 test_must_fail $command replace_sub1_with_directory &&
598 test_superproject_content origin/add_sub1 &&
599 test_git_directory_is_unchanged sub1 &&
600 test_submodule_content sub1 origin/add_sub1
603 # Replacing it with a file must fail as it could throw away any local
604 # work tree changes ...
605 test_expect_failure
"$command: replace submodule with a file must fail" '
607 reset_work_tree_to add_sub1 &&
609 cd submodule_update &&
610 git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
611 test_must_fail $command replace_sub1_with_file &&
612 test_superproject_content origin/add_sub1 &&
613 test_submodule_content sub1 origin/add_sub1
616 # ... or even destroy unpushed parts of submodule history if that
617 # still uses a .git directory.
618 test_expect_failure
"$command: replace submodule containing a .git directory with a file must fail" '
620 reset_work_tree_to add_sub1 &&
622 cd submodule_update &&
623 git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
624 replace_gitfile_with_git_dir sub1 &&
625 test_must_fail $command replace_sub1_with_file &&
626 test_superproject_content origin/add_sub1 &&
627 test_git_directory_is_unchanged sub1 &&
628 test_submodule_content sub1 origin/add_sub1
632 ########################## Modified submodule #########################
633 # Updating a submodule sha1 doesn't update the submodule's work tree
634 test_expect_success
"$command: modified submodule does not update submodule work tree" '
636 reset_work_tree_to add_sub1 &&
638 cd submodule_update &&
639 git branch -t modify_sub1 origin/modify_sub1 &&
640 $command modify_sub1 &&
641 test_superproject_content origin/modify_sub1 &&
642 test_submodule_content sub1 origin/add_sub1 &&
643 git submodule update &&
644 test_submodule_content sub1 origin/modify_sub1
647 # Updating a submodule to an invalid sha1 doesn't update the
648 # submodule's work tree, subsequent update will fail
649 test_expect_success
"$command: modified submodule does not update submodule work tree to invalid commit" '
651 reset_work_tree_to add_sub1 &&
653 cd submodule_update &&
654 git branch -t invalid_sub1 origin/invalid_sub1 &&
655 $command invalid_sub1 &&
656 test_superproject_content origin/invalid_sub1 &&
657 test_submodule_content sub1 origin/add_sub1 &&
658 test_must_fail git submodule update &&
659 test_submodule_content sub1 origin/add_sub1
662 # Updating a submodule from an invalid sha1 doesn't update the
663 # submodule's work tree, subsequent update will succeed
664 test_expect_success
"$command: modified submodule does not update submodule work tree from invalid commit" '
666 reset_work_tree_to invalid_sub1 &&
668 cd submodule_update &&
669 git branch -t valid_sub1 origin/valid_sub1 &&
670 $command valid_sub1 &&
671 test_superproject_content origin/valid_sub1 &&
672 test_dir_is_empty sub1 &&
673 git submodule update --init --recursive &&
674 test_submodule_content sub1 origin/valid_sub1