about summary refs log tree commit
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2020-03-26 17:11:20 -0700
committerJunio C Hamano <gitster@pobox.com>2020-03-26 17:11:20 -0700
commitfe870600fe2735782e9e8a8c5441f91b1a58e273 (patch)
tree9de44bb368d796cf8ff0bbe41a7c8fae52a4904a
parenta7d14a44285d3ec4b25bf9e3b7df701221350661 (diff)
parent846f34d3514b81764dea7c2a4851f6187ab31aad (diff)
downloadgit-fe870600fe2735782e9e8a8c5441f91b1a58e273.tar.gz
Fix "git checkout --recurse-submodules" of a nested submodule
hierarchy.

* pb/recurse-submodules-fix:
  t/lib-submodule-update: add test removing nested submodules
  unpack-trees: check for missing submodule directory in merged_entry
  unpack-trees: remove outdated description for verify_clean_submodule
  t/lib-submodule-update: move a test to the right section
  t/lib-submodule-update: remove outdated test description
  t7112: remove mention of KNOWN_FAILURE_SUBMODULE_RECURSIVE_NESTED
-rwxr-xr-xt/lib-submodule-update.sh68
-rwxr-xr-xt/t7112-reset-submodule.sh1
-rw-r--r--unpack-trees.c7
3 files changed, 51 insertions, 25 deletions
diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh
index 1dd17fc03e..64fc6487dd 100755
--- a/t/lib-submodule-update.sh
+++ b/t/lib-submodule-update.sh
@@ -297,7 +297,7 @@ test_submodule_content () {
 # - 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
+# - Tracked file replaced by submodule
 #
 # The default is that submodule contents aren't changed until "git submodule
 # update" is run. And even then that command doesn't delete the work tree of
@@ -621,11 +621,13 @@ test_submodule_forced_switch () {
 # - 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
+# - Tracked file replaced by submodule
 #
 # New test cases
 # - Removing a submodule with a git directory absorbs the submodules
 #   git directory first into the superproject.
+# - Switching from no submodule to nested submodules
+# - Switching from nested submodules to no submodule
 
 # Internal function; use test_submodule_switch_recursing_with_args() or
 # test_submodule_forced_switch_recursing_with_args() instead.
@@ -658,22 +660,6 @@ test_submodule_recursing_with_args_common() {
                         test_submodule_content sub1 origin/add_sub1
                 )
         '
-        test_expect_success "$command: submodule branch is not changed, detach HEAD instead" '
-                prolog &&
-                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 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" '
@@ -699,6 +685,19 @@ test_submodule_recursing_with_args_common() {
                         test_submodule_content sub1 origin/replace_directory_with_sub1
                 )
         '
+        # Switching to a commit with nested submodules recursively checks them out
+        test_expect_success "$command: nested submodules are checked out" '
+                prolog &&
+                reset_work_tree_to_interested no_submodule &&
+                (
+                        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
+                )
+        '
 
         ######################## Disappearing submodule #######################
         # Removing a submodule removes its work tree ...
@@ -762,6 +761,21 @@ test_submodule_recursing_with_args_common() {
                 )
         '
 
+        # Switching to a commit without nested submodules removes their worktrees
+        test_expect_success "$command: worktrees of nested submodules are removed" '
+                prolog &&
+                reset_work_tree_to_interested add_nested_sub &&
+                (
+                        cd submodule_update &&
+                        git branch -t no_submodule origin/no_submodule &&
+                        $command no_submodule &&
+                        test_superproject_content origin/no_submodule &&
+                        ! test_path_is_dir sub1 &&
+                        test_must_fail git config -f .git/modules/sub1/config core.worktree &&
+                        test_must_fail git config -f .git/modules/sub1/modules/sub2/config core.worktree
+                )
+        '
+
         ########################## Modified submodule #########################
         # Updating a submodule sha1 updates the submodule's work tree
         test_expect_success "$command: modified submodule updates submodule work tree" '
@@ -789,6 +803,23 @@ test_submodule_recursing_with_args_common() {
                         test_submodule_content sub1 origin/add_sub1
                 )
         '
+        # Updating a submodule does not touch the currently checked out branch in the submodule
+        test_expect_success "$command: submodule branch is not changed, detach HEAD instead" '
+                prolog &&
+                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 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
+                )
+        '
 }
 
 # Declares and invokes several tests that, in various situations, checks that
@@ -908,7 +939,6 @@ test_submodule_switch_recursing_with_args () {
                 )
         '
 
-        # 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 &&
diff --git a/t/t7112-reset-submodule.sh b/t/t7112-reset-submodule.sh
index a1cb9ff858..67346424a5 100755
--- a/t/t7112-reset-submodule.sh
+++ b/t/t7112-reset-submodule.sh
@@ -5,7 +5,6 @@ test_description='reset can handle submodules'
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-submodule-update.sh
 
-KNOWN_FAILURE_SUBMODULE_RECURSIVE_NESTED=1
 KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS=1
 KNOWN_FAILURE_SUBMODULE_OVERWRITE_IGNORED_UNTRACKED=1
 
diff --git a/unpack-trees.c b/unpack-trees.c
index 1ecdab3304..1dbcb8c1c3 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -1815,9 +1815,6 @@ static void invalidate_ce_path(const struct cache_entry *ce,
 /*
  * Check that checking out ce->sha1 in subdir ce->name is not
  * going to overwrite any working files.
- *
- * Currently, git does not checkout subprojects during a superproject
- * checkout, so it is not going to overwrite anything.
  */
 static int verify_clean_submodule(const char *old_sha1,
                                   const struct cache_entry *ce,
@@ -2067,7 +2064,7 @@ static int merged_entry(const struct cache_entry *ce,
                 }
                 invalidate_ce_path(merge, o);
 
-                if (submodule_from_ce(ce)) {
+                if (submodule_from_ce(ce) && file_exists(ce->name)) {
                         int ret = check_submodule_move_head(ce, NULL,
                                                             oid_to_hex(&ce->oid),
                                                             o);
@@ -2096,7 +2093,7 @@ static int merged_entry(const struct cache_entry *ce,
                         invalidate_ce_path(old, o);
                 }
 
-                if (submodule_from_ce(ce)) {
+                if (submodule_from_ce(ce) && file_exists(ce->name)) {
                         int ret = check_submodule_move_head(ce, oid_to_hex(&old->oid),
                                                             oid_to_hex(&ce->oid),
                                                             o);