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 sub
1/* &&
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 hash=$
(git rev-parse
--revs-only HEAD
:sub1
) &&
175 if test -n "$hash" &&
176 test $
(cd "../submodule_update_sub1" && git rev-parse
--verify "$hash^{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
() {
196 if test x
"$1" = "x-C"
203 echo "test_submodule_content needs two arguments"
208 test -d "$submodule"/ &&
209 if ! test -f "$submodule"/.git
&& ! test -d "$submodule"/.git
211 echo "Submodule $submodule is not populated"
214 sha1
=$
(git rev-parse
--verify "$commit:$submodule") &&
217 echo "Couldn't retrieve SHA-1 of $submodule for $commit"
222 git status
-u -s >actual
&&
223 test_must_be_empty actual
&&
224 git
diff "$sha1" >actual
&&
225 test_must_be_empty actual
229 # Test that the following transitions are correctly handled:
230 # - Updated submodule
232 # - Removed submodule
233 # - Directory containing tracked files replaced by submodule
234 # - Submodule replaced by tracked files in directory
235 # - Submodule replaced by tracked file with the same name
236 # - tracked file replaced by submodule
238 # The default is that submodule contents aren't changed until "git submodule
239 # update" is run. And even then that command doesn't delete the work tree of
240 # a removed submodule.
242 # Removing a submodule containing a .git directory must fail even when forced
243 # to protect the history!
246 # Test that submodule contents are currently not updated when switching
247 # between commits that change a submodule.
248 test_submodule_switch
() {
250 ######################### Appearing submodule #########################
251 # Switching to a commit letting a submodule appear creates empty dir ...
252 if test "$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES" = 1
254 # Restoring stash fails to restore submodule index entry
259 test_expect_
$RESULT "$command: added submodule creates empty directory" '
261 reset_work_tree_to no_submodule &&
263 cd submodule_update &&
264 git branch -t add_sub1 origin/add_sub1 &&
266 test_superproject_content origin/add_sub1 &&
267 test_dir_is_empty sub1 &&
268 git submodule update --init --recursive &&
269 test_submodule_content sub1 origin/add_sub1
272 # ... and doesn't care if it already exists ...
273 test_expect_
$RESULT "$command: added submodule leaves existing empty directory alone" '
275 reset_work_tree_to no_submodule &&
277 cd submodule_update &&
279 git branch -t add_sub1 origin/add_sub1 &&
281 test_superproject_content origin/add_sub1 &&
282 test_dir_is_empty sub1 &&
283 git submodule update --init --recursive &&
284 test_submodule_content sub1 origin/add_sub1
287 # ... unless there is an untracked file in its place.
288 test_expect_success
"$command: added submodule doesn't remove untracked unignored file with same name" '
290 reset_work_tree_to no_submodule &&
292 cd submodule_update &&
293 git branch -t add_sub1 origin/add_sub1 &&
295 test_must_fail $command add_sub1 &&
296 test_superproject_content origin/no_submodule &&
297 test_must_be_empty sub1
300 # Replacing a tracked file with a submodule produces an empty
302 test_expect_
$RESULT "$command: replace tracked file with submodule creates empty directory" '
304 reset_work_tree_to replace_sub1_with_file &&
306 cd submodule_update &&
307 git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&
308 $command replace_file_with_sub1 &&
309 test_superproject_content origin/replace_file_with_sub1 &&
310 test_dir_is_empty sub1 &&
311 git submodule update --init --recursive &&
312 test_submodule_content sub1 origin/replace_file_with_sub1
315 # ... as does removing a directory with tracked files with a
317 if test "$KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR" = 1
319 # Non fast-forward merges fail with "Directory sub1 doesn't
320 # exist. sub1" because the empty submodule directory is not
326 test_expect_
$RESULT "$command: replace directory with submodule" '
328 reset_work_tree_to replace_sub1_with_directory &&
330 cd submodule_update &&
331 git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
332 $command replace_directory_with_sub1 &&
333 test_superproject_content origin/replace_directory_with_sub1 &&
334 test_dir_is_empty sub1 &&
335 git submodule update --init --recursive &&
336 test_submodule_content sub1 origin/replace_directory_with_sub1
340 ######################## Disappearing submodule #######################
341 # Removing a submodule doesn't remove its work tree ...
342 if test "$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES" = 1
348 test_expect_
$RESULT "$command: removed submodule leaves submodule directory and its contents in place" '
350 reset_work_tree_to add_sub1 &&
352 cd submodule_update &&
353 git branch -t remove_sub1 origin/remove_sub1 &&
354 $command remove_sub1 &&
355 test_superproject_content origin/remove_sub1 &&
356 test_submodule_content sub1 origin/add_sub1
359 # ... especially when it contains a .git directory.
360 test_expect_
$RESULT "$command: removed submodule leaves submodule containing a .git directory alone" '
362 reset_work_tree_to add_sub1 &&
364 cd submodule_update &&
365 git branch -t remove_sub1 origin/remove_sub1 &&
366 replace_gitfile_with_git_dir sub1 &&
367 $command remove_sub1 &&
368 test_superproject_content origin/remove_sub1 &&
369 test_git_directory_is_unchanged sub1 &&
370 test_submodule_content sub1 origin/add_sub1
373 # Replacing a submodule with files in a directory must fail as the
374 # submodule work tree isn't removed ...
375 if test "$KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES" = 1
377 # Non fast-forward merges attempt to merge the former
378 # submodule files with the newly checked out ones in the
379 # directory of the same name while it shouldn't.
384 test_expect_
$RESULT "$command: replace submodule with a directory must fail" '
386 reset_work_tree_to add_sub1 &&
388 cd submodule_update &&
389 git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
390 test_must_fail $command replace_sub1_with_directory &&
391 test_superproject_content origin/add_sub1 &&
392 test_submodule_content sub1 origin/add_sub1
395 # ... especially when it contains a .git directory.
396 test_expect_
$RESULT "$command: replace submodule containing a .git directory with a directory must fail" '
398 reset_work_tree_to add_sub1 &&
400 cd submodule_update &&
401 git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
402 replace_gitfile_with_git_dir sub1 &&
403 test_must_fail $command replace_sub1_with_directory &&
404 test_superproject_content origin/add_sub1 &&
405 test_git_directory_is_unchanged sub1 &&
406 test_submodule_content sub1 origin/add_sub1
409 # Replacing it with a file must fail as it could throw away any local
410 # work tree changes ...
411 test_expect_failure
"$command: replace submodule with a file must fail" '
413 reset_work_tree_to add_sub1 &&
415 cd submodule_update &&
416 git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
417 test_must_fail $command replace_sub1_with_file &&
418 test_superproject_content origin/add_sub1 &&
419 test_submodule_content sub1 origin/add_sub1
422 # ... or even destroy unpushed parts of submodule history if that
423 # still uses a .git directory.
424 test_expect_failure
"$command: replace submodule containing a .git directory with a file must fail" '
426 reset_work_tree_to add_sub1 &&
428 cd submodule_update &&
429 git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
430 replace_gitfile_with_git_dir sub1 &&
431 test_must_fail $command replace_sub1_with_file &&
432 test_superproject_content origin/add_sub1 &&
433 test_git_directory_is_unchanged sub1 &&
434 test_submodule_content sub1 origin/add_sub1
438 ########################## Modified submodule #########################
439 # Updating a submodule sha1 doesn't update the submodule's work tree
440 if test "$KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT" = 1
442 # When cherry picking a SHA-1 update for an ignored submodule
443 # the commit incorrectly fails with "The previous cherry-pick
444 # is now empty, possibly due to conflict resolution."
449 test_expect_
$RESULT "$command: modified submodule does not update submodule work tree" '
451 reset_work_tree_to add_sub1 &&
453 cd submodule_update &&
454 git branch -t modify_sub1 origin/modify_sub1 &&
455 $command modify_sub1 &&
456 test_superproject_content origin/modify_sub1 &&
457 test_submodule_content sub1 origin/add_sub1 &&
458 git submodule update &&
459 test_submodule_content sub1 origin/modify_sub1
463 # Updating a submodule to an invalid sha1 doesn't update the
464 # submodule's work tree, subsequent update will fail
465 test_expect_
$RESULT "$command: modified submodule does not update submodule work tree to invalid commit" '
467 reset_work_tree_to add_sub1 &&
469 cd submodule_update &&
470 git branch -t invalid_sub1 origin/invalid_sub1 &&
471 $command invalid_sub1 &&
472 test_superproject_content origin/invalid_sub1 &&
473 test_submodule_content sub1 origin/add_sub1 &&
474 test_must_fail git submodule update &&
475 test_submodule_content sub1 origin/add_sub1
478 # Updating a submodule from an invalid sha1 doesn't update the
479 # submodule's work tree, subsequent update will succeed
480 test_expect_
$RESULT "$command: modified submodule does not update submodule work tree from invalid commit" '
482 reset_work_tree_to invalid_sub1 &&
484 cd submodule_update &&
485 git branch -t valid_sub1 origin/valid_sub1 &&
486 $command valid_sub1 &&
487 test_superproject_content origin/valid_sub1 &&
488 test_dir_is_empty sub1 &&
489 git submodule update --init --recursive &&
490 test_submodule_content sub1 origin/valid_sub1
495 # Test that submodule contents are currently not updated when switching
496 # between commits that change a submodule, but throwing away local changes in
497 # the superproject is allowed.
498 test_submodule_forced_switch
() {
500 ######################### Appearing submodule #########################
501 # Switching to a commit letting a submodule appear creates empty dir ...
502 test_expect_success
"$command: added submodule creates empty directory" '
504 reset_work_tree_to no_submodule &&
506 cd submodule_update &&
507 git branch -t add_sub1 origin/add_sub1 &&
509 test_superproject_content origin/add_sub1 &&
510 test_dir_is_empty sub1 &&
511 git submodule update --init --recursive &&
512 test_submodule_content sub1 origin/add_sub1
515 # ... and doesn't care if it already exists ...
516 test_expect_success
"$command: added submodule leaves existing empty directory alone" '
518 reset_work_tree_to no_submodule &&
520 cd submodule_update &&
521 git branch -t add_sub1 origin/add_sub1 &&
524 test_superproject_content origin/add_sub1 &&
525 test_dir_is_empty sub1 &&
526 git submodule update --init --recursive &&
527 test_submodule_content sub1 origin/add_sub1
530 # ... unless there is an untracked file in its place.
531 test_expect_success
"$command: added submodule does remove untracked unignored file with same name when forced" '
533 reset_work_tree_to no_submodule &&
535 cd submodule_update &&
536 git branch -t add_sub1 origin/add_sub1 &&
539 test_superproject_content origin/add_sub1 &&
540 test_dir_is_empty sub1
543 # Replacing a tracked file with a submodule produces an empty
545 test_expect_success
"$command: replace tracked file with submodule creates empty directory" '
547 reset_work_tree_to replace_sub1_with_file &&
549 cd submodule_update &&
550 git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&
551 $command replace_file_with_sub1 &&
552 test_superproject_content origin/replace_file_with_sub1 &&
553 test_dir_is_empty sub1 &&
554 git submodule update --init --recursive &&
555 test_submodule_content sub1 origin/replace_file_with_sub1
558 # ... as does removing a directory with tracked files with a
560 test_expect_success
"$command: replace directory with submodule" '
562 reset_work_tree_to replace_sub1_with_directory &&
564 cd submodule_update &&
565 git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
566 $command replace_directory_with_sub1 &&
567 test_superproject_content origin/replace_directory_with_sub1 &&
568 test_dir_is_empty sub1 &&
569 git submodule update --init --recursive &&
570 test_submodule_content sub1 origin/replace_directory_with_sub1
574 ######################## Disappearing submodule #######################
575 # Removing a submodule doesn't remove its work tree ...
576 test_expect_success
"$command: removed submodule leaves submodule directory and its contents in place" '
578 reset_work_tree_to add_sub1 &&
580 cd submodule_update &&
581 git branch -t remove_sub1 origin/remove_sub1 &&
582 $command remove_sub1 &&
583 test_superproject_content origin/remove_sub1 &&
584 test_submodule_content sub1 origin/add_sub1
587 # ... especially when it contains a .git directory.
588 test_expect_success
"$command: removed submodule leaves submodule containing a .git directory alone" '
590 reset_work_tree_to add_sub1 &&
592 cd submodule_update &&
593 git branch -t remove_sub1 origin/remove_sub1 &&
594 replace_gitfile_with_git_dir sub1 &&
595 $command remove_sub1 &&
596 test_superproject_content origin/remove_sub1 &&
597 test_git_directory_is_unchanged sub1 &&
598 test_submodule_content sub1 origin/add_sub1
601 # Replacing a submodule with files in a directory must fail as the
602 # submodule work tree isn't removed ...
603 test_expect_failure
"$command: replace submodule with a directory must fail" '
605 reset_work_tree_to add_sub1 &&
607 cd submodule_update &&
608 git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
609 test_must_fail $command replace_sub1_with_directory &&
610 test_superproject_content origin/add_sub1 &&
611 test_submodule_content sub1 origin/add_sub1
614 # ... especially when it contains a .git directory.
615 test_expect_failure
"$command: replace submodule containing a .git directory with a directory must fail" '
617 reset_work_tree_to add_sub1 &&
619 cd submodule_update &&
620 git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
621 replace_gitfile_with_git_dir sub1 &&
622 test_must_fail $command replace_sub1_with_directory &&
623 test_superproject_content origin/add_sub1 &&
624 test_git_directory_is_unchanged sub1 &&
625 test_submodule_content sub1 origin/add_sub1
628 # Replacing it with a file must fail as it could throw away any local
629 # work tree changes ...
630 test_expect_failure
"$command: replace submodule with a file must fail" '
632 reset_work_tree_to add_sub1 &&
634 cd submodule_update &&
635 git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
636 test_must_fail $command replace_sub1_with_file &&
637 test_superproject_content origin/add_sub1 &&
638 test_submodule_content sub1 origin/add_sub1
641 # ... or even destroy unpushed parts of submodule history if that
642 # still uses a .git directory.
643 test_expect_failure
"$command: replace submodule containing a .git directory with a file must fail" '
645 reset_work_tree_to add_sub1 &&
647 cd submodule_update &&
648 git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
649 replace_gitfile_with_git_dir sub1 &&
650 test_must_fail $command replace_sub1_with_file &&
651 test_superproject_content origin/add_sub1 &&
652 test_git_directory_is_unchanged sub1 &&
653 test_submodule_content sub1 origin/add_sub1
657 ########################## Modified submodule #########################
658 # Updating a submodule sha1 doesn't update the submodule's work tree
659 test_expect_success
"$command: modified submodule does not update submodule work tree" '
661 reset_work_tree_to add_sub1 &&
663 cd submodule_update &&
664 git branch -t modify_sub1 origin/modify_sub1 &&
665 $command modify_sub1 &&
666 test_superproject_content origin/modify_sub1 &&
667 test_submodule_content sub1 origin/add_sub1 &&
668 git submodule update &&
669 test_submodule_content sub1 origin/modify_sub1
672 # Updating a submodule to an invalid sha1 doesn't update the
673 # submodule's work tree, subsequent update will fail
674 test_expect_success
"$command: modified submodule does not update submodule work tree to invalid commit" '
676 reset_work_tree_to add_sub1 &&
678 cd submodule_update &&
679 git branch -t invalid_sub1 origin/invalid_sub1 &&
680 $command invalid_sub1 &&
681 test_superproject_content origin/invalid_sub1 &&
682 test_submodule_content sub1 origin/add_sub1 &&
683 test_must_fail git submodule update &&
684 test_submodule_content sub1 origin/add_sub1
687 # Updating a submodule from an invalid sha1 doesn't update the
688 # submodule's work tree, subsequent update will succeed
689 test_expect_success
"$command: modified submodule does not update submodule work tree from invalid commit" '
691 reset_work_tree_to invalid_sub1 &&
693 cd submodule_update &&
694 git branch -t valid_sub1 origin/valid_sub1 &&
695 $command valid_sub1 &&
696 test_superproject_content origin/valid_sub1 &&
697 test_dir_is_empty sub1 &&
698 git submodule update --init --recursive &&
699 test_submodule_content sub1 origin/valid_sub1