Merge branch 'sb/diff-blobfind-pickaxe'
[gitweb.git] / t / lib-submodule-update.sh
index 2d26f86800906ab1783edf10e7196adadd5f4af7..38dadd2c2902f3621d54168d32a54d7863497968 100755 (executable)
@@ -306,9 +306,9 @@ test_submodule_content () {
 # to protect the history!
 #
 
-# Test that submodule contents are currently not updated when switching
-# between commits that change a submodule.
-test_submodule_switch () {
+# Internal function; use test_submodule_switch() or
+# test_submodule_forced_switch() instead.
+test_submodule_switch_common() {
        command="$1"
        ######################### Appearing submodule #########################
        # Switching to a commit letting a submodule appear creates empty dir ...
@@ -332,7 +332,7 @@ test_submodule_switch () {
                        test_submodule_content sub1 origin/add_sub1
                )
        '
-       # ... and doesn't care if it already exists ...
+       # ... and doesn't care if it already exists.
        test_expect_$RESULT "$command: added submodule leaves existing empty directory alone" '
                prolog &&
                reset_work_tree_to no_submodule &&
@@ -347,19 +347,6 @@ test_submodule_switch () {
                        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 unignored file with same name" '
-               prolog &&
-               reset_work_tree_to 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
-               )
-       '
        # Replacing a tracked file with a submodule produces an empty
        # directory ...
        test_expect_$RESULT "$command: replace tracked file with submodule creates empty directory" '
@@ -441,6 +428,11 @@ test_submodule_switch () {
                # submodule files with the newly checked out ones in the
                # directory of the same name while it shouldn't.
                RESULT="failure"
+       elif test "$KNOWN_FAILURE_FORCED_SWITCH_TESTS" = 1
+       then
+               # All existing tests that use test_submodule_forced_switch()
+               # require this.
+               RESULT="failure"
        else
                RESULT="success"
        fi
@@ -522,7 +514,6 @@ test_submodule_switch () {
                        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_$RESULT "$command: modified submodule does not update submodule work tree to invalid commit" '
@@ -555,235 +546,269 @@ test_submodule_switch () {
        '
 }
 
-# Test that submodule contents are currently not updated when switching
-# between commits that change a submodule, but throwing away local changes in
+# Declares and invokes several tests that, in various situations, checks that
+# the provided transition function:
+#  - 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 unchanged
+#  - 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 () {
+#   target=$1
+#   # Do something here that updates the worktree and index to match target,
+#   # but not any submodule directories.
+# }
+# test_submodule_switch "my_func"
+test_submodule_switch () {
+       command="$1"
+       test_submodule_switch_common "$command"
+
+       # An empty directory does not prevent the creation of a submodule of
+       # the same name, but a file does.
+       test_expect_success "$command: added submodule doesn't remove untracked unignored file with same name" '
+               prolog &&
+               reset_work_tree_to 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
+               )
+       '
+}
+
+# Same as test_submodule_switch(), except that throwing away local changes in
 # the superproject is allowed.
 test_submodule_forced_switch () {
        command="$1"
-       ######################### Appearing submodule #########################
-       # Switching to a commit letting a submodule appear creates empty dir ...
-       test_expect_success "$command: added submodule creates empty directory" '
+       KNOWN_FAILURE_FORCED_SWITCH_TESTS=1
+       test_submodule_switch_common "$command"
+
+       # When forced, a file in the superproject does not prevent creating a
+       # submodule of the same name.
+       test_expect_success "$command: added submodule does remove untracked unignored file with same name when forced" '
                prolog &&
                reset_work_tree_to no_submodule &&
                (
                        cd submodule_update &&
                        git branch -t add_sub1 origin/add_sub1 &&
+                       >sub1 &&
                        $command add_sub1 &&
                        test_superproject_content origin/add_sub1 &&
-                       test_dir_is_empty sub1 &&
-                       git submodule update --init --recursive &&
-                       test_submodule_content sub1 origin/add_sub1
+                       test_dir_is_empty sub1
                )
        '
-       # ... and doesn't care if it already exists ...
-       test_expect_success "$command: added submodule leaves existing empty directory alone" '
+}
+
+# Test that submodule contents are correctly updated when switching
+# between commits that change a submodule.
+# Test that the following transitions are correctly handled:
+# (These tests are also above in the case where we expect no change
+#  in the submodule)
+# - Updated submodule
+# - New submodule
+# - Removed submodule
+# - Directory containing tracked files replaced by submodule
+# - Submodule replaced by tracked files in directory
+# - Submodule replaced by tracked file with the same name
+# - tracked file replaced by submodule
+#
+# New test cases
+# - Removing a submodule with a git directory absorbs the submodules
+#   git directory first into the superproject.
+
+# 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" '
                prolog &&
-               reset_work_tree_to no_submodule &&
+               reset_work_tree_to_interested no_submodule &&
                (
                        cd submodule_update &&
                        git branch -t add_sub1 origin/add_sub1 &&
-                       mkdir sub1 &&
                        $command add_sub1 &&
                        test_superproject_content origin/add_sub1 &&
-                       test_dir_is_empty sub1 &&
-                       git submodule update --init --recursive &&
                        test_submodule_content sub1 origin/add_sub1
                )
        '
-       # ... unless there is an untracked file in its place.
-       test_expect_success "$command: added submodule does remove untracked unignored file with same name when forced" '
+       # ... ignoring an empty existing directory.
+       test_expect_success "$command: added submodule is checked out in empty dir" '
                prolog &&
-               reset_work_tree_to no_submodule &&
+               reset_work_tree_to_interested no_submodule &&
                (
                        cd submodule_update &&
+                       mkdir sub1 &&
                        git branch -t add_sub1 origin/add_sub1 &&
-                       >sub1 &&
                        $command add_sub1 &&
                        test_superproject_content origin/add_sub1 &&
-                       test_dir_is_empty sub1
+                       test_submodule_content sub1 origin/add_sub1
                )
        '
-       # Replacing a tracked file with a submodule produces an empty
-       # directory ...
-       test_expect_success "$command: replace tracked file with submodule creates empty directory" '
+       test_expect_success "$command: submodule branch is not changed, detach HEAD instead" '
                prolog &&
-               reset_work_tree_to replace_sub1_with_file &&
+               reset_work_tree_to_interested add_sub1 &&
+               (
+                       cd submodule_update &&
+                       git -C sub1 checkout -b keep_branch &&
+                       git -C sub1 rev-parse HEAD >expect &&
+                       git branch -t check-keep origin/modify_sub1 &&
+                       $command check-keep &&
+                       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 &&
+               reset_work_tree_to_interested replace_sub1_with_file &&
                (
                        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_dir_is_empty sub1 &&
-                       git submodule update --init --recursive &&
                        test_submodule_content sub1 origin/replace_file_with_sub1
                )
        '
-       # ... as does removing a directory with tracked files with a
-       # submodule.
+       # ... as does removing a directory with tracked files with a submodule.
        test_expect_success "$command: replace directory with submodule" '
                prolog &&
-               reset_work_tree_to replace_sub1_with_directory &&
+               reset_work_tree_to_interested replace_sub1_with_directory &&
                (
                        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_dir_is_empty sub1 &&
-                       git submodule update --init --recursive &&
                        test_submodule_content sub1 origin/replace_directory_with_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" '
+       # Removing a submodule removes its work tree ...
+       test_expect_success "$command: removed submodule removes submodules working tree" '
                prolog &&
-               reset_work_tree_to add_sub1 &&
+               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_submodule_content sub1 origin/add_sub1
+                       ! test -e sub1
                )
        '
-       # ... especially when it contains a .git directory.
-       test_expect_success "$command: removed submodule leaves submodule containing a .git directory alone" '
+       # ... absorbing a .git directory along the way.
+       test_expect_success "$command: removed submodule absorbs submodules .git directory" '
                prolog &&
-               reset_work_tree_to add_sub1 &&
+               reset_work_tree_to_interested add_sub1 &&
                (
                        cd submodule_update &&
                        git branch -t remove_sub1 origin/remove_sub1 &&
                        replace_gitfile_with_git_dir sub1 &&
+                       rm -rf .git/modules &&
                        $command remove_sub1 &&
                        test_superproject_content origin/remove_sub1 &&
-                       test_git_directory_is_unchanged sub1 &&
-                       test_submodule_content sub1 origin/add_sub1
-               )
-       '
-       # Replacing a submodule with files in a directory must fail as the
-       # submodule work tree isn't removed ...
-       test_expect_failure "$command: replace submodule with a directory must fail" '
-               prolog &&
-               reset_work_tree_to add_sub1 &&
-               (
-                       cd submodule_update &&
-                       git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
-                       test_must_fail $command replace_sub1_with_directory &&
-                       test_superproject_content origin/add_sub1 &&
-                       test_submodule_content sub1 origin/add_sub1
-               )
-       '
-       # ... especially when it contains a .git directory.
-       test_expect_failure "$command: replace submodule containing a .git directory with a directory must fail" '
-               prolog &&
-               reset_work_tree_to add_sub1 &&
-               (
-                       cd submodule_update &&
-                       git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
-                       replace_gitfile_with_git_dir sub1 &&
-                       test_must_fail $command replace_sub1_with_directory &&
-                       test_superproject_content origin/add_sub1 &&
-                       test_git_directory_is_unchanged sub1 &&
-                       test_submodule_content sub1 origin/add_sub1
+                       ! test -e sub1 &&
+                       test_git_directory_exists sub1
                )
        '
-       # Replacing it with a file must fail as it could throw away any local
-       # work tree changes ...
-       test_expect_failure "$command: replace submodule with a file must fail" '
+
+       # Replacing it with a file ...
+       test_expect_success "$command: replace submodule with a file" '
                prolog &&
-               reset_work_tree_to add_sub1 &&
+               reset_work_tree_to_interested add_sub1 &&
                (
                        cd submodule_update &&
                        git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
-                       test_must_fail $command replace_sub1_with_file &&
-                       test_superproject_content origin/add_sub1 &&
-                       test_submodule_content sub1 origin/add_sub1
+                       $command replace_sub1_with_file &&
+                       test_superproject_content origin/replace_sub1_with_file &&
+                       test -f sub1
                )
        '
-       # ... or even destroy unpushed parts of submodule history if that
-       # still uses a .git directory.
-       test_expect_failure "$command: replace submodule containing a .git directory with a file must fail" '
+       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 &&
-               reset_work_tree_to add_sub1 &&
+               reset_work_tree_to_interested add_sub1 &&
                (
                        cd submodule_update &&
                        git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
-                       replace_gitfile_with_git_dir sub1 &&
+                       : >sub1/untrackedfile &&
                        test_must_fail $command replace_sub1_with_file &&
                        test_superproject_content origin/add_sub1 &&
-                       test_git_directory_is_unchanged sub1 &&
                        test_submodule_content sub1 origin/add_sub1
+                       test -f sub1/untracked_file
                )
        '
 
        ########################## Modified submodule #########################
-       # Updating a submodule sha1 doesn't update the submodule's work tree
-       test_expect_success "$command: modified submodule does not update submodule work tree" '
+       # 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 add_sub1 &&
+               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/add_sub1 &&
-                       git submodule update &&
                        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" '
+       # superproject nor the submodule's work tree.
+       test_expect_success "$command: updating to a missing submodule commit fails" '
                prolog &&
-               reset_work_tree_to add_sub1 &&
+               reset_work_tree_to_interested add_sub1 &&
                (
                        cd submodule_update &&
                        git branch -t invalid_sub1 origin/invalid_sub1 &&
-                       $command invalid_sub1 &&
-                       test_superproject_content origin/invalid_sub1 &&
-                       test_submodule_content sub1 origin/add_sub1 &&
-                       test_must_fail git submodule update &&
+                       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 doesn't update the
-       # submodule's work tree, subsequent update will succeed
-       test_expect_success "$command: modified submodule does not update submodule work tree from invalid commit" '
-               prolog &&
-               reset_work_tree_to invalid_sub1 &&
-               (
-                       cd submodule_update &&
-                       git branch -t valid_sub1 origin/valid_sub1 &&
-                       $command valid_sub1 &&
-                       test_superproject_content origin/valid_sub1 &&
-                       test_dir_is_empty sub1 &&
-                       git submodule update --init --recursive &&
-                       test_submodule_content sub1 origin/valid_sub1
-               )
-       '
 }
 
-# Test that submodule contents are correctly updated when switching
-# between commits that change a submodule.
-# Test that the following transitions are correctly handled:
-# (These tests are also above in the case where we expect no change
-#  in the submodule)
-# - Updated submodule
-# - New submodule
-# - Removed submodule
-# - Directory containing tracked files replaced by submodule
-# - Submodule replaced by tracked files in directory
-# - Submodule replaced by tracked file with the same name
-# - tracked file replaced by submodule
+# 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
 #
-# New test cases
-# - Removing a submodule with a git directory absorbs the submodules
-#   git directory first into the superproject.
-
+# 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"
+       test_submodule_recursing_with_args_common "$command"
+
        RESULTDS=success
        if test "$KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS" = 1
        then
@@ -794,33 +819,8 @@ test_submodule_switch_recursing_with_args () {
        then
                RESULTOI=failure
        fi
-       ######################### Appearing submodule #########################
-       # Switching to a commit letting a submodule appear checks it out ...
-       test_expect_success "$command: added submodule is checked out" '
-               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
-               )
-       '
-       # ... 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 &&
-               (
-                       cd submodule_update &&
-                       mkdir sub1 &&
-                       git branch -t add_sub1 origin/add_sub1 &&
-                       $command add_sub1 &&
-                       test_superproject_content origin/add_sub1 &&
-                       test_submodule_content sub1 origin/add_sub1
-               )
-       '
-       # ... unless there is an untracked file in its place.
+       # 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 &&
@@ -848,59 +848,7 @@ test_submodule_switch_recursing_with_args () {
                        test_submodule_content sub1 origin/add_sub1
                )
        '
-       # 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 &&
-               reset_work_tree_to_interested replace_sub1_with_file &&
-               (
-                       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
-               )
-       '
-       # ... as does removing a directory with tracked files with a submodule.
-       test_expect_success "$command: replace directory with submodule" '
-               prolog &&
-               reset_work_tree_to_interested replace_sub1_with_directory &&
-               (
-                       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
-               )
-       '
 
-       ######################## Disappearing submodule #######################
-       # Removing a submodule removes its work tree ...
-       test_expect_success "$command: removed submodule removes submodules working 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
-               )
-       '
-       # ... absorbing a .git directory along the way.
-       test_expect_success "$command: removed submodule absorbs submodules .git directory" '
-               prolog &&
-               reset_work_tree_to_interested add_sub1 &&
-               (
-                       cd submodule_update &&
-                       git branch -t remove_sub1 origin/remove_sub1 &&
-                       replace_gitfile_with_git_dir sub1 &&
-                       rm -rf .git/modules &&
-                       $command remove_sub1 &&
-                       test_superproject_content origin/remove_sub1 &&
-                       ! test -e sub1 &&
-                       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" '
@@ -929,33 +877,6 @@ test_submodule_switch_recursing_with_args () {
                )
        '
 
-       # 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 &&
-                       test -f sub1
-               )
-       '
-
-       # ... must check its local work tree for untracked files
-       test_expect_$RESULTDS "$command: replace submodule with a file must fail with 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/untrackedfile &&
-                       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" &&
@@ -971,20 +892,6 @@ test_submodule_switch_recursing_with_args () {
                )
        '
 
-       ########################## 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
-               )
-       '
-
        test_expect_success "git -c submodule.recurse=true $cmd_args: modified submodule updates submodule work tree" '
                prolog &&
                reset_work_tree_to_interested add_sub1 &&
@@ -997,20 +904,6 @@ test_submodule_switch_recursing_with_args () {
                )
        '
 
-       # 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" '
-               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
-               )
-       '
-
        # recursing deeper than one level doesn't work yet.
        test_expect_success "$command: modified submodule updates submodule recursively" '
                prolog &&
@@ -1026,44 +919,20 @@ test_submodule_switch_recursing_with_args () {
        '
 }
 
-# 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.
+# 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
-       ######################### Appearing submodule #########################
-       # Switching to a commit letting a submodule appear creates empty dir ...
-       test_expect_success "$command: added submodule is checked out" '
-               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
-               )
-       '
-       # ... and doesn't care if it already exists ...
-       test_expect_success "$command: added submodule ignores empty directory" '
-               prolog &&
-               reset_work_tree_to_interested no_submodule &&
-               (
-                       cd submodule_update &&
-                       git branch -t add_sub1 origin/add_sub1 &&
-                       mkdir sub1 &&
-                       $command add_sub1 &&
-                       test_superproject_content origin/add_sub1 &&
-                       test_submodule_content sub1 origin/add_sub1
-               )
-       '
-       # ... not caring about an untracked file either
+       # 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 &&
@@ -1076,60 +945,7 @@ test_submodule_forced_switch_recursing_with_args () {
                        test_submodule_content sub1 origin/add_sub1
                )
        '
-       # Replacing a tracked file with a submodule checks out the submodule
-       test_expect_success "$command: replace tracked file with submodule populates the submodule" '
-               prolog &&
-               reset_work_tree_to_interested replace_sub1_with_file &&
-               (
-                       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
-               )
-       '
-       # ... as does removing a directory with tracked files with a
-       # submodule.
-       test_expect_success "$command: replace directory with submodule" '
-               prolog &&
-               reset_work_tree_to_interested replace_sub1_with_directory &&
-               (
-                       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
-               )
-       '
 
-       ######################## 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" '
-               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
-               )
-       '
-       # ... especially when it contains a .git directory.
-       test_expect_success "$command: removed submodule leaves submodule containing a .git directory alone" '
-               prolog &&
-               reset_work_tree_to_interested add_sub1 &&
-               (
-                       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
-               )
-       '
        # Replacing a submodule with files in a directory ...
        test_expect_success "$command: replace submodule with a directory" '
                prolog &&
@@ -1156,17 +972,6 @@ test_submodule_forced_switch_recursing_with_args () {
                        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" '
@@ -1181,46 +986,6 @@ test_submodule_forced_switch_recursing_with_args () {
                )
        '
 
-       # ... 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 &&