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)
26 # O------O-----------O---------O
27 # ^ \ ^ replace_directory_with_sub1
28 # | \ replace_sub1_with_directory
31 # \ ^ replace_file_with_sub1
32 # \ replace_sub1_with_file
39 create_lib_submodule_repo () {
40 git init submodule_update_sub1 &&
42 cd submodule_update_sub1 &&
43 echo "expect" >>.gitignore &&
44 echo "actual" >>.gitignore &&
47 git add .gitignore file1 file2 &&
48 git commit -m "Base inside first submodule" &&
49 git branch "no_submodule"
51 git init submodule_update_repo &&
53 cd submodule_update_repo &&
54 echo "expect" >>.gitignore &&
55 echo "actual" >>.gitignore &&
58 git add .gitignore file1 file2 &&
59 git commit -m "Base" &&
60 git branch "no_submodule" &&
62 git checkout -b "add_sub1" &&
63 git submodule add ../submodule_update_sub1 sub1 &&
64 git config -f .gitmodules submodule.sub1.ignore all &&
65 git config submodule.sub1.ignore all &&
66 git add .gitmodules &&
67 git commit -m "Add sub1" &&
69 git checkout -b remove_sub1 add_sub1 &&
72 git checkout -b modify_sub1 add_sub1 &&
73 git submodule update &&
77 git checkout -b "modifications" &&
80 git add file2 file3 &&
81 git commit -m "modified file2 and added file3" &&
82 git push origin modifications
85 git commit -m "Modify sub1" &&
87 git checkout -b replace_sub1_with_directory add_sub1 &&
88 git submodule update &&
89 git -C sub1 checkout modifications &&
90 git rm --cached sub1 &&
92 git config -f .gitmodules --remove-section "submodule.sub1" &&
93 git add .gitmodules sub1/* &&
94 git commit -m "Replace sub1 with directory" &&
96 git checkout -b replace_directory_with_sub1 &&
99 git checkout -b replace_sub1_with_file add_sub1 &&
101 echo "content" >sub1 &&
103 git commit -m "Replace sub1 with file" &&
105 git checkout -b replace_file_with_sub1 &&
108 git checkout -b invalid_sub1 add_sub1 &&
109 git update-index --cacheinfo 160000 0123456789012345678901234567890123456789 sub1 &&
110 git commit -m "Invalid sub1 commit" &&
111 git checkout -b valid_sub1 &&
118 # Helper function to replace gitfile with .git directory
119 replace_gitfile_with_git_dir () {
122 git_dir="$(git rev-parse --git-dir)" &&
124 cp -R "$git_dir" .git &&
125 GIT_WORK_TREE=. git config --unset core.worktree
129 # Test that the .git directory in the submodule is unchanged (except for the
130 # core.worktree setting, which appears only in $GIT_DIR/modules/$1/config).
131 # Call this function before test_submodule_content as the latter might
132 # write the index file leading to false positive index differences.
134 # Note that this only supports submodules at the root level of the
135 # superproject, with the default name, i.e. same as its path.
136 test_git_directory_is_unchanged () {
138 cd ".git/modules/$1" &&
139 # does core.worktree point at the right place?
140 test "$(git config core.worktree)" = "../../../$1" &&
141 # remove it temporarily before comparing, as
142 # "$1/.git/config" lacks it...
143 git config --unset core.worktree
145 diff -r ".git/modules/$1" "$1/.git" &&
147 # ... and then restore.
148 cd ".git/modules/$1" &&
149 git config core.worktree "../../../$1"
153 # Helper function to be executed at the start of every test below, it sets up
154 # the submodule repo if it doesn't exist and configures the most problematic
155 # settings for diff.ignoreSubmodules.
157 (test -d submodule_update_repo || create_lib_submodule_repo) &&
158 test_config_global diff.ignoreSubmodules all &&
159 test_config diff.ignoreSubmodules all
162 # Helper function to bring work tree back into the state given by the
163 # commit. This includes trying to populate sub1 accordingly if it exists and
164 # should be updated to an existing commit.
165 reset_work_tree_to () {
166 rm -rf submodule_update &&
167 git clone submodule_update_repo submodule_update &&
169 cd submodule_update &&
171 git checkout -f "$1" &&
172 git status -u -s >actual &&
173 test_must_be_empty actual &&
174 sha1=$(git rev-parse --revs-only HEAD:sub1) &&
175 if test -n "$sha1" &&
176 test $(cd "../submodule_update_sub1" && git rev-parse --verify "$sha1^{commit}")
178 git submodule update --init --recursive "sub1"
183 # Test that the superproject contains the content according to commit "$1"
184 # (the work tree must match the index for everything but submodules but the
185 # index must exactly match the given commit including any submodule SHA-1s).
186 test_superproject_content () {
187 git diff-index --cached "$1" >actual &&
188 test_must_be_empty actual &&
189 git diff-files --ignore-submodules >actual &&
190 test_must_be_empty actual
193 # Test that the given submodule at path "$1" contains the content according
194 # to the submodule commit recorded in the superproject's commit "$2"
195 test_submodule_content () {
198 echo "test_submodule_content needs two arguments"
203 test -d "$submodule"/ &&
204 if ! test -f "$submodule"/.git && ! test -d "$submodule"/.git
206 echo "Submodule $submodule is not populated"
209 sha1=$(git rev-parse --verify "$commit:$submodule") &&
212 echo "Couldn't retrieve SHA-1 of $submodule for $commit"
217 git status -u -s >actual &&
218 test_must_be_empty actual &&
219 git diff "$sha1" >actual &&
220 test_must_be_empty actual
224 # Test that the following transitions are correctly handled:
225 # - Updated submodule
227 # - Removed submodule
228 # - Directory containing tracked files replaced by submodule
229 # - Submodule replaced by tracked files in directory
230 # - Submodule replaced by tracked file with the same name
231 # - tracked file replaced by submodule
233 # The default is that submodule contents aren't changed until "git submodule
234 # update" is run. And even then that command doesn't delete the work tree of
235 # a removed submodule.
237 # Removing a submodule containing a .git directory must fail even when forced
238 # to protect the history!
241 # Test that submodule contents are currently not updated when switching
242 # between commits that change a submodule.
243 test_submodule_switch () {
245 ######################### Appearing submodule #########################
246 # Switching to a commit letting a submodule appear creates empty dir ...
247 if test "$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES" = 1
249 # Restoring stash fails to restore submodule index entry
254 test_expect_$RESULT "$command: added submodule creates empty directory" '
256 reset_work_tree_to no_submodule &&
258 cd submodule_update &&
259 git branch -t add_sub1 origin/add_sub1 &&
261 test_superproject_content origin/add_sub1 &&
262 test_dir_is_empty sub1 &&
263 git submodule update --init --recursive &&
264 test_submodule_content sub1 origin/add_sub1
267 # ... and doesn't care if it already exists ...
268 test_expect_$RESULT "$command: added submodule leaves existing empty directory alone" '
270 reset_work_tree_to no_submodule &&
272 cd submodule_update &&
274 git branch -t add_sub1 origin/add_sub1 &&
276 test_superproject_content origin/add_sub1 &&
277 test_dir_is_empty sub1 &&
278 git submodule update --init --recursive &&
279 test_submodule_content sub1 origin/add_sub1
282 # ... unless there is an untracked file in its place.
283 test_expect_success "$command: added submodule doesn't remove untracked unignored file with same name" '
285 reset_work_tree_to no_submodule &&
287 cd submodule_update &&
288 git branch -t add_sub1 origin/add_sub1 &&
290 test_must_fail $command add_sub1 &&
291 test_superproject_content origin/no_submodule &&
292 test_must_be_empty sub1
295 # Replacing a tracked file with a submodule produces an empty
297 test_expect_$RESULT "$command: replace tracked file with submodule creates empty directory" '
299 reset_work_tree_to replace_sub1_with_file &&
301 cd submodule_update &&
302 git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&
303 $command replace_file_with_sub1 &&
304 test_superproject_content origin/replace_file_with_sub1 &&
305 test_dir_is_empty sub1 &&
306 git submodule update --init --recursive &&
307 test_submodule_content sub1 origin/replace_file_with_sub1
310 # ... as does removing a directory with tracked files with a
312 if test "$KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR" = 1
314 # Non fast-forward merges fail with "Directory sub1 doesn't
315 # exist. sub1" because the empty submodule directory is not
321 test_expect_$RESULT "$command: replace directory with submodule" '
323 reset_work_tree_to replace_sub1_with_directory &&
325 cd submodule_update &&
326 git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
327 $command replace_directory_with_sub1 &&
328 test_superproject_content origin/replace_directory_with_sub1 &&
329 test_dir_is_empty sub1 &&
330 git submodule update --init --recursive &&
331 test_submodule_content sub1 origin/replace_directory_with_sub1
335 ######################## Disappearing submodule #######################
336 # Removing a submodule doesn't remove its work tree ...
337 if test "$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES" = 1
343 test_expect_$RESULT "$command: removed submodule leaves submodule directory and its contents in place" '
345 reset_work_tree_to add_sub1 &&
347 cd submodule_update &&
348 git branch -t remove_sub1 origin/remove_sub1 &&
349 $command remove_sub1 &&
350 test_superproject_content origin/remove_sub1 &&
351 test_submodule_content sub1 origin/add_sub1
354 # ... especially when it contains a .git directory.
355 test_expect_$RESULT "$command: removed submodule leaves submodule containing a .git directory alone" '
357 reset_work_tree_to add_sub1 &&
359 cd submodule_update &&
360 git branch -t remove_sub1 origin/remove_sub1 &&
361 replace_gitfile_with_git_dir sub1 &&
362 $command remove_sub1 &&
363 test_superproject_content origin/remove_sub1 &&
364 test_git_directory_is_unchanged sub1 &&
365 test_submodule_content sub1 origin/add_sub1
368 # Replacing a submodule with files in a directory must fail as the
369 # submodule work tree isn't removed ...
370 if test "$KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES" = 1
372 # Non fast-forward merges attempt to merge the former
373 # submodule files with the newly checked out ones in the
374 # directory of the same name while it shouldn't.
379 test_expect_$RESULT "$command: replace submodule with a directory must fail" '
381 reset_work_tree_to add_sub1 &&
383 cd submodule_update &&
384 git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
385 test_must_fail $command replace_sub1_with_directory &&
386 test_superproject_content origin/add_sub1 &&
387 test_submodule_content sub1 origin/add_sub1
390 # ... especially when it contains a .git directory.
391 test_expect_$RESULT "$command: replace submodule containing a .git directory with a directory must fail" '
393 reset_work_tree_to add_sub1 &&
395 cd submodule_update &&
396 git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
397 replace_gitfile_with_git_dir sub1 &&
398 test_must_fail $command replace_sub1_with_directory &&
399 test_superproject_content origin/add_sub1 &&
400 test_git_directory_is_unchanged sub1 &&
401 test_submodule_content sub1 origin/add_sub1
404 # Replacing it with a file must fail as it could throw away any local
405 # work tree changes ...
406 test_expect_failure "$command: replace submodule with a file must fail" '
408 reset_work_tree_to add_sub1 &&
410 cd submodule_update &&
411 git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
412 test_must_fail $command replace_sub1_with_file &&
413 test_superproject_content origin/add_sub1 &&
414 test_submodule_content sub1 origin/add_sub1
417 # ... or even destroy unpushed parts of submodule history if that
418 # still uses a .git directory.
419 test_expect_failure "$command: replace submodule containing a .git directory with a file must fail" '
421 reset_work_tree_to add_sub1 &&
423 cd submodule_update &&
424 git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
425 replace_gitfile_with_git_dir sub1 &&
426 test_must_fail $command replace_sub1_with_file &&
427 test_superproject_content origin/add_sub1 &&
428 test_git_directory_is_unchanged sub1 &&
429 test_submodule_content sub1 origin/add_sub1
433 ########################## Modified submodule #########################
434 # Updating a submodule sha1 doesn't update the submodule's work tree
435 if test "$KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT" = 1
437 # When cherry picking a SHA-1 update for an ignored submodule
438 # the commit incorrectly fails with "The previous cherry-pick
439 # is now empty, possibly due to conflict resolution."
444 test_expect_$RESULT "$command: modified submodule does not update submodule work tree" '
446 reset_work_tree_to add_sub1 &&
448 cd submodule_update &&
449 git branch -t modify_sub1 origin/modify_sub1 &&
450 $command modify_sub1 &&
451 test_superproject_content origin/modify_sub1 &&
452 test_submodule_content sub1 origin/add_sub1 &&
453 git submodule update &&
454 test_submodule_content sub1 origin/modify_sub1
458 # Updating a submodule to an invalid sha1 doesn't update the
459 # submodule's work tree, subsequent update will fail
460 test_expect_$RESULT "$command: modified submodule does not update submodule work tree to invalid commit" '
462 reset_work_tree_to add_sub1 &&
464 cd submodule_update &&
465 git branch -t invalid_sub1 origin/invalid_sub1 &&
466 $command invalid_sub1 &&
467 test_superproject_content origin/invalid_sub1 &&
468 test_submodule_content sub1 origin/add_sub1 &&
469 test_must_fail git submodule update &&
470 test_submodule_content sub1 origin/add_sub1
473 # Updating a submodule from an invalid sha1 doesn't update the
474 # submodule's work tree, subsequent update will succeed
475 test_expect_$RESULT "$command: modified submodule does not update submodule work tree from invalid commit" '
477 reset_work_tree_to invalid_sub1 &&
479 cd submodule_update &&
480 git branch -t valid_sub1 origin/valid_sub1 &&
481 $command valid_sub1 &&
482 test_superproject_content origin/valid_sub1 &&
483 test_dir_is_empty sub1 &&
484 git submodule update --init --recursive &&
485 test_submodule_content sub1 origin/valid_sub1
490 # Test that submodule contents are currently not updated when switching
491 # between commits that change a submodule, but throwing away local changes in
492 # the superproject is allowed.
493 test_submodule_forced_switch () {
495 ######################### Appearing submodule #########################
496 # Switching to a commit letting a submodule appear creates empty dir ...
497 test_expect_success "$command: added submodule creates empty directory" '
499 reset_work_tree_to no_submodule &&
501 cd submodule_update &&
502 git branch -t add_sub1 origin/add_sub1 &&
504 test_superproject_content origin/add_sub1 &&
505 test_dir_is_empty sub1 &&
506 git submodule update --init --recursive &&
507 test_submodule_content sub1 origin/add_sub1
510 # ... and doesn't care if it already exists ...
511 test_expect_success "$command: added submodule leaves existing empty directory alone" '
513 reset_work_tree_to no_submodule &&
515 cd submodule_update &&
516 git branch -t add_sub1 origin/add_sub1 &&
519 test_superproject_content origin/add_sub1 &&
520 test_dir_is_empty sub1 &&
521 git submodule update --init --recursive &&
522 test_submodule_content sub1 origin/add_sub1
525 # ... unless there is an untracked file in its place.
526 test_expect_success "$command: added submodule does remove untracked unignored file with same name when forced" '
528 reset_work_tree_to no_submodule &&
530 cd submodule_update &&
531 git branch -t add_sub1 origin/add_sub1 &&
534 test_superproject_content origin/add_sub1 &&
535 test_dir_is_empty sub1
538 # Replacing a tracked file with a submodule produces an empty
540 test_expect_success "$command: replace tracked file with submodule creates empty directory" '
542 reset_work_tree_to replace_sub1_with_file &&
544 cd submodule_update &&
545 git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&
546 $command replace_file_with_sub1 &&
547 test_superproject_content origin/replace_file_with_sub1 &&
548 test_dir_is_empty sub1 &&
549 git submodule update --init --recursive &&
550 test_submodule_content sub1 origin/replace_file_with_sub1
553 # ... as does removing a directory with tracked files with a
555 test_expect_success "$command: replace directory with submodule" '
557 reset_work_tree_to replace_sub1_with_directory &&
559 cd submodule_update &&
560 git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
561 $command replace_directory_with_sub1 &&
562 test_superproject_content origin/replace_directory_with_sub1 &&
563 test_dir_is_empty sub1 &&
564 git submodule update --init --recursive &&
565 test_submodule_content sub1 origin/replace_directory_with_sub1
569 ######################## Disappearing submodule #######################
570 # Removing a submodule doesn't remove its work tree ...
571 test_expect_success "$command: removed submodule leaves submodule directory and its contents in place" '
573 reset_work_tree_to add_sub1 &&
575 cd submodule_update &&
576 git branch -t remove_sub1 origin/remove_sub1 &&
577 $command remove_sub1 &&
578 test_superproject_content origin/remove_sub1 &&
579 test_submodule_content sub1 origin/add_sub1
582 # ... especially when it contains a .git directory.
583 test_expect_success "$command: removed submodule leaves submodule containing a .git directory alone" '
585 reset_work_tree_to add_sub1 &&
587 cd submodule_update &&
588 git branch -t remove_sub1 origin/remove_sub1 &&
589 replace_gitfile_with_git_dir sub1 &&
590 $command remove_sub1 &&
591 test_superproject_content origin/remove_sub1 &&
592 test_git_directory_is_unchanged sub1 &&
593 test_submodule_content sub1 origin/add_sub1
596 # Replacing a submodule with files in a directory must fail as the
597 # submodule work tree isn't removed ...
598 test_expect_failure "$command: replace submodule with a directory must fail" '
600 reset_work_tree_to add_sub1 &&
602 cd submodule_update &&
603 git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
604 test_must_fail $command replace_sub1_with_directory &&
605 test_superproject_content origin/add_sub1 &&
606 test_submodule_content sub1 origin/add_sub1
609 # ... especially when it contains a .git directory.
610 test_expect_failure "$command: replace submodule containing a .git directory with a directory must fail" '
612 reset_work_tree_to add_sub1 &&
614 cd submodule_update &&
615 git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
616 replace_gitfile_with_git_dir sub1 &&
617 test_must_fail $command replace_sub1_with_directory &&
618 test_superproject_content origin/add_sub1 &&
619 test_git_directory_is_unchanged sub1 &&
620 test_submodule_content sub1 origin/add_sub1
623 # Replacing it with a file must fail as it could throw away any local
624 # work tree changes ...
625 test_expect_failure "$command: replace submodule with a file must fail" '
627 reset_work_tree_to add_sub1 &&
629 cd submodule_update &&
630 git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
631 test_must_fail $command replace_sub1_with_file &&
632 test_superproject_content origin/add_sub1 &&
633 test_submodule_content sub1 origin/add_sub1
636 # ... or even destroy unpushed parts of submodule history if that
637 # still uses a .git directory.
638 test_expect_failure "$command: replace submodule containing a .git directory with a file must fail" '
640 reset_work_tree_to add_sub1 &&
642 cd submodule_update &&
643 git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
644 replace_gitfile_with_git_dir sub1 &&
645 test_must_fail $command replace_sub1_with_file &&
646 test_superproject_content origin/add_sub1 &&
647 test_git_directory_is_unchanged sub1 &&
648 test_submodule_content sub1 origin/add_sub1
652 ########################## Modified submodule #########################
653 # Updating a submodule sha1 doesn't update the submodule's work tree
654 test_expect_success "$command: modified submodule does not update submodule work tree" '
656 reset_work_tree_to add_sub1 &&
658 cd submodule_update &&
659 git branch -t modify_sub1 origin/modify_sub1 &&
660 $command modify_sub1 &&
661 test_superproject_content origin/modify_sub1 &&
662 test_submodule_content sub1 origin/add_sub1 &&
663 git submodule update &&
664 test_submodule_content sub1 origin/modify_sub1
667 # Updating a submodule to an invalid sha1 doesn't update the
668 # submodule's work tree, subsequent update will fail
669 test_expect_success "$command: modified submodule does not update submodule work tree to invalid commit" '
671 reset_work_tree_to add_sub1 &&
673 cd submodule_update &&
674 git branch -t invalid_sub1 origin/invalid_sub1 &&
675 $command invalid_sub1 &&
676 test_superproject_content origin/invalid_sub1 &&
677 test_submodule_content sub1 origin/add_sub1 &&
678 test_must_fail git submodule update &&
679 test_submodule_content sub1 origin/add_sub1
682 # Updating a submodule from an invalid sha1 doesn't update the
683 # submodule's work tree, subsequent update will succeed
684 test_expect_success "$command: modified submodule does not update submodule work tree from invalid commit" '
686 reset_work_tree_to invalid_sub1 &&
688 cd submodule_update &&
689 git branch -t valid_sub1 origin/valid_sub1 &&
690 $command valid_sub1 &&
691 test_superproject_content origin/valid_sub1 &&
692 test_dir_is_empty sub1 &&
693 git submodule update --init --recursive &&
694 test_submodule_content sub1 origin/valid_sub1