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_repo &&
42 cd submodule_update_repo &&
43 echo "expect" >>.gitignore &&
44 echo "actual" >>.gitignore &&
47 git add .gitignore file1 file2 &&
48 git commit -m "Base" &&
49 git branch "no_submodule" &&
51 git checkout -b "add_sub1" &&
52 git submodule add ./. sub1 &&
53 git config -f .gitmodules submodule.sub1.ignore all &&
54 git config submodule.sub1.ignore all &&
55 git add .gitmodules &&
56 git commit -m "Add sub1" &&
58 git checkout -b remove_sub1 add_sub1 &&
61 git checkout -b modify_sub1 add_sub1 &&
62 git submodule update &&
66 git checkout -b "modifications" &&
69 git add file2 file3 &&
70 git commit -m "modified file2 and added file3" &&
71 git push origin modifications
74 git commit -m "Modify sub1" &&
76 git checkout -b replace_sub1_with_directory add_sub1 &&
77 git submodule update &&
78 git -C sub1 checkout modifications &&
79 git rm --cached sub1 &&
81 git config -f .gitmodules --remove-section "submodule.sub1" &&
82 git add .gitmodules sub1/* &&
83 git commit -m "Replace sub1 with directory" &&
85 git checkout -b replace_directory_with_sub1 &&
88 git checkout -b replace_sub1_with_file add_sub1 &&
90 echo "content" >sub1 &&
92 git commit -m "Replace sub1 with file" &&
94 git checkout -b replace_file_with_sub1 &&
97 git checkout -b invalid_sub1 add_sub1 &&
98 git update-index --cacheinfo 160000 0123456789012345678901234567890123456789 sub1 &&
99 git commit -m "Invalid sub1 commit" &&
100 git checkout -b valid_sub1 &&
107 # Helper function to replace gitfile with .git directory
108 replace_gitfile_with_git_dir () {
111 git_dir="$(git rev-parse --git-dir)" &&
113 cp -R "$git_dir" .git &&
114 GIT_WORK_TREE=. git config --unset core.worktree
118 # Test that the .git directory in the submodule is unchanged (except for the
119 # core.worktree setting, which appears only in $GIT_DIR/modules/$1/config).
120 # Call this function before test_submodule_content as the latter might
121 # write the index file leading to false positive index differences.
123 # Note that this only supports submodules at the root level of the
124 # superproject, with the default name, i.e. same as its path.
125 test_git_directory_is_unchanged () {
127 cd ".git/modules/$1" &&
128 # does core.worktree point at the right place?
129 test "$(git config core.worktree)" = "../../../$1" &&
130 # remove it temporarily before comparing, as
131 # "$1/.git/config" lacks it...
132 git config --unset core.worktree
134 diff -r ".git/modules/$1" "$1/.git" &&
136 # ... and then restore.
137 cd ".git/modules/$1" &&
138 git config core.worktree "../../../$1"
142 # Helper function to be executed at the start of every test below, it sets up
143 # the submodule repo if it doesn't exist and configures the most problematic
144 # settings for diff.ignoreSubmodules.
146 (test -d submodule_update_repo || create_lib_submodule_repo) &&
147 test_config_global diff.ignoreSubmodules all &&
148 test_config diff.ignoreSubmodules all
151 # Helper function to bring work tree back into the state given by the
152 # commit. This includes trying to populate sub1 accordingly if it exists and
153 # should be updated to an existing commit.
154 reset_work_tree_to () {
155 rm -rf submodule_update &&
156 git clone submodule_update_repo submodule_update &&
158 cd submodule_update &&
160 git checkout -f "$1" &&
161 git status -u -s >actual &&
162 test_must_be_empty actual &&
163 sha1=$(git rev-parse --revs-only HEAD:sub1) &&
164 if test -n "$sha1" &&
165 test $(cd "sub1" && git rev-parse --verify "$sha1^{commit}")
167 git submodule update --init --recursive "sub1"
172 # Test that the superproject contains the content according to commit "$1"
173 # (the work tree must match the index for everything but submodules but the
174 # index must exactly match the given commit including any submodule SHA-1s).
175 test_superproject_content () {
176 git diff-index --cached "$1" >actual &&
177 test_must_be_empty actual &&
178 git diff-files --ignore-submodules >actual &&
179 test_must_be_empty actual
182 # Test that the given submodule at path "$1" contains the content according
183 # to the submodule commit recorded in the superproject's commit "$2"
184 test_submodule_content () {
187 echo "test_submodule_content needs two arguments"
192 test -d "$submodule"/ &&
193 if ! test -f "$submodule"/.git && ! test -d "$submodule"/.git
195 echo "Submodule $submodule is not populated"
198 sha1=$(git rev-parse --verify "$commit:$submodule") &&
201 echo "Couldn't retrieve SHA-1 of $submodule for $commit"
206 git status -u -s >actual &&
207 test_must_be_empty actual &&
208 git diff "$sha1" >actual &&
209 test_must_be_empty actual
213 # Test that the following transitions are correctly handled:
214 # - Updated submodule
216 # - Removed submodule
217 # - Directory containing tracked files replaced by submodule
218 # - Submodule replaced by tracked files in directory
219 # - Submodule replaced by tracked file with the same name
220 # - tracked file replaced by submodule
222 # The default is that submodule contents aren't changed until "git submodule
223 # update" is run. And even then that command doesn't delete the work tree of
224 # a removed submodule.
226 # Removing a submodule containing a .git directory must fail even when forced
227 # to protect the history!
230 # Test that submodule contents are currently not updated when switching
231 # between commits that change a submodule.
232 test_submodule_switch () {
234 ######################### Appearing submodule #########################
235 # Switching to a commit letting a submodule appear creates empty dir ...
236 if test "$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES" = 1
238 # Restoring stash fails to restore submodule index entry
243 test_expect_$RESULT "$command: added submodule creates empty directory" '
245 reset_work_tree_to no_submodule &&
247 cd submodule_update &&
248 git branch -t add_sub1 origin/add_sub1 &&
250 test_superproject_content origin/add_sub1 &&
251 test_dir_is_empty sub1 &&
252 git submodule update --init --recursive &&
253 test_submodule_content sub1 origin/add_sub1
256 # ... and doesn't care if it already exists ...
257 test_expect_$RESULT "$command: added submodule leaves existing empty directory alone" '
259 reset_work_tree_to no_submodule &&
261 cd submodule_update &&
263 git branch -t add_sub1 origin/add_sub1 &&
265 test_superproject_content origin/add_sub1 &&
266 test_dir_is_empty sub1 &&
267 git submodule update --init --recursive &&
268 test_submodule_content sub1 origin/add_sub1
271 # ... unless there is an untracked file in its place.
272 test_expect_success "$command: added submodule doesn't remove untracked unignored file with same name" '
274 reset_work_tree_to no_submodule &&
276 cd submodule_update &&
277 git branch -t add_sub1 origin/add_sub1 &&
279 test_must_fail $command add_sub1 &&
280 test_superproject_content origin/no_submodule &&
281 test_must_be_empty sub1
284 # Replacing a tracked file with a submodule produces an empty
286 test_expect_$RESULT "$command: replace tracked file with submodule creates empty directory" '
288 reset_work_tree_to replace_sub1_with_file &&
290 cd submodule_update &&
291 git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&
292 $command replace_file_with_sub1 &&
293 test_superproject_content origin/replace_file_with_sub1 &&
294 test_dir_is_empty sub1 &&
295 git submodule update --init --recursive &&
296 test_submodule_content sub1 origin/replace_file_with_sub1
299 # ... as does removing a directory with tracked files with a
301 if test "$KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR" = 1
303 # Non fast-forward merges fail with "Directory sub1 doesn't
304 # exist. sub1" because the empty submodule directory is not
310 test_expect_$RESULT "$command: replace directory with submodule" '
312 reset_work_tree_to replace_sub1_with_directory &&
314 cd submodule_update &&
315 git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
316 $command replace_directory_with_sub1 &&
317 test_superproject_content origin/replace_directory_with_sub1 &&
318 test_dir_is_empty sub1 &&
319 git submodule update --init --recursive &&
320 test_submodule_content sub1 origin/replace_directory_with_sub1
324 ######################## Disappearing submodule #######################
325 # Removing a submodule doesn't remove its work tree ...
326 if test "$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES" = 1
332 test_expect_$RESULT "$command: removed submodule leaves submodule directory and its contents in place" '
334 reset_work_tree_to add_sub1 &&
336 cd submodule_update &&
337 git branch -t remove_sub1 origin/remove_sub1 &&
338 $command remove_sub1 &&
339 test_superproject_content origin/remove_sub1 &&
340 test_submodule_content sub1 origin/add_sub1
343 # ... especially when it contains a .git directory.
344 test_expect_$RESULT "$command: removed submodule leaves submodule containing a .git directory alone" '
346 reset_work_tree_to add_sub1 &&
348 cd submodule_update &&
349 git branch -t remove_sub1 origin/remove_sub1 &&
350 replace_gitfile_with_git_dir sub1 &&
351 $command remove_sub1 &&
352 test_superproject_content origin/remove_sub1 &&
353 test_git_directory_is_unchanged sub1 &&
354 test_submodule_content sub1 origin/add_sub1
357 # Replacing a submodule with files in a directory must fail as the
358 # submodule work tree isn't removed ...
359 if test "$KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES" = 1
361 # Non fast-forward merges attempt to merge the former
362 # submodule files with the newly checked out ones in the
363 # directory of the same name while it shouldn't.
368 test_expect_$RESULT "$command: replace submodule with a directory must fail" '
370 reset_work_tree_to add_sub1 &&
372 cd submodule_update &&
373 git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
374 test_must_fail $command replace_sub1_with_directory &&
375 test_superproject_content origin/add_sub1 &&
376 test_submodule_content sub1 origin/add_sub1
379 # ... especially when it contains a .git directory.
380 test_expect_$RESULT "$command: replace submodule containing a .git directory with a directory must fail" '
382 reset_work_tree_to add_sub1 &&
384 cd submodule_update &&
385 git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
386 replace_gitfile_with_git_dir sub1 &&
387 test_must_fail $command replace_sub1_with_directory &&
388 test_superproject_content origin/add_sub1 &&
389 test_git_directory_is_unchanged sub1 &&
390 test_submodule_content sub1 origin/add_sub1
393 # Replacing it with a file must fail as it could throw away any local
394 # work tree changes ...
395 test_expect_failure "$command: replace submodule with a file must fail" '
397 reset_work_tree_to add_sub1 &&
399 cd submodule_update &&
400 git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
401 test_must_fail $command replace_sub1_with_file &&
402 test_superproject_content origin/add_sub1 &&
403 test_submodule_content sub1 origin/add_sub1
406 # ... or even destroy unpushed parts of submodule history if that
407 # still uses a .git directory.
408 test_expect_failure "$command: replace submodule containing a .git directory with a file must fail" '
410 reset_work_tree_to add_sub1 &&
412 cd submodule_update &&
413 git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
414 replace_gitfile_with_git_dir sub1 &&
415 test_must_fail $command replace_sub1_with_file &&
416 test_superproject_content origin/add_sub1 &&
417 test_git_directory_is_unchanged sub1 &&
418 test_submodule_content sub1 origin/add_sub1
422 ########################## Modified submodule #########################
423 # Updating a submodule sha1 doesn't update the submodule's work tree
424 if test "$KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT" = 1
426 # When cherry picking a SHA-1 update for an ignored submodule
427 # the commit incorrectly fails with "The previous cherry-pick
428 # is now empty, possibly due to conflict resolution."
433 test_expect_$RESULT "$command: modified submodule does not update submodule work tree" '
435 reset_work_tree_to add_sub1 &&
437 cd submodule_update &&
438 git branch -t modify_sub1 origin/modify_sub1 &&
439 $command modify_sub1 &&
440 test_superproject_content origin/modify_sub1 &&
441 test_submodule_content sub1 origin/add_sub1 &&
442 git submodule update &&
443 test_submodule_content sub1 origin/modify_sub1
447 # Updating a submodule to an invalid sha1 doesn't update the
448 # submodule's work tree, subsequent update will fail
449 test_expect_$RESULT "$command: modified submodule does not update submodule work tree to invalid commit" '
451 reset_work_tree_to add_sub1 &&
453 cd submodule_update &&
454 git branch -t invalid_sub1 origin/invalid_sub1 &&
455 $command invalid_sub1 &&
456 test_superproject_content origin/invalid_sub1 &&
457 test_submodule_content sub1 origin/add_sub1 &&
458 test_must_fail git submodule update &&
459 test_submodule_content sub1 origin/add_sub1
462 # Updating a submodule from an invalid sha1 doesn't update the
463 # submodule's work tree, subsequent update will succeed
464 test_expect_$RESULT "$command: modified submodule does not update submodule work tree from invalid commit" '
466 reset_work_tree_to invalid_sub1 &&
468 cd submodule_update &&
469 git branch -t valid_sub1 origin/valid_sub1 &&
470 $command valid_sub1 &&
471 test_superproject_content origin/valid_sub1 &&
472 test_dir_is_empty sub1 &&
473 git submodule update --init --recursive &&
474 test_submodule_content sub1 origin/valid_sub1
479 # Test that submodule contents are currently not updated when switching
480 # between commits that change a submodule, but throwing away local changes in
481 # the superproject is allowed.
482 test_submodule_forced_switch () {
484 ######################### Appearing submodule #########################
485 # Switching to a commit letting a submodule appear creates empty dir ...
486 test_expect_success "$command: added submodule creates empty directory" '
488 reset_work_tree_to no_submodule &&
490 cd submodule_update &&
491 git branch -t add_sub1 origin/add_sub1 &&
493 test_superproject_content origin/add_sub1 &&
494 test_dir_is_empty sub1 &&
495 git submodule update --init --recursive &&
496 test_submodule_content sub1 origin/add_sub1
499 # ... and doesn't care if it already exists ...
500 test_expect_success "$command: added submodule leaves existing empty directory alone" '
502 reset_work_tree_to no_submodule &&
504 cd submodule_update &&
505 git branch -t add_sub1 origin/add_sub1 &&
508 test_superproject_content origin/add_sub1 &&
509 test_dir_is_empty sub1 &&
510 git submodule update --init --recursive &&
511 test_submodule_content sub1 origin/add_sub1
514 # ... unless there is an untracked file in its place.
515 test_expect_success "$command: added submodule does remove untracked unignored file with same name when forced" '
517 reset_work_tree_to no_submodule &&
519 cd submodule_update &&
520 git branch -t add_sub1 origin/add_sub1 &&
523 test_superproject_content origin/add_sub1 &&
524 test_dir_is_empty sub1
527 # Replacing a tracked file with a submodule produces an empty
529 test_expect_success "$command: replace tracked file with submodule creates empty directory" '
531 reset_work_tree_to replace_sub1_with_file &&
533 cd submodule_update &&
534 git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&
535 $command replace_file_with_sub1 &&
536 test_superproject_content origin/replace_file_with_sub1 &&
537 test_dir_is_empty sub1 &&
538 git submodule update --init --recursive &&
539 test_submodule_content sub1 origin/replace_file_with_sub1
542 # ... as does removing a directory with tracked files with a
544 test_expect_success "$command: replace directory with submodule" '
546 reset_work_tree_to replace_sub1_with_directory &&
548 cd submodule_update &&
549 git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
550 $command replace_directory_with_sub1 &&
551 test_superproject_content origin/replace_directory_with_sub1 &&
552 test_dir_is_empty sub1 &&
553 git submodule update --init --recursive &&
554 test_submodule_content sub1 origin/replace_directory_with_sub1
558 ######################## Disappearing submodule #######################
559 # Removing a submodule doesn't remove its work tree ...
560 test_expect_success "$command: removed submodule leaves submodule directory and its contents in place" '
562 reset_work_tree_to add_sub1 &&
564 cd submodule_update &&
565 git branch -t remove_sub1 origin/remove_sub1 &&
566 $command remove_sub1 &&
567 test_superproject_content origin/remove_sub1 &&
568 test_submodule_content sub1 origin/add_sub1
571 # ... especially when it contains a .git directory.
572 test_expect_success "$command: removed submodule leaves submodule containing a .git directory alone" '
574 reset_work_tree_to add_sub1 &&
576 cd submodule_update &&
577 git branch -t remove_sub1 origin/remove_sub1 &&
578 replace_gitfile_with_git_dir sub1 &&
579 $command remove_sub1 &&
580 test_superproject_content origin/remove_sub1 &&
581 test_git_directory_is_unchanged sub1 &&
582 test_submodule_content sub1 origin/add_sub1
585 # Replacing a submodule with files in a directory must fail as the
586 # submodule work tree isn't removed ...
587 test_expect_failure "$command: replace submodule with a directory must fail" '
589 reset_work_tree_to add_sub1 &&
591 cd submodule_update &&
592 git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
593 test_must_fail $command replace_sub1_with_directory &&
594 test_superproject_content origin/add_sub1 &&
595 test_submodule_content sub1 origin/add_sub1
598 # ... especially when it contains a .git directory.
599 test_expect_failure "$command: replace submodule containing a .git directory with a directory must fail" '
601 reset_work_tree_to add_sub1 &&
603 cd submodule_update &&
604 git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
605 replace_gitfile_with_git_dir sub1 &&
606 test_must_fail $command replace_sub1_with_directory &&
607 test_superproject_content origin/add_sub1 &&
608 test_git_directory_is_unchanged sub1 &&
609 test_submodule_content sub1 origin/add_sub1
612 # Replacing it with a file must fail as it could throw away any local
613 # work tree changes ...
614 test_expect_failure "$command: replace submodule with a file must fail" '
616 reset_work_tree_to add_sub1 &&
618 cd submodule_update &&
619 git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
620 test_must_fail $command replace_sub1_with_file &&
621 test_superproject_content origin/add_sub1 &&
622 test_submodule_content sub1 origin/add_sub1
625 # ... or even destroy unpushed parts of submodule history if that
626 # still uses a .git directory.
627 test_expect_failure "$command: replace submodule containing a .git directory with a file must fail" '
629 reset_work_tree_to add_sub1 &&
631 cd submodule_update &&
632 git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
633 replace_gitfile_with_git_dir sub1 &&
634 test_must_fail $command replace_sub1_with_file &&
635 test_superproject_content origin/add_sub1 &&
636 test_git_directory_is_unchanged sub1 &&
637 test_submodule_content sub1 origin/add_sub1
641 ########################## Modified submodule #########################
642 # Updating a submodule sha1 doesn't update the submodule's work tree
643 test_expect_success "$command: modified submodule does not update submodule work tree" '
645 reset_work_tree_to add_sub1 &&
647 cd submodule_update &&
648 git branch -t modify_sub1 origin/modify_sub1 &&
649 $command modify_sub1 &&
650 test_superproject_content origin/modify_sub1 &&
651 test_submodule_content sub1 origin/add_sub1 &&
652 git submodule update &&
653 test_submodule_content sub1 origin/modify_sub1
656 # Updating a submodule to an invalid sha1 doesn't update the
657 # submodule's work tree, subsequent update will fail
658 test_expect_success "$command: modified submodule does not update submodule work tree to invalid commit" '
660 reset_work_tree_to add_sub1 &&
662 cd submodule_update &&
663 git branch -t invalid_sub1 origin/invalid_sub1 &&
664 $command invalid_sub1 &&
665 test_superproject_content origin/invalid_sub1 &&
666 test_submodule_content sub1 origin/add_sub1 &&
667 test_must_fail git submodule update &&
668 test_submodule_content sub1 origin/add_sub1
671 # Updating a submodule from an invalid sha1 doesn't update the
672 # submodule's work tree, subsequent update will succeed
673 test_expect_success "$command: modified submodule does not update submodule work tree from invalid commit" '
675 reset_work_tree_to invalid_sub1 &&
677 cd submodule_update &&
678 git branch -t valid_sub1 origin/valid_sub1 &&
679 $command valid_sub1 &&
680 test_superproject_content origin/valid_sub1 &&
681 test_dir_is_empty sub1 &&
682 git submodule update --init --recursive &&
683 test_submodule_content sub1 origin/valid_sub1