{"thread":{"id":"44869","subject":"[RFC-PATCH] lib-submodule-update.sh: define tests for recursing into submodules","startedAt":"2017-01-13T01:52:37Z","lastAt":"2017-01-13T01:52:37Z","messageCount":1,"participants":["Stefan Beller"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"309342","messageId":"20170113015145.12330-1-sbeller@google.com","threadId":"44869","inReplyTo":null,"subject":"[RFC-PATCH] lib-submodule-update.sh: define tests for recursing into submodules","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-01-13T01:51:45Z","receivedAt":"2017-01-13T01:52:37Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"Currently lib-submodule-update.sh provides 2 functions\ntest_submodule_switch and test_submodule_forced_switch that are used by a\nvariety of tests to ensure that submodules behave as expected. The current\nexpected behavior is that submodules are not touched at all.\n(See 42639d2317a for the exact setup)\n\nIn the future we want to teach all these commands to properly recurse\ninto submodules. To do that, we'll add two testing functions to\nsubmodule-update-lib.sh test_submodule_switch_recursing and\ntest_submodule_forced_switch_recursing.\n\nThese two functions behave in analogy to the already existing functions\njust with a different expectation on submodule behavior. The submodule\nin the working tree is expected to be updated to the recorded submodule\nversion. The behavior is analogous to e.g. the behavior of files in a\nnested directory in the working tree, where a change to the working tree\nhandles any arising directory/file conflicts just fine.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n\nSo I have been looking into implementing \"checkout --recurse-submodules\",\nfor quite some time, but the correct approach is to not just make git-checkout\nsupport submodules, but all the working tree operations at the same time.\n\nCurrently all the working tree operations have a test that submodules are\nnot touched even when the superproject is messing with the submodule,\nso all submodule operations are tested via the submodule library, e.g.:\n\n    test_submodule_switch \"git pull\"\n\nwould see what happens for git-pull. Below I am proposing a test\nthat can be used for any operation that is aware of submodules, e.g.\neventually we'll have checks like:\n\n    test_submodule_switch_recursing \"git checkout --recurse-submodules\"\n    # as well as\n    test_submodule_switch_recursing \"git pull --recurse-submodules\"\n\nThis RFC email is asking if the behavior is sound and expected for submodule\noperations in the working tree.\n\nThanks,\nStefan\n\n t/lib-submodule-update.sh | 465 +++++++++++++++++++++++++++++++++++++++++++++-\n 1 file changed, 463 insertions(+), 2 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 79cdd34a54..bf33c30409 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -4,6 +4,7 @@\n # - New submodule (no_submodule => add_sub1)\n # - Removed submodule (add_sub1 => remove_sub1)\n # - Updated submodule (add_sub1 => modify_sub1)\n+# - Updated submodule recursively (modify_sub1 => modify_sub1_recursively)\n # - Submodule updated to invalid commit (add_sub1 => invalid_sub1)\n # - Submodule updated from invalid commit (invalid_sub1 => valid_sub1)\n # - Submodule replaced by tracked files in directory (add_sub1 =>\n@@ -20,8 +21,8 @@\n #                 /   replace_sub1_with_directory\n #                /----O\n #               /     ^\n-#              /      modify_sub1\n-#      O------O-------O\n+#              /      modify_sub1      modify_sub1_recursive\n+#      O------O-------O----------------O\n #      ^      ^\\      ^\n #      |      | \\     remove_sub1\n #      |      |  -----O-----O\n@@ -67,6 +68,14 @@ create_lib_submodule_repo () {\n \t\tgit add sub1 &&\n \t\tgit commit -m \"Modify sub1\" &&\n \n+\t\tgit checkout -b \"modify_sub1_recursively\" \"modify_sub1\" &&\n+\t\tgit -C sub1 checkout -b \"add_nested_sub\" &&\n+\t\tgit -C sub1 submodule add --branch no_submodule ./. sub2 &&\n+\t\tgit -C sub1 commit -a -m \"add a nested submodule\" &&\n+\t\tgit add sub1 &&\n+\t\tgit commit -a -m \"update submodule, that updates a nested submodule\" &&\n+\t\tgit -C sub1 submodule deinit -f --all &&\n+\n \t\tgit checkout -b \"replace_sub1_with_directory\" \"add_sub1\" &&\n \t\tgit submodule update &&\n \t\t(\n@@ -133,6 +142,15 @@ test_git_directory_is_unchanged () {\n \t)\n }\n \n+test_git_directory_exists() {\n+\ttest -e \".git/modules/$1\" &&\n+\t(\n+\t\tcd \".git/modules/$1\" &&\n+\t\t# does core.worktree point at the right place?\n+\t\ttest \"$(git config core.worktree)\" = \"../../../$1\"\n+\t)\n+}\n+\n # Helper function to be executed at the start of every test below, it sets up\n # the submodule repo if it doesn't exist and configures the most problematic\n # settings for diff.ignoreSubmodules.\n@@ -678,3 +696,446 @@ test_submodule_forced_switch () {\n \t\t)\n \t'\n }\n+\n+# Test that submodule contents are correctly updated when switching\n+# between commits that change a submodule.\n+# Test that the following transitions are correctly handled:\n+# (These tests are also above in the case where we expect no change\n+#  in the submodule)\n+# - Updated submodule\n+# - New submodule\n+# - Removed submodule\n+# - Directory containing tracked files replaced by submodule\n+# - Submodule replaced by tracked files in directory\n+# - Submodule replaced by tracked file with the same name\n+# - tracked file replaced by submodule\n+#\n+# New test cases\n+# - Removing a submodule with a git directory absorbs the submodules\n+#   git directory first into the superproject.\n+\n+test_submodule_switch_recursing () {\n+\tcommand=\"$1\"\n+\t######################### Appearing submodule #########################\n+\t# Switching to a commit letting a submodule appear checks it out ...\n+\ttest_expect_success \"$command: added submodule is checked out\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to no_submodule &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\t$command add_sub1 &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... ignoring an empty existing directory ...\n+\ttest_expect_success \"$command: added submodule is checked out in empty dir\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to no_submodule &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tmkdir sub1 &&\n+\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\t$command add_sub1 &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... unless there is an untracked file in its place.\n+\ttest_expect_success \"$command: added submodule doesn't remove untracked file with same name\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to no_submodule &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\t: >sub1 &&\n+\t\t\ttest_must_fail $command add_sub1 &&\n+\t\t\ttest_superproject_content origin/no_submodule &&\n+\t\t\ttest_must_be_empty sub1\n+\t\t)\n+\t'\n+\n+\t# ... but an ignored file is fine.\n+\ttest_expect_success \"$command: added submodule removes an untracked ignored file\" '\n+\t\ttest_when_finished \"rm submodule_update/.git/info/exclude\" &&\n+\t\tprolog &&\n+\t\treset_work_tree_to no_submodule &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\t: >sub1 &&\n+\t\t\techo sub1 > .git/info/exclude\n+\t\t\t$command add_sub1 &&\n+\t\t\ttest_superproject_content origin/no_submodule &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\n+\t# Replacing a tracked file with a submodule produces a checked out submodule\n+\ttest_expect_success \"$command: replace tracked file with submodule checks out submodule\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to replace_sub1_with_file &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&\n+\t\t\t$command replace_file_with_sub1 &&\n+\t\t\ttest_superproject_content origin/replace_file_with_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/replace_file_with_sub1\n+\t\t)\n+\t'\n+\t# ... as does removing a directory with tracked files with a\n+\t# submodule.\n+\ttest_expect_success \"$command: replace directory with submodule\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to replace_sub1_with_directory &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&\n+\t\t\t$command replace_directory_with_sub1 &&\n+\t\t\ttest_superproject_content origin/replace_directory_with_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/replace_directory_with_sub1\n+\t\t)\n+\t'\n+\n+\t######################## Disappearing submodule #######################\n+\t# Removing a submodule removes its work tree ...\n+\ttest_expect_success \"$command: removed submodule removes submodules working tree\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n+\t\t\t$command remove_sub1 &&\n+\t\t\ttest_superproject_content origin/remove_sub1 &&\n+\t\t\t! test -e sub1\n+\t\t)\n+\t'\n+\t# ... absorbing a .git directory along the way.\n+\ttest_expect_success \"$command: removed submodule absorbs submodules .git directory\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n+\t\t\treplace_gitfile_with_git_dir sub1 &&\n+\t\t\trm -rf .git/modules &&\n+\t\t\t$command remove_sub1 &&\n+\t\t\ttest_superproject_content origin/remove_sub1 &&\n+\t\t\t! test -e sub1 &&\n+\t\t\ttest_git_directory_exists sub1\n+\t\t)\n+\t'\n+\t# Replacing a submodule with files in a directory must succeeds\n+\t# when the submodule is clean\n+\ttest_expect_success \"$command: replace submodule with a directory\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\t$command replace_sub1_with_directory &&\n+\t\t\ttest_superproject_content origin/replace_sub1_with_directory &&\n+\t\t\ttest_submodule_content sub1 origin/replace_sub1_with_directory\n+\t\t)\n+\t'\n+\t# ... absorbing a .git directory.\n+\ttest_expect_success \"$command: replace submodule containing a .git directory with a directory must absorb the git dir\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\treplace_gitfile_with_git_dir sub1 &&\n+\t\t\trm -rf .git/modules &&\n+\t\t\t$command replace_sub1_with_directory &&\n+\t\t\ttest_superproject_content origin/replace_sub1_with_directory &&\n+\t\t\ttest_git_directory_exists sub1\n+\t\t)\n+\t'\n+\n+\t# Replacing it with a file ...\n+\ttest_expect_success \"$command: replace submodule with a file\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\t$command replace_sub1_with_file &&\n+\t\t\ttest_superproject_content origin/replace_sub1_with_file &&\n+\t\t\ttest -f sub1\n+\t\t)\n+\t'\n+\n+\t# ... must check its local work tree for untracked files\n+\ttest_expect_success \"$command: replace submodule with a file must fail with untracked files\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\t> sub1/untrackedfile &&\n+\t\t\t$command replace_sub1_with_file &&\n+\t\t\ttest_superproject_content origin/replace_sub1_with_file &&\n+\t\t\ttest -f sub1\n+\t\t)\n+\t'\n+\n+\t# ... and ignored files are ignroed\n+\ttest_expect_success \"$command: replace submodule with a file works ignores ignored files in submodule\" '\n+\t\ttest_when_finished \"rm .git/modules/sub1/info/exclude\" &&\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\t> sub1/ignored &&\n+\t\t\t$command replace_sub1_with_file &&\n+\t\t\ttest_superproject_content origin/replace_sub1_with_file &&\n+\t\t\ttest -f sub1\n+\t\t)\n+\t'\n+\n+\t########################## Modified submodule #########################\n+\t# Updating a submodule sha1 updates the submodule's work tree\n+\ttest_expect_success \"$command: modified submodule updates submodule work tree\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t modify_sub1 origin/modify_sub1 &&\n+\t\t\t$command modify_sub1 &&\n+\t\t\ttest_superproject_content origin/modify_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/modify_sub1\n+\t\t)\n+\t'\n+\n+\t# Updating a submodule to an invalid sha1 doesn't update the\n+\t# superproject nor the submodule's work tree.\n+\ttest_expect_success \"$command: updating to a missing submodule commit fails\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t invalid_sub1 origin/invalid_sub1 &&\n+\t\t\ttest_must_fail $command invalid_sub1 &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\n+\ttest_expect_success \"$command: modified submodule updates submodule recursively\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t modify_sub1_recursively origin/modify_sub1_recursively &&\n+\t\t\t$command modify_sub1_recursively &&\n+\t\t\ttest_superproject_content origin/modify_sub1_recursively &&\n+\t\t\ttest_submodule_content sub1 origin/modify_sub1_recursively\n+\t\t\ttest_submodule_content sub1/sub2\n+\t\t)\n+\t'\n+}\n+\n+# Test that submodule contents are updated when switching between commits\n+# that change a submodule, but throwing away local changes in\n+# the superproject as well as the submodule is allowed.\n+test_submodule_forced_switch_recursing () {\n+\tcommand=\"$1\"\n+\t######################### Appearing submodule #########################\n+\t# Switching to a commit letting a submodule appear creates empty dir ...\n+\ttest_expect_success \"$command: added submodule is checked out\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to no_submodule &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\t$command add_sub1 &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... and doesn't care if it already exists ...\n+\ttest_expect_success \"$command: added submodule ignores empty directory\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to no_submodule &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\tmkdir sub1 &&\n+\t\t\t$command add_sub1 &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... not caring about an untracked file either\n+\ttest_expect_success \"$command: added submodule does remove untracked unignored file with same name when forced\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to no_submodule &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\t>sub1 &&\n+\t\t\t$command add_sub1 &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# Replacing a tracked file with a submodule checks out the submodule\n+\ttest_expect_success \"$command: replace tracked file with submodule populates the submodule\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to replace_sub1_with_file &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&\n+\t\t\t$command replace_file_with_sub1 &&\n+\t\t\ttest_superproject_content origin/replace_file_with_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/replace_file_with_sub1\n+\t\t)\n+\t'\n+\t# ... as does removing a directory with tracked files with a\n+\t# submodule.\n+\ttest_expect_success \"$command: replace directory with submodule\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to replace_sub1_with_directory &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&\n+\t\t\t$command replace_directory_with_sub1 &&\n+\t\t\ttest_superproject_content origin/replace_directory_with_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/replace_directory_with_sub1\n+\t\t)\n+\t'\n+\n+\t######################## Disappearing submodule #######################\n+\t# Removing a submodule doesn't remove its work tree ...\n+\ttest_expect_success \"$command: removed submodule leaves submodule directory and its contents in place\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n+\t\t\t$command remove_sub1 &&\n+\t\t\ttest_superproject_content origin/remove_sub1 &&\n+\t\t\t! test -e sub1\n+\t\t)\n+\t'\n+\t# ... especially when it contains a .git directory.\n+\ttest_expect_success \"$command: removed submodule leaves submodule containing a .git directory alone\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n+\t\t\treplace_gitfile_with_git_dir sub1 &&\n+\t\t\trm -rf .git/modules/sub1 &&\n+\t\t\t$command remove_sub1 &&\n+\t\t\ttest_superproject_content origin/remove_sub1 &&\n+\t\t\ttest_git_directory_exists sub1 &&\n+\t\t\t! test -e sub1\n+\t\t)\n+\t'\n+\t# Replacing a submodule with files in a directory ...\n+\ttest_expect_failure \"$command: replace submodule with a directory\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\t$command replace_sub1_with_directory &&\n+\t\t\ttest_superproject_content origin/replace_sub1_with_directory\n+\t\t)\n+\t'\n+\t# ... absorbing a .git directory.\n+\ttest_expect_failure \"$command: replace submodule containing a .git directory with a directory must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\treplace_gitfile_with_git_dir sub1 &&\n+\t\t\trm -rf .git/modules/sub1 &&\n+\t\t\t$command replace_sub1_with_directory &&\n+\t\t\ttest_superproject_content origin/replace_sub1_with_directory &&\n+\t\t\ttest_git_directory_exists sub1\n+\t\t)\n+\t'\n+\t# Replacing it with a file\n+\ttest_expect_failure \"$command: replace submodule with a file must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\t$command replace_sub1_with_file &&\n+\t\t\ttest_superproject_content origin/replace_sub1_with_file\n+\t\t)\n+\t'\n+\n+\t# ... even if the submodule contains ignored files\n+\ttest_expect_failure \"$command: replace submodule with a file\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\t: > sub1/expect &&\n+\t\t\t$command replace_sub1_with_file &&\n+\t\t\ttest_superproject_content origin/replace_sub1_with_file\n+\t\t)\n+\t'\n+\n+\t# ... but stops for untracked files that would be lost\n+\ttest_expect_failure \"$command: replace submodule with a file\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\t: > sub1/untracked_file &&\n+\t\t\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest -f sub1/untracked_file\n+\t\t)\n+\t'\n+\n+\t########################## Modified submodule #########################\n+\t# Updating a submodule sha1 updates the submodule's work tree\n+\ttest_expect_success \"$command: modified submodule updates submodule work tree\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t modify_sub1 origin/modify_sub1 &&\n+\t\t\t$command modify_sub1 &&\n+\t\t\ttest_superproject_content origin/modify_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/modify_sub1\n+\t\t)\n+\t'\n+\t# Updating a submodule to an invalid sha1 doesn't update the\n+\t# submodule's work tree, subsequent update will fail\n+\ttest_expect_success \"$command: modified submodule does not update submodule work tree to invalid commit\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t invalid_sub1 origin/invalid_sub1 &&\n+\t\t\ttest_must_fail $command invalid_sub1 &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# Updating a submodule from an invalid sha1 updates\n+\ttest_expect_success \"$command: modified submodule does not update submodule work tree from invalid commit\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to invalid_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t valid_sub1 origin/valid_sub1 &&\n+\t\t\t$command valid_sub1 &&\n+\t\t\ttest_superproject_content origin/valid_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/valid_sub1\n+\t\t)\n+\t'\n+}\n-- \n2.11.0.299.g77584d2295\n\n"}]}