# - if succeeds, once "git submodule update" is invoked, the contents of
# submodule directories are updated
#
+# If the command under test is known to not work with submodules in certain
+# conditions, set the appropriate KNOWN_FAILURE_* variable used in the tests
+# below to 1.
+#
# Use as follows:
#
# my_func () {
# - Removing a submodule with a git directory absorbs the submodules
# git directory first into the superproject.
-test_submodule_switch_recursing_with_args () {
- cmd_args="$1"
- command="git $cmd_args --recurse-submodules"
- RESULTDS=success
- if test "$KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS" = 1
- then
- RESULTDS=failure
- fi
- RESULTOI=success
- if test "$KNOWN_FAILURE_SUBMODULE_OVERWRITE_IGNORED_UNTRACKED" = 1
- then
- RESULTOI=failure
- fi
+# Internal function; use test_submodule_switch_recursing_with_args() or
+# test_submodule_forced_switch_recursing_with_args() instead.
+test_submodule_recursing_with_args_common() {
+ command="$1"
+
######################### Appearing submodule #########################
# Switching to a commit letting a submodule appear checks it out ...
test_expect_success "$command: added submodule is checked out" '
test_submodule_content sub1 origin/add_sub1
)
'
- # ... ignoring an empty existing directory ...
+ # ... ignoring an empty existing directory.
test_expect_success "$command: added submodule is checked out in empty dir" '
prolog &&
reset_work_tree_to_interested no_submodule &&
test_submodule_content sub1 origin/add_sub1
)
'
- # ... unless there is an untracked file in its place.
- test_expect_success "$command: added submodule doesn't remove untracked file with same name" '
+ test_expect_success "$command: submodule branch is not changed, detach HEAD instead" '
prolog &&
- reset_work_tree_to_interested no_submodule &&
- (
- cd submodule_update &&
- git branch -t add_sub1 origin/add_sub1 &&
- : >sub1 &&
- test_must_fail $command add_sub1 &&
- test_superproject_content origin/no_submodule &&
- test_must_be_empty sub1
- )
- '
- # ... but an ignored file is fine.
- test_expect_$RESULTOI "$command: added submodule removes an untracked ignored file" '
- test_when_finished "rm submodule_update/.git/info/exclude" &&
- prolog &&
- reset_work_tree_to_interested no_submodule &&
+ reset_work_tree_to_interested add_sub1 &&
(
cd submodule_update &&
- git branch -t add_sub1 origin/add_sub1 &&
- : >sub1 &&
- echo sub1 >.git/info/exclude
- $command add_sub1 &&
- test_superproject_content origin/add_sub1 &&
- test_submodule_content sub1 origin/add_sub1
+ git -C sub1 checkout -b keep_branch &&
+ git -C sub1 rev-parse HEAD >expect &&
+ git branch -t modify_sub1 origin/modify_sub1 &&
+ $command modify_sub1 &&
+ test_superproject_content origin/modify_sub1 &&
+ test_submodule_content sub1 origin/modify_sub1 &&
+ git -C sub1 rev-parse keep_branch >actual &&
+ test_cmp expect actual &&
+ test_must_fail git -C sub1 symbolic-ref HEAD
)
'
+
# Replacing a tracked file with a submodule produces a checked out submodule
test_expect_success "$command: replace tracked file with submodule checks out submodule" '
prolog &&
test_git_directory_exists sub1
)
'
- # Replacing a submodule with files in a directory must succeeds
- # when the submodule is clean
- test_expect_$RESULTDS "$command: replace submodule with a directory" '
- prolog &&
- reset_work_tree_to_interested add_sub1 &&
- (
- cd submodule_update &&
- git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
- $command replace_sub1_with_directory &&
- test_superproject_content origin/replace_sub1_with_directory &&
- test_submodule_content sub1 origin/replace_sub1_with_directory
- )
- '
- # ... absorbing a .git directory.
- test_expect_$RESULTDS "$command: replace submodule containing a .git directory with a directory must absorb the git dir" '
- prolog &&
- reset_work_tree_to_interested add_sub1 &&
- (
- cd submodule_update &&
- git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
- replace_gitfile_with_git_dir sub1 &&
- rm -rf .git/modules &&
- $command replace_sub1_with_directory &&
- test_superproject_content origin/replace_sub1_with_directory &&
- test_git_directory_exists sub1
- )
- '
# Replacing it with a file ...
test_expect_success "$command: replace submodule with a file" '
test -f sub1
)
'
-
+ RESULTDS=success
+ if test "$KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS" = 1
+ then
+ RESULTDS=failure
+ fi
# ... must check its local work tree for untracked files
test_expect_$RESULTDS "$command: replace submodule with a file must fail with untracked files" '
prolog &&
test_must_fail $command replace_sub1_with_file &&
test_superproject_content origin/add_sub1 &&
test_submodule_content sub1 origin/add_sub1
- )
- '
-
- # ... and ignored files are ignored
- test_expect_success "$command: replace submodule with a file works ignores ignored files in submodule" '
- test_when_finished "rm submodule_update/.git/modules/sub1/info/exclude" &&
- prolog &&
- reset_work_tree_to_interested add_sub1 &&
- (
- cd submodule_update &&
- git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
- : >sub1/ignored &&
- $command replace_sub1_with_file &&
- test_superproject_content origin/replace_sub1_with_file &&
- test -f sub1
+ test -f sub1/untracked_file
)
'
test_submodule_content sub1 origin/modify_sub1
)
'
-
- test_expect_success "git -c submodule.recurse=true $cmd_args: modified submodule updates submodule work tree" '
- prolog &&
- reset_work_tree_to_interested add_sub1 &&
- (
- cd submodule_update &&
- git branch -t modify_sub1 origin/modify_sub1 &&
- git -c submodule.recurse=true $cmd_args modify_sub1 &&
- test_superproject_content origin/modify_sub1 &&
- test_submodule_content sub1 origin/modify_sub1
- )
- '
-
# Updating a submodule to an invalid sha1 doesn't update the
# superproject nor the submodule's work tree.
test_expect_success "$command: updating to a missing submodule commit fails" '
test_submodule_content sub1 origin/add_sub1
)
'
-
- # recursing deeper than one level doesn't work yet.
- test_expect_success "$command: modified submodule updates submodule recursively" '
- prolog &&
- reset_work_tree_to_interested add_nested_sub &&
- (
- cd submodule_update &&
- git branch -t modify_sub1_recursively origin/modify_sub1_recursively &&
- $command modify_sub1_recursively &&
- test_superproject_content origin/modify_sub1_recursively &&
- test_submodule_content sub1 origin/modify_sub1_recursively &&
- test_submodule_content -C sub1 sub2 origin/modify_sub1_recursively
- )
- '
}
-# Test that submodule contents are updated when switching between commits
-# that change a submodule, but throwing away local changes in
-# the superproject as well as the submodule is allowed.
-test_submodule_forced_switch_recursing_with_args () {
+# Declares and invokes several tests that, in various situations, checks that
+# the provided Git command, when invoked with --recurse-submodules:
+# - succeeds in updating the worktree and index of a superproject to a target
+# commit, or fails atomically (depending on the test situation)
+# - if succeeds, the contents of submodule directories are updated
+#
+# Specify the Git command so that "git $GIT_COMMAND --recurse-submodules"
+# works.
+#
+# If the command under test is known to not work with submodules in certain
+# conditions, set the appropriate KNOWN_FAILURE_* variable used in the tests
+# below to 1.
+#
+# Use as follows:
+#
+# test_submodule_switch_recursing_with_args "$GIT_COMMAND"
+test_submodule_switch_recursing_with_args () {
cmd_args="$1"
command="git $cmd_args --recurse-submodules"
- RESULT=success
+ test_submodule_recursing_with_args_common "$command"
+
+ RESULTDS=success
if test "$KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS" = 1
then
- RESULT=failure
+ RESULTDS=failure
fi
- ######################### Appearing submodule #########################
- # Switching to a commit letting a submodule appear creates empty dir ...
- test_expect_success "$command: added submodule is checked out" '
+ RESULTOI=success
+ if test "$KNOWN_FAILURE_SUBMODULE_OVERWRITE_IGNORED_UNTRACKED" = 1
+ then
+ RESULTOI=failure
+ fi
+ # Switching to a commit letting a submodule appear cannot override an
+ # untracked file.
+ test_expect_success "$command: added submodule doesn't remove untracked file with same name" '
prolog &&
reset_work_tree_to_interested no_submodule &&
(
cd submodule_update &&
git branch -t add_sub1 origin/add_sub1 &&
- $command add_sub1 &&
- test_superproject_content origin/add_sub1 &&
- test_submodule_content sub1 origin/add_sub1
+ : >sub1 &&
+ test_must_fail $command add_sub1 &&
+ test_superproject_content origin/no_submodule &&
+ test_must_be_empty sub1
)
'
- # ... and doesn't care if it already exists ...
- test_expect_success "$command: added submodule ignores empty directory" '
+ # ... but an ignored file is fine.
+ test_expect_$RESULTOI "$command: added submodule removes an untracked ignored file" '
+ test_when_finished "rm submodule_update/.git/info/exclude" &&
prolog &&
reset_work_tree_to_interested no_submodule &&
(
cd submodule_update &&
git branch -t add_sub1 origin/add_sub1 &&
- mkdir sub1 &&
+ : >sub1 &&
+ echo sub1 >.git/info/exclude
$command add_sub1 &&
test_superproject_content origin/add_sub1 &&
test_submodule_content sub1 origin/add_sub1
)
'
- # ... not caring about an untracked file either
- test_expect_success "$command: added submodule does remove untracked unignored file with same name when forced" '
+
+ # Replacing a submodule with files in a directory must succeeds
+ # when the submodule is clean
+ test_expect_$RESULTDS "$command: replace submodule with a directory" '
prolog &&
- reset_work_tree_to_interested no_submodule &&
+ reset_work_tree_to_interested add_sub1 &&
(
cd submodule_update &&
- git branch -t add_sub1 origin/add_sub1 &&
- >sub1 &&
- $command add_sub1 &&
- test_superproject_content origin/add_sub1 &&
- test_submodule_content sub1 origin/add_sub1
+ git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
+ $command replace_sub1_with_directory &&
+ test_superproject_content origin/replace_sub1_with_directory &&
+ test_submodule_content sub1 origin/replace_sub1_with_directory
)
'
- # Replacing a tracked file with a submodule checks out the submodule
- test_expect_success "$command: replace tracked file with submodule populates the submodule" '
+ # ... absorbing a .git directory.
+ test_expect_$RESULTDS "$command: replace submodule containing a .git directory with a directory must absorb the git dir" '
prolog &&
- reset_work_tree_to_interested replace_sub1_with_file &&
+ reset_work_tree_to_interested add_sub1 &&
(
cd submodule_update &&
- git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&
- $command replace_file_with_sub1 &&
- test_superproject_content origin/replace_file_with_sub1 &&
- test_submodule_content sub1 origin/replace_file_with_sub1
+ git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
+ replace_gitfile_with_git_dir sub1 &&
+ rm -rf .git/modules &&
+ $command replace_sub1_with_directory &&
+ test_superproject_content origin/replace_sub1_with_directory &&
+ test_git_directory_exists sub1
)
'
- # ... as does removing a directory with tracked files with a
- # submodule.
- test_expect_success "$command: replace directory with submodule" '
+
+ # ... and ignored files are ignored
+ test_expect_success "$command: replace submodule with a file works ignores ignored files in submodule" '
+ test_when_finished "rm submodule_update/.git/modules/sub1/info/exclude" &&
prolog &&
- reset_work_tree_to_interested replace_sub1_with_directory &&
+ reset_work_tree_to_interested add_sub1 &&
(
cd submodule_update &&
- git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
- $command replace_directory_with_sub1 &&
- test_superproject_content origin/replace_directory_with_sub1 &&
- test_submodule_content sub1 origin/replace_directory_with_sub1
+ git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
+ echo ignored >.git/modules/sub1/info/exclude &&
+ : >sub1/ignored &&
+ $command replace_sub1_with_file &&
+ test_superproject_content origin/replace_sub1_with_file &&
+ test -f sub1
)
'
- ######################## Disappearing submodule #######################
- # Removing a submodule doesn't remove its work tree ...
- test_expect_success "$command: removed submodule leaves submodule directory and its contents in place" '
+ test_expect_success "git -c submodule.recurse=true $cmd_args: modified submodule updates submodule work tree" '
prolog &&
reset_work_tree_to_interested add_sub1 &&
(
cd submodule_update &&
- git branch -t remove_sub1 origin/remove_sub1 &&
- $command remove_sub1 &&
- test_superproject_content origin/remove_sub1 &&
- ! test -e sub1
+ git branch -t modify_sub1 origin/modify_sub1 &&
+ git -c submodule.recurse=true $cmd_args modify_sub1 &&
+ test_superproject_content origin/modify_sub1 &&
+ test_submodule_content sub1 origin/modify_sub1
)
'
- # ... especially when it contains a .git directory.
- test_expect_success "$command: removed submodule leaves submodule containing a .git directory alone" '
+
+ # recursing deeper than one level doesn't work yet.
+ test_expect_success "$command: modified submodule updates submodule recursively" '
prolog &&
- reset_work_tree_to_interested add_sub1 &&
+ reset_work_tree_to_interested add_nested_sub &&
(
cd submodule_update &&
- git branch -t remove_sub1 origin/remove_sub1 &&
- replace_gitfile_with_git_dir sub1 &&
- rm -rf .git/modules/sub1 &&
- $command remove_sub1 &&
- test_superproject_content origin/remove_sub1 &&
- test_git_directory_exists sub1 &&
- ! test -e sub1
+ git branch -t modify_sub1_recursively origin/modify_sub1_recursively &&
+ $command modify_sub1_recursively &&
+ test_superproject_content origin/modify_sub1_recursively &&
+ test_submodule_content sub1 origin/modify_sub1_recursively &&
+ test_submodule_content -C sub1 sub2 origin/modify_sub1_recursively
)
'
+}
+
+# Same as test_submodule_switch_recursing_with_args(), except that throwing
+# away local changes in the superproject is allowed.
+test_submodule_forced_switch_recursing_with_args () {
+ cmd_args="$1"
+ command="git $cmd_args --recurse-submodules"
+ test_submodule_recursing_with_args_common "$command"
+
+ RESULT=success
+ if test "$KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS" = 1
+ then
+ RESULT=failure
+ fi
+ # Switching to a commit letting a submodule appear does not care about
+ # an untracked file.
+ test_expect_success "$command: added submodule does remove untracked unignored file with same name when forced" '
+ prolog &&
+ reset_work_tree_to_interested no_submodule &&
+ (
+ cd submodule_update &&
+ git branch -t add_sub1 origin/add_sub1 &&
+ >sub1 &&
+ $command add_sub1 &&
+ test_superproject_content origin/add_sub1 &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+
# Replacing a submodule with files in a directory ...
test_expect_success "$command: replace submodule with a directory" '
prolog &&
test_git_directory_exists sub1
)
'
- # Replacing it with a file
- test_expect_success "$command: replace submodule with a file" '
- prolog &&
- reset_work_tree_to_interested add_sub1 &&
- (
- cd submodule_update &&
- git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
- $command replace_sub1_with_file &&
- test_superproject_content origin/replace_sub1_with_file
- )
- '
# ... even if the submodule contains ignored files
test_expect_success "$command: replace submodule with a file ignoring ignored files" '
)
'
- # ... but stops for untracked files that would be lost
- test_expect_$RESULT "$command: replace submodule with a file stops for untracked files" '
- prolog &&
- reset_work_tree_to_interested add_sub1 &&
- (
- cd submodule_update &&
- git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
- : >sub1/untracked_file &&
- test_must_fail $command replace_sub1_with_file &&
- test_superproject_content origin/add_sub1 &&
- test -f sub1/untracked_file
- )
- '
-
- ########################## Modified submodule #########################
- # Updating a submodule sha1 updates the submodule's work tree
- test_expect_success "$command: modified submodule updates submodule work tree" '
- prolog &&
- reset_work_tree_to_interested add_sub1 &&
- (
- cd submodule_update &&
- git branch -t modify_sub1 origin/modify_sub1 &&
- $command modify_sub1 &&
- test_superproject_content origin/modify_sub1 &&
- test_submodule_content sub1 origin/modify_sub1
- )
- '
- # Updating a submodule to an invalid sha1 doesn't update the
- # submodule's work tree, subsequent update will fail
- test_expect_success "$command: modified submodule does not update submodule work tree to invalid commit" '
- prolog &&
- reset_work_tree_to_interested add_sub1 &&
- (
- cd submodule_update &&
- git branch -t invalid_sub1 origin/invalid_sub1 &&
- test_must_fail $command invalid_sub1 &&
- test_superproject_content origin/add_sub1 &&
- test_submodule_content sub1 origin/add_sub1
- )
- '
# Updating a submodule from an invalid sha1 updates
test_expect_success "$command: modified submodule does update submodule work tree from invalid commit" '
prolog &&
test_submodule_content sub1 origin/modify_sub1
)
'
+
+ test_expect_success "$command: changed submodule worktree is reset" '
+ prolog &&
+ reset_work_tree_to_interested add_sub1 &&
+ (
+ cd submodule_update &&
+ rm sub1/file1 &&
+ : >sub1/new_file &&
+ git -C sub1 add new_file &&
+ $command HEAD &&
+ test_path_is_file sub1/file1 &&
+ test_path_is_missing sub1/new_file
+ )
+ '
}