{"thread":{"id":"53350","subject":"[PATCH 0/4] t: replace incorrect test_must_fail usage (part 5)","startedAt":"2020-04-29T12:22:52Z","lastAt":"2020-06-24T16:00:37Z","messageCount":64,"participants":["Denton Liu","Junio C Hamano","Taylor Blau","Johannes Sixt","Eric Sunshine","Philip Oakley","Jeff King","Đoàn Trần Công Danh"],"isPatch":true,"patchVersion":1,"patchTotal":4},"messages":[{"id":"396546","messageId":"cover.1588162842.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":null,"subject":"[PATCH 0/4] t: replace incorrect test_must_fail usage (part 5)","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-04-29T12:22:22Z","receivedAt":"2020-04-29T12:22:52Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"The overall scope of these patches is to replace inappropriate uses of\ntest_must_fail. IOW, we should only allow test_must_fail to run on `git`\nand `test-tool`. Ultimately, we will conclude by making test_must_fail\nerror out on non-git commands. An advance view of the final series can\nbe found here[1].\n\nThis is the fifth part. It focuses on lib-submodule-update.sh and tests\nthat make use of it.\n\nThe first part can be found here[2]. The second part can be found\nhere[3]. The third part can be found here[4]. The fourth part can be\nfound here[5].\n\n[1]: (may be rebased at any time) https://github.com/Denton-L/git/tree/ready/cleanup-test-must-fail2\n[2]: https://lore.kernel.org/git/cover.1576583819.git.liu.denton@gmail.com/\n[3]: https://lore.kernel.org/git/cover.1577454401.git.liu.denton@gmail.com/\n[4]: https://lore.kernel.org/git/cover.1585209554.git.liu.denton@gmail.com/\n[5]: https://lore.kernel.org/git/cover.1587372771.git.liu.denton@gmail.com/\n\nDenton Liu (4):\n  lib-submodule-update: add space after function name\n  lib-submodule-update: consolidate --recurse-submodules\n  lib-submodule-update: prepend \"git\" to $command\n  lib-submodule-update: pass OVERWRITING_FAIL\n\n t/lib-submodule-update.sh        | 47 ++++++++++++++++++++------------\n t/t1013-read-tree-submodule.sh   |  4 +--\n t/t2013-checkout-submodule.sh    |  4 +--\n t/t3426-rebase-submodule.sh      |  8 +++---\n t/t3512-cherry-pick-submodule.sh |  2 +-\n t/t3513-revert-submodule.sh      | 22 +++++++++------\n t/t3906-stash-submodule.sh       | 17 +++++++-----\n t/t4137-apply-submodule.sh       | 10 ++++---\n t/t4255-am-submodule.sh          | 10 ++++---\n t/t5572-pull-submodule.sh        | 16 +++++------\n t/t6041-bisect-submodule.sh      | 35 +++++++++++++-----------\n t/t7112-reset-submodule.sh       |  6 ++--\n t/t7613-merge-submodule.sh       |  8 +++---\n 13 files changed, 108 insertions(+), 81 deletions(-)\n\n-- \n2.26.2.548.gbb00c8a0a9\n\n"},{"id":"396547","messageId":"ea7a5ca7a97b31e123ed6062702cc1c6f6b33623.1588162842.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1588162842.git.liu.denton@gmail.com","subject":"[PATCH 1/4] lib-submodule-update: add space after function name","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-04-29T12:22:23Z","receivedAt":"2020-04-29T12:22:54Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"In the shell scripts in this codebase, the usual style is to include a\nspace between the function name and the (). Add these missing spaces to\nconform to the usual style of the code.\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\n t/lib-submodule-update.sh | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 64fc6487dd..a3732d3f6c 100644\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -183,7 +183,7 @@ test_git_directory_is_unchanged () {\n \t)\n }\n \n-test_git_directory_exists() {\n+test_git_directory_exists () {\n \ttest -e \".git/modules/$1\" &&\n \tif test -f sub1/.git\n \tthen\n@@ -309,7 +309,7 @@ test_submodule_content () {\n \n # Internal function; use test_submodule_switch() or\n # test_submodule_forced_switch() instead.\n-test_submodule_switch_common() {\n+test_submodule_switch_common () {\n \tcommand=\"$1\"\n \t######################### Appearing submodule #########################\n \t# Switching to a commit letting a submodule appear creates empty dir ...\n@@ -631,7 +631,7 @@ test_submodule_forced_switch () {\n \n # Internal function; use test_submodule_switch_recursing_with_args() or\n # test_submodule_forced_switch_recursing_with_args() instead.\n-test_submodule_recursing_with_args_common() {\n+test_submodule_recursing_with_args_common () {\n \tcommand=\"$1\"\n \n \t######################### Appearing submodule #########################\n-- \n2.26.2.548.gbb00c8a0a9\n\n"},{"id":"396549","messageId":"86eb9c5a8ad8dc0836f3a612a45a86bbd8cece24.1588162842.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1588162842.git.liu.denton@gmail.com","subject":"[PATCH 3/4] lib-submodule-update: prepend \"git\" to $command","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-04-29T12:22:25Z","receivedAt":"2020-04-29T12:22:57Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"Since all invocations of test_submodule_forced_switch() are git\ncommands, automatically prepend \"git\" before invoking\ntest_submodule_switch_common().\n\nSimilarly, many invocations of test_submodule_switch() are also git\ncommands so automatically prepend \"git\" before invoking\ntest_submodule_switch_common() as well.\n\nFinally, for invocations of test_submodule_switch() that invoke a custom\nfunction, rename the old function to test_submodule_switch_func().\n\nThis is necessary because in a future commit, we will be adding some\nlogic that needs to distinguish between an invocation of a plain git\ncomamnd and an invocation of a test helper function.\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\n t/lib-submodule-update.sh        | 14 +++++++++-----\n t/t1013-read-tree-submodule.sh   |  4 ++--\n t/t2013-checkout-submodule.sh    |  4 ++--\n t/t3426-rebase-submodule.sh      |  4 ++--\n t/t3512-cherry-pick-submodule.sh |  2 +-\n t/t3513-revert-submodule.sh      |  2 +-\n t/t3906-stash-submodule.sh       |  2 +-\n t/t4137-apply-submodule.sh       |  4 ++--\n t/t4255-am-submodule.sh          |  4 ++--\n t/t5572-pull-submodule.sh        |  8 ++++----\n t/t6041-bisect-submodule.sh      |  2 +-\n t/t7112-reset-submodule.sh       |  6 +++---\n t/t7613-merge-submodule.sh       |  8 ++++----\n 13 files changed, 34 insertions(+), 30 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 81457b4c31..cd80d77707 100644\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -307,8 +307,8 @@ test_submodule_content () {\n # to protect the history!\n #\n \n-# Internal function; use test_submodule_switch() or\n-# test_submodule_forced_switch() instead.\n+# Internal function; use test_submodule_switch_func(), test_submodule_switch_func(),\n+# or test_submodule_forced_switch() instead.\n test_submodule_switch_common () {\n \tcommand=\"$1\"\n \t######################### Appearing submodule #########################\n@@ -566,8 +566,8 @@ test_submodule_switch_common () {\n #   # Do something here that updates the worktree and index to match target,\n #   # but not any submodule directories.\n # }\n-# test_submodule_switch \"my_func\"\n-test_submodule_switch () {\n+# test_submodule_switch_func \"my_func\"\n+test_submodule_switch_func () {\n \tcommand=\"$1\"\n \ttest_submodule_switch_common \"$command\"\n \n@@ -587,12 +587,16 @@ test_submodule_switch () {\n \t'\n }\n \n+test_submodule_switch () {\n+\ttest_submodule_switch_func \"git $1\"\n+}\n+\n # Same as test_submodule_switch(), except that throwing away local changes in\n # the superproject is allowed.\n test_submodule_forced_switch () {\n \tcommand=\"$1\"\n \tKNOWN_FAILURE_FORCED_SWITCH_TESTS=1\n-\ttest_submodule_switch_common \"$command\"\n+\ttest_submodule_switch_common \"git $command\"\n \n \t# When forced, a file in the superproject does not prevent creating a\n \t# submodule of the same name.\ndiff --git a/t/t1013-read-tree-submodule.sh b/t/t1013-read-tree-submodule.sh\nindex 91a6fafcb4..b6df7444c0 100755\n--- a/t/t1013-read-tree-submodule.sh\n+++ b/t/t1013-read-tree-submodule.sh\n@@ -12,8 +12,8 @@ test_submodule_switch_recursing_with_args \"read-tree -u -m\"\n \n test_submodule_forced_switch_recursing_with_args \"read-tree -u --reset\"\n \n-test_submodule_switch \"git read-tree -u -m\"\n+test_submodule_switch \"read-tree -u -m\"\n \n-test_submodule_forced_switch \"git read-tree -u --reset\"\n+test_submodule_forced_switch \"read-tree -u --reset\"\n \n test_done\ndiff --git a/t/t2013-checkout-submodule.sh b/t/t2013-checkout-submodule.sh\nindex 8f86b5f4b2..b2bdd1fcb4 100755\n--- a/t/t2013-checkout-submodule.sh\n+++ b/t/t2013-checkout-submodule.sh\n@@ -68,8 +68,8 @@ test_submodule_switch_recursing_with_args \"checkout\"\n \n test_submodule_forced_switch_recursing_with_args \"checkout -f\"\n \n-test_submodule_switch \"git checkout\"\n+test_submodule_switch \"checkout\"\n \n-test_submodule_forced_switch \"git checkout -f\"\n+test_submodule_forced_switch \"checkout -f\"\n \n test_done\ndiff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh\nindex a2bba04ba9..788605ccc0 100755\n--- a/t/t3426-rebase-submodule.sh\n+++ b/t/t3426-rebase-submodule.sh\n@@ -20,7 +20,7 @@ git_rebase () {\n \tgit rebase \"$1\"\n }\n \n-test_submodule_switch \"git_rebase\"\n+test_submodule_switch_func \"git_rebase\"\n \n git_rebase_interactive () {\n \tgit status -su >expect &&\n@@ -38,7 +38,7 @@ git_rebase_interactive () {\n \tgit rebase -i \"$1\"\n }\n \n-test_submodule_switch \"git_rebase_interactive\"\n+test_submodule_switch_func \"git_rebase_interactive\"\n \n test_expect_success 'rebase interactive ignores modified submodules' '\n \ttest_when_finished \"rm -rf super sub\" &&\ndiff --git a/t/t3512-cherry-pick-submodule.sh b/t/t3512-cherry-pick-submodule.sh\nindex bd78287841..6ece1d8573 100755\n--- a/t/t3512-cherry-pick-submodule.sh\n+++ b/t/t3512-cherry-pick-submodule.sh\n@@ -7,7 +7,7 @@ test_description='cherry-pick can handle submodules'\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-test_submodule_switch \"git cherry-pick\"\n+test_submodule_switch \"cherry-pick\"\n \n test_expect_success 'unrelated submodule/file conflict is ignored' '\n \ttest_create_repo sub &&\ndiff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh\nindex 5e39fcdb66..95a7f64471 100755\n--- a/t/t3513-revert-submodule.sh\n+++ b/t/t3513-revert-submodule.sh\n@@ -26,6 +26,6 @@ git_revert () {\n }\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-test_submodule_switch \"git_revert\"\n+test_submodule_switch_func \"git_revert\"\n \n test_done\ndiff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh\nindex b93d1d74da..6a7e801ca0 100755\n--- a/t/t3906-stash-submodule.sh\n+++ b/t/t3906-stash-submodule.sh\n@@ -19,7 +19,7 @@ git_stash () {\n KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES=1\n KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1\n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-test_submodule_switch \"git_stash\"\n+test_submodule_switch_func \"git_stash\"\n \n setup_basic () {\n \ttest_when_finished \"rm -rf main sub\" &&\ndiff --git a/t/t4137-apply-submodule.sh b/t/t4137-apply-submodule.sh\nindex a9bd40a6d0..b645e303a0 100755\n--- a/t/t4137-apply-submodule.sh\n+++ b/t/t4137-apply-submodule.sh\n@@ -9,12 +9,12 @@ apply_index () {\n \tgit diff --ignore-submodules=dirty \"..$1\" | git apply --index -\n }\n \n-test_submodule_switch \"apply_index\"\n+test_submodule_switch_func \"apply_index\"\n \n apply_3way () {\n \tgit diff --ignore-submodules=dirty \"..$1\" | git apply --3way -\n }\n \n-test_submodule_switch \"apply_3way\"\n+test_submodule_switch_func \"apply_3way\"\n \n test_done\ndiff --git a/t/t4255-am-submodule.sh b/t/t4255-am-submodule.sh\nindex 0ba8194403..1b179d5f45 100755\n--- a/t/t4255-am-submodule.sh\n+++ b/t/t4255-am-submodule.sh\n@@ -9,14 +9,14 @@ am () {\n \tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am -\n }\n \n-test_submodule_switch \"am\"\n+test_submodule_switch_func \"am\"\n \n am_3way () {\n \tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am --3way -\n }\n \n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-test_submodule_switch \"am_3way\"\n+test_submodule_switch_func \"am_3way\"\n \n test_expect_success 'setup diff.submodule' '\n \ttest_commit one &&\ndiff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh\nindex f916729a12..f911bf631e 100755\n--- a/t/t5572-pull-submodule.sh\n+++ b/t/t5572-pull-submodule.sh\n@@ -17,21 +17,21 @@ git_pull () {\n }\n \n # pulls without conflicts\n-test_submodule_switch \"git_pull\"\n+test_submodule_switch_func \"git_pull\"\n \n git_pull_ff () {\n \treset_branch_to_HEAD \"$1\" &&\n \tgit pull --ff\n }\n \n-test_submodule_switch \"git_pull_ff\"\n+test_submodule_switch_func \"git_pull_ff\"\n \n git_pull_ff_only () {\n \treset_branch_to_HEAD \"$1\" &&\n \tgit pull --ff-only\n }\n \n-test_submodule_switch \"git_pull_ff_only\"\n+test_submodule_switch_func \"git_pull_ff_only\"\n \n git_pull_noff () {\n \treset_branch_to_HEAD \"$1\" &&\n@@ -40,7 +40,7 @@ git_pull_noff () {\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-test_submodule_switch \"git_pull_noff\"\n+test_submodule_switch_func \"git_pull_noff\"\n \n test_expect_success 'pull --recurse-submodule setup' '\n \ttest_create_repo child &&\ndiff --git a/t/t6041-bisect-submodule.sh b/t/t6041-bisect-submodule.sh\nindex 62b8a2e7bb..0e0cdf638d 100755\n--- a/t/t6041-bisect-submodule.sh\n+++ b/t/t6041-bisect-submodule.sh\n@@ -27,6 +27,6 @@ git_bisect () {\n \tgit bisect bad $BAD\n }\n \n-test_submodule_switch \"git_bisect\"\n+test_submodule_switch_func \"git_bisect\"\n \n test_done\ndiff --git a/t/t7112-reset-submodule.sh b/t/t7112-reset-submodule.sh\nindex 67346424a5..19830d9036 100755\n--- a/t/t7112-reset-submodule.sh\n+++ b/t/t7112-reset-submodule.sh\n@@ -12,10 +12,10 @@ test_submodule_switch_recursing_with_args \"reset --keep\"\n \n test_submodule_forced_switch_recursing_with_args \"reset --hard\"\n \n-test_submodule_switch \"git reset --keep\"\n+test_submodule_switch \"reset --keep\"\n \n-test_submodule_switch \"git reset --merge\"\n+test_submodule_switch \"reset --merge\"\n \n-test_submodule_forced_switch \"git reset --hard\"\n+test_submodule_forced_switch \"reset --hard\"\n \n test_done\ndiff --git a/t/t7613-merge-submodule.sh b/t/t7613-merge-submodule.sh\nindex d1e9fcc781..04bf4be7d7 100755\n--- a/t/t7613-merge-submodule.sh\n+++ b/t/t7613-merge-submodule.sh\n@@ -6,14 +6,14 @@ test_description='merge can handle submodules'\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n # merges without conflicts\n-test_submodule_switch \"git merge\"\n+test_submodule_switch \"merge\"\n \n-test_submodule_switch \"git merge --ff\"\n+test_submodule_switch \"merge --ff\"\n \n-test_submodule_switch \"git merge --ff-only\"\n+test_submodule_switch \"merge --ff-only\"\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-test_submodule_switch \"git merge --no-ff\"\n+test_submodule_switch \"merge --no-ff\"\n \n test_done\n-- \n2.26.2.548.gbb00c8a0a9\n\n"},{"id":"396548","messageId":"d5809877af3e20eb9ff459a91d3099846fd32197.1588162842.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1588162842.git.liu.denton@gmail.com","subject":"[PATCH 2/4] lib-submodule-update: consolidate --recurse-submodules","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-04-29T12:22:24Z","receivedAt":"2020-04-29T12:22:58Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"Both test_submodule_switch_recursing_with_args() and\ntest_submodule_forced_switch_recursing_with_args() call the internal\nfunction test_submodule_recursing_with_args_common() with the final\nargument of `--recurse-submodules`. Consolidate this duplication by\nappending the argument in test_submodule_recursing_with_args_common().\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\n t/lib-submodule-update.sh | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex a3732d3f6c..81457b4c31 100644\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -632,7 +632,7 @@ test_submodule_forced_switch () {\n # Internal function; use test_submodule_switch_recursing_with_args() or\n # test_submodule_forced_switch_recursing_with_args() instead.\n test_submodule_recursing_with_args_common () {\n-\tcommand=\"$1\"\n+\tcommand=\"$1 --recurse-submodules\"\n \n \t######################### Appearing submodule #########################\n \t# Switching to a commit letting a submodule appear checks it out ...\n@@ -840,7 +840,7 @@ test_submodule_recursing_with_args_common () {\n # test_submodule_switch_recursing_with_args \"$GIT_COMMAND\"\n test_submodule_switch_recursing_with_args () {\n \tcmd_args=\"$1\"\n-\tcommand=\"git $cmd_args --recurse-submodules\"\n+\tcommand=\"git $cmd_args\"\n \ttest_submodule_recursing_with_args_common \"$command\"\n \n \tRESULTDS=success\n@@ -957,7 +957,7 @@ test_submodule_switch_recursing_with_args () {\n # away local changes in the superproject is allowed.\n test_submodule_forced_switch_recursing_with_args () {\n \tcmd_args=\"$1\"\n-\tcommand=\"git $cmd_args --recurse-submodules\"\n+\tcommand=\"git $cmd_args\"\n \ttest_submodule_recursing_with_args_common \"$command\"\n \n \tRESULT=success\n-- \n2.26.2.548.gbb00c8a0a9\n\n"},{"id":"396550","messageId":"22eacd20a8213c3281974a6c103fd2d00c95efaa.1588162842.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1588162842.git.liu.denton@gmail.com","subject":"[PATCH 4/4] lib-submodule-update: pass OVERWRITING_FAIL","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-04-29T12:22:26Z","receivedAt":"2020-04-29T12:23:01Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"We are using `test_must_fail $command`. However, $command is not\nnecessarily a git command; it could be a test helper function.\n\nIn an effort to stop using test_must_fail with non-git commands, instead\nof invoking `test_must_fail $command`, run\n`OVERWRITING_FAIL=test_must_fail $command` instead. Increase the\ngranularity of the test helper functions by specifically choosing the\nindividual git invocation which is designed to fail.\n\nWhile we're at it, some helper functions have git commands piping into\nanother git command. Break these pipes up into two separate invocations\nwith a file buffer so that the return code of the first command is not\nlost.\n\nThis patch can be better viewed with `--ignore-all-space`.\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\n t/lib-submodule-update.sh   | 25 +++++++++++++++++--------\n t/t3426-rebase-submodule.sh |  4 ++--\n t/t3513-revert-submodule.sh | 20 ++++++++++++--------\n t/t3906-stash-submodule.sh  | 15 +++++++++------\n t/t4137-apply-submodule.sh  |  6 ++++--\n t/t4255-am-submodule.sh     |  6 ++++--\n t/t5572-pull-submodule.sh   |  8 ++++----\n t/t6041-bisect-submodule.sh | 33 ++++++++++++++++++---------------\n 8 files changed, 70 insertions(+), 47 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex cd80d77707..c8d1b6f528 100644\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -304,12 +304,15 @@ test_submodule_content () {\n # a removed submodule.\n #\n # Removing a submodule containing a .git directory must fail even when forced\n-# to protect the history!\n+# to protect the history! If we are testing this case,\n+# OVERWRITING_FAIL=test_must_fail, otherwise OVERWRITING_FAIL will be the empty\n+# string.\n #\n \n # Internal function; use test_submodule_switch_func(), test_submodule_switch_func(),\n # or test_submodule_forced_switch() instead.\n test_submodule_switch_common () {\n+\tOVERWRITING_FAIL=\n \tcommand=\"$1\"\n \t######################### Appearing submodule #########################\n \t# Switching to a commit letting a submodule appear creates empty dir ...\n@@ -443,7 +446,7 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\tOVERWRITING_FAIL=test_must_fail $command replace_sub1_with_directory &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -456,7 +459,7 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\tOVERWRITING_FAIL=test_must_fail $command replace_sub1_with_directory &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -470,7 +473,7 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\tOVERWRITING_FAIL=test_must_fail $command replace_sub1_with_file &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -484,7 +487,7 @@ test_submodule_switch_common () {\n \t\t\tcd submodule_update &&\n \t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n \t\t\treplace_gitfile_with_git_dir sub1 &&\n-\t\t\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\tOVERWRITING_FAIL=test_must_fail $command replace_sub1_with_file &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -559,6 +562,11 @@ test_submodule_switch_common () {\n # conditions, set the appropriate KNOWN_FAILURE_* variable used in the tests\n # below to 1.\n #\n+# Removing a submodule containing a .git directory must fail even when forced\n+# to protect the history! If we are testing this case,\n+# OVERWRITING_FAIL=test_must_fail, otherwise OVERWRITING_FAIL will be the empty\n+# string.\n+#\n # Use as follows:\n #\n # my_func () {\n@@ -568,6 +576,7 @@ test_submodule_switch_common () {\n # }\n # test_submodule_switch_func \"my_func\"\n test_submodule_switch_func () {\n+\tOVERWRITING_FAIL=\n \tcommand=\"$1\"\n \ttest_submodule_switch_common \"$command\"\n \n@@ -580,7 +589,7 @@ test_submodule_switch_func () {\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\tOVERWRITING_FAIL=test_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@@ -588,7 +597,7 @@ test_submodule_switch_func () {\n }\n \n test_submodule_switch () {\n-\ttest_submodule_switch_func \"git $1\"\n+\ttest_submodule_switch_func \"eval \\$OVERWRITING_FAIL git $1\"\n }\n \n # Same as test_submodule_switch(), except that throwing away local changes in\n@@ -596,7 +605,7 @@ test_submodule_switch () {\n test_submodule_forced_switch () {\n \tcommand=\"$1\"\n \tKNOWN_FAILURE_FORCED_SWITCH_TESTS=1\n-\ttest_submodule_switch_common \"git $command\"\n+\ttest_submodule_switch_common \"eval \\$OVERWRITING_FAIL git $command\"\n \n \t# When forced, a file in the superproject does not prevent creating a\n \t# submodule of the same name.\ndiff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh\nindex 788605ccc0..c6a7f584ed 100755\n--- a/t/t3426-rebase-submodule.sh\n+++ b/t/t3426-rebase-submodule.sh\n@@ -17,7 +17,7 @@ git_rebase () {\n \tgit status -su >actual &&\n \tls -1pR * >>actual &&\n \ttest_cmp expect actual &&\n-\tgit rebase \"$1\"\n+\t$OVERWRITING_FAIL git rebase \"$1\"\n }\n \n test_submodule_switch_func \"git_rebase\"\n@@ -35,7 +35,7 @@ git_rebase_interactive () {\n \ttest_cmp expect actual &&\n \tset_fake_editor &&\n \techo \"fake-editor.sh\" >.git/info/exclude &&\n-\tgit rebase -i \"$1\"\n+\t$OVERWRITING_FAIL git rebase -i \"$1\"\n }\n \n test_submodule_switch_func \"git_rebase_interactive\"\ndiff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh\nindex 95a7f64471..6c899db7e1 100755\n--- a/t/t3513-revert-submodule.sh\n+++ b/t/t3513-revert-submodule.sh\n@@ -15,14 +15,18 @@ git_revert () {\n \tgit status -su >expect &&\n \tls -1pR * >>expect &&\n \ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n-\tgit checkout \"$1\" &&\n-\tgit revert HEAD &&\n-\trm -rf * &&\n-\ttar xf \"$TRASH_DIRECTORY/tmp.tar\" &&\n-\tgit status -su >actual &&\n-\tls -1pR * >>actual &&\n-\ttest_cmp expect actual &&\n-\tgit revert HEAD\n+\t$OVERWRITING_FAIL git checkout \"$1\" &&\n+\tif test -z \"$OVERWRITING_FAIL\"\n+\tthen\n+\t\tgit checkout \"$1\" &&\n+\t\tgit revert HEAD &&\n+\t\trm -rf * &&\n+\t\ttar xf \"$TRASH_DIRECTORY/tmp.tar\" &&\n+\t\tgit status -su >actual &&\n+\t\tls -1pR * >>actual &&\n+\t\ttest_cmp expect actual &&\n+\t\tgit revert HEAD\n+\tfi\n }\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\ndiff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh\nindex 6a7e801ca0..860940072d 100755\n--- a/t/t3906-stash-submodule.sh\n+++ b/t/t3906-stash-submodule.sh\n@@ -8,12 +8,15 @@ test_description='stash can handle submodules'\n git_stash () {\n \tgit status -su >expect &&\n \tls -1pR * >>expect &&\n-\tgit read-tree -u -m \"$1\" &&\n-\tgit stash &&\n-\tgit status -su >actual &&\n-\tls -1pR * >>actual &&\n-\ttest_cmp expect actual &&\n-\tgit stash apply\n+\t$OVERWRITING_FAIL git read-tree -u -m \"$1\" &&\n+\tif test -z \"$OVERWRITING_FAIL\"\n+\tthen\n+\t\tgit stash &&\n+\t\tgit status -su >actual &&\n+\t\tls -1pR * >>actual &&\n+\t\ttest_cmp expect actual &&\n+\t\tgit stash apply\n+\tfi\n }\n \n KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES=1\ndiff --git a/t/t4137-apply-submodule.sh b/t/t4137-apply-submodule.sh\nindex b645e303a0..dd08d9e1a4 100755\n--- a/t/t4137-apply-submodule.sh\n+++ b/t/t4137-apply-submodule.sh\n@@ -6,13 +6,15 @@ test_description='git apply handling submodules'\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n apply_index () {\n-\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --index -\n+\tgit diff --ignore-submodules=dirty \"..$1\" >diff &&\n+\t$OVERWRITING_FAIL git apply --index - <diff\n }\n \n test_submodule_switch_func \"apply_index\"\n \n apply_3way () {\n-\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --3way -\n+\tgit diff --ignore-submodules=dirty \"..$1\" >diff &&\n+\t$OVERWRITING_FAIL git apply --3way - <diff\n }\n \n test_submodule_switch_func \"apply_3way\"\ndiff --git a/t/t4255-am-submodule.sh b/t/t4255-am-submodule.sh\nindex 1b179d5f45..b0fe78a956 100755\n--- a/t/t4255-am-submodule.sh\n+++ b/t/t4255-am-submodule.sh\n@@ -6,13 +6,15 @@ test_description='git am handling submodules'\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n am () {\n-\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am -\n+\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" >patch &&\n+\t$OVERWRITING_FAIL git am - <patch\n }\n \n test_submodule_switch_func \"am\"\n \n am_3way () {\n-\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am --3way -\n+\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" >patch &&\n+\t$OVERWRITING_FAIL git am --3way - <patch\n }\n \n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\ndiff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh\nindex f911bf631e..4dd9913b6b 100755\n--- a/t/t5572-pull-submodule.sh\n+++ b/t/t5572-pull-submodule.sh\n@@ -13,7 +13,7 @@ reset_branch_to_HEAD () {\n \n git_pull () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull\n+\t$OVERWRITING_FAIL git pull\n }\n \n # pulls without conflicts\n@@ -21,21 +21,21 @@ test_submodule_switch_func \"git_pull\"\n \n git_pull_ff () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --ff\n+\t$OVERWRITING_FAIL git pull --ff\n }\n \n test_submodule_switch_func \"git_pull_ff\"\n \n git_pull_ff_only () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --ff-only\n+\t$OVERWRITING_FAIL git pull --ff-only\n }\n \n test_submodule_switch_func \"git_pull_ff_only\"\n \n git_pull_noff () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --no-ff\n+\t$OVERWRITING_FAIL git pull --no-ff\n }\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\ndiff --git a/t/t6041-bisect-submodule.sh b/t/t6041-bisect-submodule.sh\nindex 0e0cdf638d..714d393899 100755\n--- a/t/t6041-bisect-submodule.sh\n+++ b/t/t6041-bisect-submodule.sh\n@@ -10,21 +10,24 @@ git_bisect () {\n \tls -1pR * >>expect &&\n \ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n \tGOOD=$(git rev-parse --verify HEAD) &&\n-\tgit checkout \"$1\" &&\n-\techo \"foo\" >bar &&\n-\tgit add bar &&\n-\tgit commit -m \"bisect bad\" &&\n-\tBAD=$(git rev-parse --verify HEAD) &&\n-\tgit reset --hard HEAD^^ &&\n-\tgit submodule update &&\n-\tgit bisect start &&\n-\tgit bisect good $GOOD &&\n-\trm -rf * &&\n-\ttar xf \"$TRASH_DIRECTORY/tmp.tar\" &&\n-\tgit status -su >actual &&\n-\tls -1pR * >>actual &&\n-\ttest_cmp expect actual &&\n-\tgit bisect bad $BAD\n+\t$OVERWRITING_FAIL git checkout \"$1\" &&\n+\tif test -z \"$OVERWRITING_FAIL\"\n+\tthen\n+\t\techo \"foo\" >bar &&\n+\t\tgit add bar &&\n+\t\tgit commit -m \"bisect bad\" &&\n+\t\tBAD=$(git rev-parse --verify HEAD) &&\n+\t\tgit reset --hard HEAD^^ &&\n+\t\tgit submodule update &&\n+\t\tgit bisect start &&\n+\t\tgit bisect good $GOOD &&\n+\t\trm -rf * &&\n+\t\ttar xf \"$TRASH_DIRECTORY/tmp.tar\" &&\n+\t\tgit status -su >actual &&\n+\t\tls -1pR * >>actual &&\n+\t\ttest_cmp expect actual &&\n+\t\tgit bisect bad $BAD\n+\tfi\n }\n \n test_submodule_switch_func \"git_bisect\"\n-- \n2.26.2.548.gbb00c8a0a9\n\n"},{"id":"396585","messageId":"xmqqtv12w4i2.fsf@gitster.c.googlers.com","threadId":"53350","inReplyTo":"d5809877af3e20eb9ff459a91d3099846fd32197.1588162842.git.liu.denton@gmail.com","subject":"Re: [PATCH 2/4] lib-submodule-update: consolidate --recurse-submodules","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-04-29T18:06:45Z","receivedAt":"2020-04-29T18:06:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Denton Liu <liu.denton@gmail.com> writes:\n\n> Both test_submodule_switch_recursing_with_args() and\n> test_submodule_forced_switch_recursing_with_args() call the internal\n> function test_submodule_recursing_with_args_common() with the final\n> argument of `--recurse-submodules`. Consolidate this duplication by\n> appending the argument in test_submodule_recursing_with_args_common().\n>\n\nOK, I just made sure that these two are the only callers and they\nboth pass the \"--recurse-submodules\", so the patch looks quite\nsensible.\n\nThanks.\n\n> Signed-off-by: Denton Liu <liu.denton@gmail.com>\n> ---\n>  t/lib-submodule-update.sh | 6 +++---\n>  1 file changed, 3 insertions(+), 3 deletions(-)\n>\n> diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\n> index a3732d3f6c..81457b4c31 100644\n> --- a/t/lib-submodule-update.sh\n> +++ b/t/lib-submodule-update.sh\n> @@ -632,7 +632,7 @@ test_submodule_forced_switch () {\n>  # Internal function; use test_submodule_switch_recursing_with_args() or\n>  # test_submodule_forced_switch_recursing_with_args() instead.\n>  test_submodule_recursing_with_args_common () {\n> -\tcommand=\"$1\"\n> +\tcommand=\"$1 --recurse-submodules\"\n>  \n>  \t######################### Appearing submodule #########################\n>  \t# Switching to a commit letting a submodule appear checks it out ...\n> @@ -840,7 +840,7 @@ test_submodule_recursing_with_args_common () {\n>  # test_submodule_switch_recursing_with_args \"$GIT_COMMAND\"\n>  test_submodule_switch_recursing_with_args () {\n>  \tcmd_args=\"$1\"\n> -\tcommand=\"git $cmd_args --recurse-submodules\"\n> +\tcommand=\"git $cmd_args\"\n>  \ttest_submodule_recursing_with_args_common \"$command\"\n>  \n>  \tRESULTDS=success\n> @@ -957,7 +957,7 @@ test_submodule_switch_recursing_with_args () {\n>  # away local changes in the superproject is allowed.\n>  test_submodule_forced_switch_recursing_with_args () {\n>  \tcmd_args=\"$1\"\n> -\tcommand=\"git $cmd_args --recurse-submodules\"\n> +\tcommand=\"git $cmd_args\"\n>  \ttest_submodule_recursing_with_args_common \"$command\"\n>  \n>  \tRESULT=success\n"},{"id":"396590","messageId":"xmqqpnbqw0vz.fsf@gitster.c.googlers.com","threadId":"53350","inReplyTo":"22eacd20a8213c3281974a6c103fd2d00c95efaa.1588162842.git.liu.denton@gmail.com","subject":"Re: [PATCH 4/4] lib-submodule-update: pass OVERWRITING_FAIL","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-04-29T19:24:48Z","receivedAt":"2020-04-29T19:24:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Denton Liu <liu.denton@gmail.com> writes:\n\n> We are using `test_must_fail $command`. However, $command is not\n> necessarily a git command; it could be a test helper function.\n>\n> In an effort to stop using test_must_fail with non-git commands, instead\n> of invoking `test_must_fail $command`, run\n> `OVERWRITING_FAIL=test_must_fail $command` instead. Increase the\n> granularity of the test helper functions by specifically choosing the\n> individual git invocation which is designed to fail.\n\nSorry, but I do not know why this is a good idea.\n\n>  test_submodule_switch_common () {\n> +\tOVERWRITING_FAIL=\n>  \tcommand=\"$1\"\n>  \t######################### Appearing submodule #########################\n>  \t# Switching to a commit letting a submodule appear creates empty dir ...\n> @@ -443,7 +446,7 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_directory &&\n> +\t\t\tOVERWRITING_FAIL=test_must_fail $command replace_sub1_with_directory &&\n\nHere, $command may or may not be a git command and more importantly,\nit could be a shell function, right?  Then we need to take it into\naccount that \n\n\tVAR=VAL shell_function args...\n\nwill not work, no?\n\nSome shells do not make this a single-shot environment variable\nassignment that will not persist once the single function invocation\nreturns.\n\n"},{"id":"396593","messageId":"20200429195035.GB3920@syl.local","threadId":"53350","inReplyTo":"cover.1588162842.git.liu.denton@gmail.com","subject":"Re: [PATCH 0/4] t: replace incorrect test_must_fail usage (part 5)","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2020-04-29T19:50:35Z","receivedAt":"2020-04-29T19:50:41Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Wed, Apr 29, 2020 at 08:22:22AM -0400, Denton Liu wrote:\n> The overall scope of these patches is to replace inappropriate uses of\n> test_must_fail. IOW, we should only allow test_must_fail to run on `git`\n> and `test-tool`. Ultimately, we will conclude by making test_must_fail\n> error out on non-git commands. An advance view of the final series can\n> be found here[1].\n\nThis comment has nothing to do with your series, but I am curious if you\nare planning on touching 'test_might_fail' at all. These can be useful\nfor non-Git commands, too, such as 'test_might_fail umask 022' on\nsystems that may or may not do something sensible with umask.\n\nSorry for injecting myself into this thread on an otherwise unrelated\ntopic.\n\nThanks,\nTaylor\n"},{"id":"396609","messageId":"90edb162-e035-bdb7-a2d2-ffc6bd075977@kdbg.org","threadId":"53350","inReplyTo":"20200429195035.GB3920@syl.local","subject":"Re: [PATCH 0/4] t: replace incorrect test_must_fail usage (part 5)","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2020-04-29T21:30:19Z","receivedAt":"2020-04-29T21:30:23Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 29.04.20 um 21:50 schrieb Taylor Blau:\n> This comment has nothing to do with your series, but I am curious if you\n> are planning on touching 'test_might_fail' at all. These can be useful\n> for non-Git commands, too, such as 'test_might_fail umask 022' on\n> systems that may or may not do something sensible with umask.\n\nWhen it's not a git command that might fail, the idiom is\n\n\t... &&\n\t{ umask 022 || :; } &&\n\t...\n\n-- Hannes\n"},{"id":"396610","messageId":"xmqqblnaufyt.fsf_-_@gitster.c.googlers.com","threadId":"53350","inReplyTo":"90edb162-e035-bdb7-a2d2-ffc6bd075977@kdbg.org","subject":"Re* [PATCH 0/4] t: replace incorrect test_must_fail usage (part 5)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-04-29T21:42:02Z","receivedAt":"2020-04-29T21:42:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Sixt <j6t@kdbg.org> writes:\n\n> Am 29.04.20 um 21:50 schrieb Taylor Blau:\n>> This comment has nothing to do with your series, but I am curious if you\n>> are planning on touching 'test_might_fail' at all. These can be useful\n>> for non-Git commands, too, such as 'test_might_fail umask 022' on\n>> systems that may or may not do something sensible with umask.\n>\n> When it's not a git command that might fail, the idiom is\n>\n> \t... &&\n> \t{ umask 022 || :; } &&\n> \t...\n>\n> -- Hannes\n\nI hoped to find this documented in t/README, but ended up writing\nthis.  Overkill?  I dunno.\n\n-- >8 --\nSubject: [PATCH] t/README: document when not to use test_might_fail\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/README | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/t/README b/t/README\nindex 13747f1344..870950c7d1 100644\n--- a/t/README\n+++ b/t/README\n@@ -875,7 +875,9 @@ library for your script to use.\n  - test_might_fail [<options>] <git-command>\n \n    Similar to test_must_fail, but tolerate success, too.  Use this\n-   instead of \"<git-command> || :\" to catch failures due to segv.\n+   instead of \"<git-command> || :\" to catch failures due to segv,\n+   but do use \"{ <non-git-command> || :; }\" to ignore a failure from\n+   a command that is not git.\n \n    Accepts the same options as test_must_fail.\n \n"},{"id":"396611","messageId":"20200429214906.GA12075@syl.local","threadId":"53350","inReplyTo":"xmqqblnaufyt.fsf_-_@gitster.c.googlers.com","subject":"Re: Re* [PATCH 0/4] t: replace incorrect test_must_fail usage (part 5)","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2020-04-29T21:49:06Z","receivedAt":"2020-04-29T21:49:12Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Wed, Apr 29, 2020 at 02:42:02PM -0700, Junio C Hamano wrote:\n> Johannes Sixt <j6t@kdbg.org> writes:\n>\n> > Am 29.04.20 um 21:50 schrieb Taylor Blau:\n> >> This comment has nothing to do with your series, but I am curious if you\n> >> are planning on touching 'test_might_fail' at all. These can be useful\n> >> for non-Git commands, too, such as 'test_might_fail umask 022' on\n> >> systems that may or may not do something sensible with umask.\n> >\n> > When it's not a git command that might fail, the idiom is\n> >\n> > \t... &&\n> > \t{ umask 022 || :; } &&\n> > \t...\n> >\n> > -- Hannes\n>\n> I hoped to find this documented in t/README, but ended up writing\n> this.  Overkill?  I dunno.\n>\n> -- >8 --\n> Subject: [PATCH] t/README: document when not to use test_might_fail\n>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>  t/README | 4 +++-\n>  1 file changed, 3 insertions(+), 1 deletion(-)\n>\n> diff --git a/t/README b/t/README\n> index 13747f1344..870950c7d1 100644\n> --- a/t/README\n> +++ b/t/README\n> @@ -875,7 +875,9 @@ library for your script to use.\n>   - test_might_fail [<options>] <git-command>\n>\n>     Similar to test_must_fail, but tolerate success, too.  Use this\n> -   instead of \"<git-command> || :\" to catch failures due to segv.\n> +   instead of \"<git-command> || :\" to catch failures due to segv,\n> +   but do use \"{ <non-git-command> || :; }\" to ignore a failure from\n> +   a command that is not git.\n\nHmm. I say this as somebody who just re-rolled a series to add two\n'test_might_fail umask 022' lines, so am a little disappointed to learn\nthat this is not considered to be idiomatic.\n\nTo me this seems a little overkill, but it may not be on environments\nwhere an extra subshell incurred by 'test_might_fail' might be overly\nexpensive.\n\nJunio: do you want another reroll of that series? :/\n\n>     Accepts the same options as test_must_fail.\n\nThanks,\nTaylor\n"},{"id":"396613","messageId":"CAPig+cT5DH2KW4nnQxUMaZzLR0JSLovGbpGC=3vYOWY2QWyKsw@mail.gmail.com","threadId":"53350","inReplyTo":"xmqqblnaufyt.fsf_-_@gitster.c.googlers.com","subject":"Re: Re* [PATCH 0/4] t: replace incorrect test_must_fail usage (part 5)","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2020-04-29T22:00:23Z","receivedAt":"2020-04-29T22:00:39Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Apr 29, 2020 at 5:42 PM Junio C Hamano <gitster@pobox.com> wrote:\n> Subject: [PATCH] t/README: document when not to use test_might_fail\n>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n> diff --git a/t/README b/t/README\n> @@ -875,7 +875,9 @@ library for your script to use.\n>   - test_might_fail [<options>] <git-command>\n>\n>     Similar to test_must_fail, but tolerate success, too.  Use this\n> -   instead of \"<git-command> || :\" to catch failures due to segv.\n> +   instead of \"<git-command> || :\" to catch failures due to segv,\n> +   but do use \"{ <non-git-command> || :; }\" to ignore a failure from\n> +   a command that is not git.\n\nThis seems like a good addition and perhaps may help reduce reviewer\nburden (not that this comes up very often, but I've recommended it\nhere and there when reviewing patches). Here's a possible alternate\nwording:\n\n    Similar to test_must_fail, but tolerate success, too. Use this\n    instead of \"<git-command> || :\" to catch failures due to segv.\n    To ignore failure of non-git commands, however, use\n    \"{ <non-git-command> || :; }\".\n"},{"id":"396615","messageId":"xmqq368muetb.fsf@gitster.c.googlers.com","threadId":"53350","inReplyTo":"CAPig+cT5DH2KW4nnQxUMaZzLR0JSLovGbpGC=3vYOWY2QWyKsw@mail.gmail.com","subject":"Re: Re* [PATCH 0/4] t: replace incorrect test_must_fail usage (part 5)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-04-29T22:06:56Z","receivedAt":"2020-04-29T22:07:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Sunshine <sunshine@sunshineco.com> writes:\n\n> This seems like a good addition and perhaps may help reduce reviewer\n> burden (not that this comes up very often, but I've recommended it\n> here and there when reviewing patches). Here's a possible alternate\n> wording:\n>\n>     Similar to test_must_fail, but tolerate success, too. Use this\n>     instead of \"<git-command> || :\" to catch failures due to segv.\n>     To ignore failure of non-git commands, however, use\n>     \"{ <non-git-command> || :; }\".\n\nThat is certainly more succinct.  \"git grep -e '|| :' t/\" gives some\nhits that are candidates to convert to test_might_fail, by the way.\n\n\n"},{"id":"396616","messageId":"xmqqy2qet02d.fsf@gitster.c.googlers.com","threadId":"53350","inReplyTo":"20200429214906.GA12075@syl.local","subject":"Re: Re* [PATCH 0/4] t: replace incorrect test_must_fail usage (part 5)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-04-29T22:10:50Z","receivedAt":"2020-04-29T22:10:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Taylor Blau <me@ttaylorr.com> writes:\n\n> To me this seems a little overkill, but it may not be on environments\n> where an extra subshell incurred by 'test_might_fail' might be overly\n> expensive.\n\nIt comes from the same principle as \"we are not in the business of\ncatching segv from system tools---don't use test_must_fail on\nnon-git commands\".  Adopting the convention happened quite some time\nago and that was why I checked if we failed to document it.\n\nWhat I wondered was if it is overkill to document the convention; if\nthe convention was overkill is not a question at this point.\n\n"},{"id":"396617","messageId":"20200429221611.GA12776@syl.local","threadId":"53350","inReplyTo":"xmqqy2qet02d.fsf@gitster.c.googlers.com","subject":"Re: Re* [PATCH 0/4] t: replace incorrect test_must_fail usage (part 5)","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2020-04-29T22:16:11Z","receivedAt":"2020-04-29T22:16:17Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Wed, Apr 29, 2020 at 03:10:50PM -0700, Junio C Hamano wrote:\n> Taylor Blau <me@ttaylorr.com> writes:\n>\n> > To me this seems a little overkill, but it may not be on environments\n> > where an extra subshell incurred by 'test_might_fail' might be overly\n> > expensive.\n>\n> It comes from the same principle as \"we are not in the business of\n> catching segv from system tools---don't use test_must_fail on\n> non-git commands\".  Adopting the convention happened quite some time\n> ago and that was why I checked if we failed to document it.\n>\n> What I wondered was if it is overkill to document the convention; if\n> the convention was overkill is not a question at this point.\n\nAh, fair enough. Thanks for a patient explanation.\n\nThanks,\nTaylor\n"},{"id":"396618","messageId":"xmqqsggludg6.fsf@gitster.c.googlers.com","threadId":"53350","inReplyTo":"20200429214906.GA12075@syl.local","subject":"Re: Re* [PATCH 0/4] t: replace incorrect test_must_fail usage (part 5)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-04-29T22:36:25Z","receivedAt":"2020-04-29T22:36:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Taylor Blau <me@ttaylorr.com> writes:\n\n> Hmm. I say this as somebody who just re-rolled a series to add two\n> 'test_might_fail umask 022' lines, so am a little disappointed to learn\n> that this is not considered to be idiomatic.\n> ...\n> Junio: do you want another reroll of that series? :/\n\nThe one I saw and remember was two new umask calls protected in POSIXPERM\nprerequisite but without test-might-fail involved.\n\nPerhaps there is nothing to reroll?  Or perhaps I am not checking my\nmailbox often enough?\n"},{"id":"396625","messageId":"20200429224121.GA18172@syl.local","threadId":"53350","inReplyTo":"xmqqsggludg6.fsf@gitster.c.googlers.com","subject":"Re: Re* [PATCH 0/4] t: replace incorrect test_must_fail usage (part 5)","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2020-04-29T22:41:21Z","receivedAt":"2020-04-29T22:41:25Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Wed, Apr 29, 2020 at 03:36:25PM -0700, Junio C Hamano wrote:\n> Taylor Blau <me@ttaylorr.com> writes:\n>\n> > Hmm. I say this as somebody who just re-rolled a series to add two\n> > 'test_might_fail umask 022' lines, so am a little disappointed to learn\n> > that this is not considered to be idiomatic.\n> > ...\n> > Junio: do you want another reroll of that series? :/\n>\n> The one I saw and remember was two new umask calls protected in POSIXPERM\n> prerequisite but without test-might-fail involved.\n>\n> Perhaps there is nothing to reroll?  Or perhaps I am not checking my\n> mailbox often enough?\n\nYou are checking your mailbox often enough, but unfortunately my memory\nisn't as good as I thought ;). You're right: those calls are in\nPOSIXPERM-only tests, and don't have a 'test_might_fail' in front of\nthem as such.\n\nThat was easy ;).\n\nThanks,\nTaylor\n"},{"id":"396640","messageId":"20200430011056.GA3036@generichostname","threadId":"53350","inReplyTo":"xmqqpnbqw0vz.fsf@gitster.c.googlers.com","subject":"Re: [PATCH 4/4] lib-submodule-update: pass OVERWRITING_FAIL","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-04-30T01:10:56Z","receivedAt":"2020-04-30T01:11:03Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"Hi Junio,\n\nOn Wed, Apr 29, 2020 at 12:24:48PM -0700, Junio C Hamano wrote:\n> Denton Liu <liu.denton@gmail.com> writes:\n> \n> > We are using `test_must_fail $command`. However, $command is not\n> > necessarily a git command; it could be a test helper function.\n> >\n> > In an effort to stop using test_must_fail with non-git commands, instead\n> > of invoking `test_must_fail $command`, run\n> > `OVERWRITING_FAIL=test_must_fail $command` instead. Increase the\n> > granularity of the test helper functions by specifically choosing the\n> > individual git invocation which is designed to fail.\n> \n> Sorry, but I do not know why this is a good idea.\n\nThis is useful because currently, when we run a test helper function, we\njust mark the whole thing as `test_must_fail`. However, it's possible\nthat the helper function might fail earlier or later than expected due\nto some side effect. If this happens, then the test case will still\nbe reported as passing but I think that it should be marked as failing\ninstead since it didn't actually display the desired behaviour.\n\n> >  test_submodule_switch_common () {\n> > +\tOVERWRITING_FAIL=\n> >  \tcommand=\"$1\"\n> >  \t######################### Appearing submodule #########################\n> >  \t# Switching to a commit letting a submodule appear creates empty dir ...\n> > @@ -443,7 +446,7 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_directory &&\n> > +\t\t\tOVERWRITING_FAIL=test_must_fail $command replace_sub1_with_directory &&\n> \n> Here, $command may or may not be a git command and more importantly,\n> it could be a shell function, right?  Then we need to take it into\n> account that \n> \n> \tVAR=VAL shell_function args...\n> \n> will not work, no?\n> \n> Some shells do not make this a single-shot environment variable\n> assignment that will not persist once the single function invocation\n> returns.\n\nI looked through POSIX specification and it says under 2.9.1 Simple\nComamnds,\n\n\tIf no command name results, variable assignments shall affect\n\tthe current execution environment. Otherwise, the variable\n\tassignments shall be exported for the execution environment of\n\tthe command and shall not affect the current execution\n\tenvironment (except for special built-ins).\n\nwhich makes me suspect that these shells are not POSIX-compliant. What\nare some examples of shells that behave this way?\n\nThat being said, I know that we live in the real world and POSIX\nstandards don't justify breaking test cases. I'll reroll this to add an\n`OVERWRITING_FAIL=` after the command to ensure that the variable is\ncleared.\n\nThanks,\n\nDenton\n"},{"id":"396649","messageId":"xmqqd07ptzbw.fsf@gitster.c.googlers.com","threadId":"53350","inReplyTo":"20200430011056.GA3036@generichostname","subject":"Re: [PATCH 4/4] lib-submodule-update: pass OVERWRITING_FAIL","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-04-30T03:41:23Z","receivedAt":"2020-04-30T03:41:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Denton Liu <liu.denton@gmail.com> writes:\n\n>> Here, $command may or may not be a git command and more importantly,\n>> it could be a shell function, right?  Then we need to take it into\n>> account that \n>> \n>> \tVAR=VAL shell_function args...\n>> \n>> will not work, no?\n>> \n>> Some shells do not make this a single-shot environment variable\n>> assignment that will not persist once the single function invocation\n>> returns.\n>\n> ...\n> which makes me suspect that these shells are not POSIX-compliant. What\n> are some examples of shells that behave this way?\n\nI think the most relevant thread is the one that contains this\nmessage:\n\n  https://public-inbox.org/git/7vljfzz0yd.fsf@alter.siamese.dyndns.org/\n\nFWIW, shells that do not retain the assignment after a function\nreturns are not POSIX compliant.\n\n"},{"id":"396653","messageId":"20200430092220.GA25331@generichostname","threadId":"53350","inReplyTo":"xmqqd07ptzbw.fsf@gitster.c.googlers.com","subject":"Re: [PATCH 4/4] lib-submodule-update: pass OVERWRITING_FAIL","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-04-30T09:22:20Z","receivedAt":"2020-04-30T09:22:27Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"On Wed, Apr 29, 2020 at 08:41:23PM -0700, Junio C Hamano wrote:\n> Denton Liu <liu.denton@gmail.com> writes:\n> \n> >> Here, $command may or may not be a git command and more importantly,\n> >> it could be a shell function, right?  Then we need to take it into\n> >> account that \n> >> \n> >> \tVAR=VAL shell_function args...\n> >> \n> >> will not work, no?\n> >> \n> >> Some shells do not make this a single-shot environment variable\n> >> assignment that will not persist once the single function invocation\n> >> returns.\n> >\n> > ...\n> > which makes me suspect that these shells are not POSIX-compliant. What\n> > are some examples of shells that behave this way?\n> \n> I think the most relevant thread is the one that contains this\n> message:\n> \n>   https://public-inbox.org/git/7vljfzz0yd.fsf@alter.siamese.dyndns.org/\n> \n> FWIW, shells that do not retain the assignment after a function\n> returns are not POSIX compliant.\n\nHmm, interesting. Running an experiment:\n\n\t$ cat test.sh\n\tf () {\n\t\techo $var\n\t}\n\n\tvar=test f\n\techo $var\n\t$ bash test.sh\n\ttest\n\n\t$ bash --posix test.sh\n\ttest\n\ttest\n\t$ dash test.sh\n\ttest\n\n\nSo it seems like there's a bug in dash. Guess it's time to file a bug\nreport...\n"},{"id":"396657","messageId":"f0d8dcf7dc52fe5ad2f1e173cd744bfdeb55eb45.1588242122.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"22eacd20a8213c3281974a6c103fd2d00c95efaa.1588162842.git.liu.denton@gmail.com","subject":"[PATCH v1.1] lib-submodule-update: pass OVERWRITING_FAIL","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-04-30T10:25:05Z","receivedAt":"2020-04-30T10:25:30Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"We are using `test_must_fail $command`. However, $command is not\nnecessarily a git command; it could be a test helper function.\n\nIn an effort to stop using test_must_fail with non-git commands, instead\nof invoking `test_must_fail $command`, run\n`OVERWRITING_FAIL=test_must_fail $command` instead. Increase the\ngranularity of the test helper functions by specifically choosing the\nindividual git invocation which is designed to fail.\n\nThis is useful because currently, when we run a test helper function, we\njust mark the whole thing as `test_must_fail`. However, it's possible\nthat the helper function might fail earlier or later than expected due\nto an introduced bug. If this happens, then the test case will still\nreport as passing but it should really be marked as failing since it\ndidn't actually display the intended behaviour.\n\nWhile we're at it, some helper functions have git commands piping into\nanother git command. Break these pipes up into two separate invocations\nwith a file buffer so that the return code of the first command is not\nlost.\n\nThis patch can be better viewed with `--ignore-all-space`.\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\nRange-diff against v1:\n1:  22eacd20a8 ! 1:  f0d8dcf7dc lib-submodule-update: pass OVERWRITING_FAIL\n    @@ Commit message\n         granularity of the test helper functions by specifically choosing the\n         individual git invocation which is designed to fail.\n     \n    +    This is useful because currently, when we run a test helper function, we\n    +    just mark the whole thing as `test_must_fail`. However, it's possible\n    +    that the helper function might fail earlier or later than expected due\n    +    to an introduced bug. If this happens, then the test case will still\n    +    report as passing but it should really be marked as failing since it\n    +    didn't actually display the intended behaviour.\n    +\n         While we're at it, some helper functions have git commands piping into\n         another git command. Break these pipes up into two separate invocations\n         with a file buffer so that the return code of the first command is not\n    @@ t/lib-submodule-update.sh: test_submodule_switch_common () {\n      \t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n     -\t\t\ttest_must_fail $command replace_sub1_with_directory &&\n     +\t\t\tOVERWRITING_FAIL=test_must_fail $command replace_sub1_with_directory &&\n    ++\t\t\tOVERWRITING_FAIL= &&\n      \t\t\ttest_superproject_content origin/add_sub1 &&\n      \t\t\ttest_submodule_content sub1 origin/add_sub1\n      \t\t)\n\n t/lib-submodule-update.sh   | 26 ++++++++++++++++++--------\n t/t3426-rebase-submodule.sh |  4 ++--\n t/t3513-revert-submodule.sh | 20 ++++++++++++--------\n t/t3906-stash-submodule.sh  | 15 +++++++++------\n t/t4137-apply-submodule.sh  |  6 ++++--\n t/t4255-am-submodule.sh     |  6 ++++--\n t/t5572-pull-submodule.sh   |  8 ++++----\n t/t6041-bisect-submodule.sh | 33 ++++++++++++++++++---------------\n 8 files changed, 71 insertions(+), 47 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex cd80d77707..f61c3b43df 100644\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -304,12 +304,15 @@ test_submodule_content () {\n # a removed submodule.\n #\n # Removing a submodule containing a .git directory must fail even when forced\n-# to protect the history!\n+# to protect the history! If we are testing this case,\n+# OVERWRITING_FAIL=test_must_fail, otherwise OVERWRITING_FAIL will be the empty\n+# string.\n #\n \n # Internal function; use test_submodule_switch_func(), test_submodule_switch_func(),\n # or test_submodule_forced_switch() instead.\n test_submodule_switch_common () {\n+\tOVERWRITING_FAIL=\n \tcommand=\"$1\"\n \t######################### Appearing submodule #########################\n \t# Switching to a commit letting a submodule appear creates empty dir ...\n@@ -443,7 +446,8 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\tOVERWRITING_FAIL=test_must_fail $command replace_sub1_with_directory &&\n+\t\t\tOVERWRITING_FAIL= &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -456,7 +460,7 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\tOVERWRITING_FAIL=test_must_fail $command replace_sub1_with_directory &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -470,7 +474,7 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\tOVERWRITING_FAIL=test_must_fail $command replace_sub1_with_file &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -484,7 +488,7 @@ test_submodule_switch_common () {\n \t\t\tcd submodule_update &&\n \t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n \t\t\treplace_gitfile_with_git_dir sub1 &&\n-\t\t\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\tOVERWRITING_FAIL=test_must_fail $command replace_sub1_with_file &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -559,6 +563,11 @@ test_submodule_switch_common () {\n # conditions, set the appropriate KNOWN_FAILURE_* variable used in the tests\n # below to 1.\n #\n+# Removing a submodule containing a .git directory must fail even when forced\n+# to protect the history! If we are testing this case,\n+# OVERWRITING_FAIL=test_must_fail, otherwise OVERWRITING_FAIL will be the empty\n+# string.\n+#\n # Use as follows:\n #\n # my_func () {\n@@ -568,6 +577,7 @@ test_submodule_switch_common () {\n # }\n # test_submodule_switch_func \"my_func\"\n test_submodule_switch_func () {\n+\tOVERWRITING_FAIL=\n \tcommand=\"$1\"\n \ttest_submodule_switch_common \"$command\"\n \n@@ -580,7 +590,7 @@ test_submodule_switch_func () {\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\tOVERWRITING_FAIL=test_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@@ -588,7 +598,7 @@ test_submodule_switch_func () {\n }\n \n test_submodule_switch () {\n-\ttest_submodule_switch_func \"git $1\"\n+\ttest_submodule_switch_func \"eval \\$OVERWRITING_FAIL git $1\"\n }\n \n # Same as test_submodule_switch(), except that throwing away local changes in\n@@ -596,7 +606,7 @@ test_submodule_switch () {\n test_submodule_forced_switch () {\n \tcommand=\"$1\"\n \tKNOWN_FAILURE_FORCED_SWITCH_TESTS=1\n-\ttest_submodule_switch_common \"git $command\"\n+\ttest_submodule_switch_common \"eval \\$OVERWRITING_FAIL git $command\"\n \n \t# When forced, a file in the superproject does not prevent creating a\n \t# submodule of the same name.\ndiff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh\nindex 788605ccc0..c6a7f584ed 100755\n--- a/t/t3426-rebase-submodule.sh\n+++ b/t/t3426-rebase-submodule.sh\n@@ -17,7 +17,7 @@ git_rebase () {\n \tgit status -su >actual &&\n \tls -1pR * >>actual &&\n \ttest_cmp expect actual &&\n-\tgit rebase \"$1\"\n+\t$OVERWRITING_FAIL git rebase \"$1\"\n }\n \n test_submodule_switch_func \"git_rebase\"\n@@ -35,7 +35,7 @@ git_rebase_interactive () {\n \ttest_cmp expect actual &&\n \tset_fake_editor &&\n \techo \"fake-editor.sh\" >.git/info/exclude &&\n-\tgit rebase -i \"$1\"\n+\t$OVERWRITING_FAIL git rebase -i \"$1\"\n }\n \n test_submodule_switch_func \"git_rebase_interactive\"\ndiff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh\nindex 95a7f64471..6c899db7e1 100755\n--- a/t/t3513-revert-submodule.sh\n+++ b/t/t3513-revert-submodule.sh\n@@ -15,14 +15,18 @@ git_revert () {\n \tgit status -su >expect &&\n \tls -1pR * >>expect &&\n \ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n-\tgit checkout \"$1\" &&\n-\tgit revert HEAD &&\n-\trm -rf * &&\n-\ttar xf \"$TRASH_DIRECTORY/tmp.tar\" &&\n-\tgit status -su >actual &&\n-\tls -1pR * >>actual &&\n-\ttest_cmp expect actual &&\n-\tgit revert HEAD\n+\t$OVERWRITING_FAIL git checkout \"$1\" &&\n+\tif test -z \"$OVERWRITING_FAIL\"\n+\tthen\n+\t\tgit checkout \"$1\" &&\n+\t\tgit revert HEAD &&\n+\t\trm -rf * &&\n+\t\ttar xf \"$TRASH_DIRECTORY/tmp.tar\" &&\n+\t\tgit status -su >actual &&\n+\t\tls -1pR * >>actual &&\n+\t\ttest_cmp expect actual &&\n+\t\tgit revert HEAD\n+\tfi\n }\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\ndiff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh\nindex 6a7e801ca0..860940072d 100755\n--- a/t/t3906-stash-submodule.sh\n+++ b/t/t3906-stash-submodule.sh\n@@ -8,12 +8,15 @@ test_description='stash can handle submodules'\n git_stash () {\n \tgit status -su >expect &&\n \tls -1pR * >>expect &&\n-\tgit read-tree -u -m \"$1\" &&\n-\tgit stash &&\n-\tgit status -su >actual &&\n-\tls -1pR * >>actual &&\n-\ttest_cmp expect actual &&\n-\tgit stash apply\n+\t$OVERWRITING_FAIL git read-tree -u -m \"$1\" &&\n+\tif test -z \"$OVERWRITING_FAIL\"\n+\tthen\n+\t\tgit stash &&\n+\t\tgit status -su >actual &&\n+\t\tls -1pR * >>actual &&\n+\t\ttest_cmp expect actual &&\n+\t\tgit stash apply\n+\tfi\n }\n \n KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES=1\ndiff --git a/t/t4137-apply-submodule.sh b/t/t4137-apply-submodule.sh\nindex b645e303a0..dd08d9e1a4 100755\n--- a/t/t4137-apply-submodule.sh\n+++ b/t/t4137-apply-submodule.sh\n@@ -6,13 +6,15 @@ test_description='git apply handling submodules'\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n apply_index () {\n-\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --index -\n+\tgit diff --ignore-submodules=dirty \"..$1\" >diff &&\n+\t$OVERWRITING_FAIL git apply --index - <diff\n }\n \n test_submodule_switch_func \"apply_index\"\n \n apply_3way () {\n-\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --3way -\n+\tgit diff --ignore-submodules=dirty \"..$1\" >diff &&\n+\t$OVERWRITING_FAIL git apply --3way - <diff\n }\n \n test_submodule_switch_func \"apply_3way\"\ndiff --git a/t/t4255-am-submodule.sh b/t/t4255-am-submodule.sh\nindex 1b179d5f45..b0fe78a956 100755\n--- a/t/t4255-am-submodule.sh\n+++ b/t/t4255-am-submodule.sh\n@@ -6,13 +6,15 @@ test_description='git am handling submodules'\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n am () {\n-\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am -\n+\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" >patch &&\n+\t$OVERWRITING_FAIL git am - <patch\n }\n \n test_submodule_switch_func \"am\"\n \n am_3way () {\n-\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am --3way -\n+\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" >patch &&\n+\t$OVERWRITING_FAIL git am --3way - <patch\n }\n \n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\ndiff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh\nindex f911bf631e..4dd9913b6b 100755\n--- a/t/t5572-pull-submodule.sh\n+++ b/t/t5572-pull-submodule.sh\n@@ -13,7 +13,7 @@ reset_branch_to_HEAD () {\n \n git_pull () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull\n+\t$OVERWRITING_FAIL git pull\n }\n \n # pulls without conflicts\n@@ -21,21 +21,21 @@ test_submodule_switch_func \"git_pull\"\n \n git_pull_ff () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --ff\n+\t$OVERWRITING_FAIL git pull --ff\n }\n \n test_submodule_switch_func \"git_pull_ff\"\n \n git_pull_ff_only () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --ff-only\n+\t$OVERWRITING_FAIL git pull --ff-only\n }\n \n test_submodule_switch_func \"git_pull_ff_only\"\n \n git_pull_noff () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --no-ff\n+\t$OVERWRITING_FAIL git pull --no-ff\n }\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\ndiff --git a/t/t6041-bisect-submodule.sh b/t/t6041-bisect-submodule.sh\nindex 0e0cdf638d..714d393899 100755\n--- a/t/t6041-bisect-submodule.sh\n+++ b/t/t6041-bisect-submodule.sh\n@@ -10,21 +10,24 @@ git_bisect () {\n \tls -1pR * >>expect &&\n \ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n \tGOOD=$(git rev-parse --verify HEAD) &&\n-\tgit checkout \"$1\" &&\n-\techo \"foo\" >bar &&\n-\tgit add bar &&\n-\tgit commit -m \"bisect bad\" &&\n-\tBAD=$(git rev-parse --verify HEAD) &&\n-\tgit reset --hard HEAD^^ &&\n-\tgit submodule update &&\n-\tgit bisect start &&\n-\tgit bisect good $GOOD &&\n-\trm -rf * &&\n-\ttar xf \"$TRASH_DIRECTORY/tmp.tar\" &&\n-\tgit status -su >actual &&\n-\tls -1pR * >>actual &&\n-\ttest_cmp expect actual &&\n-\tgit bisect bad $BAD\n+\t$OVERWRITING_FAIL git checkout \"$1\" &&\n+\tif test -z \"$OVERWRITING_FAIL\"\n+\tthen\n+\t\techo \"foo\" >bar &&\n+\t\tgit add bar &&\n+\t\tgit commit -m \"bisect bad\" &&\n+\t\tBAD=$(git rev-parse --verify HEAD) &&\n+\t\tgit reset --hard HEAD^^ &&\n+\t\tgit submodule update &&\n+\t\tgit bisect start &&\n+\t\tgit bisect good $GOOD &&\n+\t\trm -rf * &&\n+\t\ttar xf \"$TRASH_DIRECTORY/tmp.tar\" &&\n+\t\tgit status -su >actual &&\n+\t\tls -1pR * >>actual &&\n+\t\ttest_cmp expect actual &&\n+\t\tgit bisect bad $BAD\n+\tfi\n }\n \n test_submodule_switch_func \"git_bisect\"\n-- \n2.26.2.548.gbb00c8a0a9\n\n"},{"id":"396695","messageId":"xmqqpnbor9ng.fsf@gitster.c.googlers.com","threadId":"53350","inReplyTo":"f0d8dcf7dc52fe5ad2f1e173cd744bfdeb55eb45.1588242122.git.liu.denton@gmail.com","subject":"Re: [PATCH v1.1] lib-submodule-update: pass OVERWRITING_FAIL","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-04-30T20:38:59Z","receivedAt":"2020-04-30T20:39:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Denton Liu <liu.denton@gmail.com> writes:\n\n> We are using `test_must_fail $command`. However, $command is not\n> necessarily a git command; it could be a test helper function.\n>\n> In an effort to stop using test_must_fail with non-git commands, instead\n> of invoking `test_must_fail $command`, run\n> `OVERWRITING_FAIL=test_must_fail $command` instead.\n\nThis description alone does not make much sense to me as a reader.\nFor \"when OVERWRITING_FAIL environment variable is set to\ntest_must_fail, something magical happens while running $command\" to\nbe true, $command (which may be \"a git command\", or \"a test helper\nfunction\") must be aware of, and must be told how to react to the\nOVERWRITING_FAIL environment variable.  For example,\n\n\ttest_must_fail test a = b\n\ttest_must_fail git cat-file leaf HEAD\n\nmay succeed because \"test a = b\" and \"git cat-file leaf HEAD\" fail\nand test_must_fail would notice that these commands exited with\nnon-zero status without crashing.\n\nBut how would the same happen for these commands,\n\n\tOVERWRITING_FAIL=test_must_fail test a = b\n\tOVERWRITING_FAIL=test_must_fail git cat-file leaf HEAD\n\nwhich is what the above paragraph tells me to write \"instead of\nusing test_must_fail\".  There is something gravely missing from the\ndescription.  \n\nIs it that $command is *NEVER* a 'git' command, but just a selected\nfew helper functions know how to honor this convention?  If that is\nthe case, perhaps can we teach these helper functions an *option* to\nexpect a failure instead of expecting a success?  These are all\nspeculations, because the above description is too vague as a\nstarting point for clear thinking.\n\n> +\t\t\tOVERWRITING_FAIL=test_must_fail $command replace_sub1_with_directory &&\n> +\t\t\tOVERWRITING_FAIL= &&\n\nIf we have given up the \"single-shot environment export\" for\ncompatibility reasons (which is a sound decision to follow), we\nshould make sure it is clear to our readers that we are not using\nthat shell feature.  I.e.\n\n\t\t\texport OVERWRITING_FAIL=test_must_fail &&\n\t\t\t$command replace_sub1_with_directory &&\n\t\t\tunset OVERWRITING_FAIL &&\n\nI still do not understand how you are forcing an arbitrary $command\nto honor this environment variable, though.\n"},{"id":"396737","messageId":"20200501093554.GA49619@generichostname","threadId":"53350","inReplyTo":"xmqqpnbor9ng.fsf@gitster.c.googlers.com","subject":"Re: [PATCH v1.1] lib-submodule-update: pass OVERWRITING_FAIL","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-05-01T09:35:54Z","receivedAt":"2020-05-01T09:36:00Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"Hi Junio,\n\nOn Thu, Apr 30, 2020 at 01:38:59PM -0700, Junio C Hamano wrote:\n> Denton Liu <liu.denton@gmail.com> writes:\n> \n> > We are using `test_must_fail $command`. However, $command is not\n> > necessarily a git command; it could be a test helper function.\n> >\n> > In an effort to stop using test_must_fail with non-git commands, instead\n> > of invoking `test_must_fail $command`, run\n> > `OVERWRITING_FAIL=test_must_fail $command` instead.\n> \n> This description alone does not make much sense to me as a reader.\n> For \"when OVERWRITING_FAIL environment variable is set to\n> test_must_fail, something magical happens while running $command\" to\n> be true, $command (which may be \"a git command\", or \"a test helper\n> function\") must be aware of, and must be told how to react to the\n> OVERWRITING_FAIL environment variable.  For example,\n> \n> \ttest_must_fail test a = b\n> \ttest_must_fail git cat-file leaf HEAD\n> \n> may succeed because \"test a = b\" and \"git cat-file leaf HEAD\" fail\n> and test_must_fail would notice that these commands exited with\n> non-zero status without crashing.\n> \n> But how would the same happen for these commands,\n> \n> \tOVERWRITING_FAIL=test_must_fail test a = b\n> \tOVERWRITING_FAIL=test_must_fail git cat-file leaf HEAD\n> \n> which is what the above paragraph tells me to write \"instead of\n> using test_must_fail\".  There is something gravely missing from the\n> description.  \n\nBecause of the previous patch in this series, helper functions are\ncalled using test_submodule_switch_func() while git commands are invoked\nusing test_submodule_switch() and test_submodule_forced_switch(). As a\nresult, helper functions that are invoked must learn to handle\n$OVERWRITING_FAIL appropriately. The latter two functions now feature\nsomething like\n\n\ttest_submodule_switch_func \"eval \\$OVERWRITING_FAIL git $1\"\n\nDoes this commit message increase the clarity?\n\n\tlib-submodule-update: pass OVERWRITING_FAIL\n\n\tWe are using `test_must_fail $command`. However, $command is not\n\tnecessarily a git command; it could be a test helper function.\n\n\tIn an effort to stop using test_must_fail with non-git commands, instead\n\tof invoking `test_must_fail $command`, run\n\t`OVERWRITING_FAIL=test_must_fail $command` instead in\n\ttest_submodule_switch_common().\n\n\tIn the case where $command is a git command,\n\ttest_submodule_switch_common() is called by one of\n\ttest_submodule_switch() or test_submodule_forced_switch(). In those two\n\tfunctions, pass $command like this:\n\n\t\ttest_submodule_switch_common \"eval \\$OVERWRITING_FAIL git $command\"\n\n\tIn the case where $command is a test helper function, increase the\n\tgranularity of the test helper function by marking the git invocation\n\twhich was meant to fail like this:\n\n\t\t$OVERWRITING_FAIL git checkout \"$1\"\n\n\tThis is useful because currently, when we run a test helper function, we\n\tjust mark the whole thing as `test_must_fail`. However, it's possible\n\tthat the helper function might fail earlier or later than expected due\n\tto an introduced bug. If this happens, then the test case will still\n\treport as passing but it should really be marked as failing since it\n\tdidn't actually display the intended behaviour.\n\n\tWhile we're at it, some helper functions have git commands piping into\n\tanother git command. Break these pipes up into two separate invocations\n\twith a file buffer so that the return code of the first command is not\n\tlost.\n\n\tThis patch can be better viewed with `--ignore-all-space`.\n\n> Is it that $command is *NEVER* a 'git' command, but just a selected\n> few helper functions know how to honor this convention?\n\nWith the changes made, it is now either a helper function or an eval of\na git command, as described above.\n\n> If that is\n> the case, perhaps can we teach these helper functions an *option* to\n> expect a failure instead of expecting a success?\n\nI don't think this is possible because $command is some arbitrary\ncommand string, in particular due to the eval stuff. I suppose we could\nwrite something like\n\n\ttest_submodule_switch_common \"f () {\n\t\t\t# handle potential --expect-fail\n\t\t\tgit $command\"\n\t\t} && f\"\n\nbut I'm not sure if this would even work. I haven't tested it and I feel\nlike doing this would be far too unwieldy. Also, since\ntest_submodule_switch_common() uses $command as the test name, I don't\nthink it's feasible to take this approach.\n\n> These are all\n> speculations, because the above description is too vague as a\n> starting point for clear thinking.\n> \n> > +\t\t\tOVERWRITING_FAIL=test_must_fail $command replace_sub1_with_directory &&\n> > +\t\t\tOVERWRITING_FAIL= &&\n> \n> If we have given up the \"single-shot environment export\" for\n> compatibility reasons (which is a sound decision to follow), we\n> should make sure it is clear to our readers that we are not using\n> that shell feature.  I.e.\n> \n> \t\t\texport OVERWRITING_FAIL=test_must_fail &&\n> \t\t\t$command replace_sub1_with_directory &&\n> \t\t\tunset OVERWRITING_FAIL &&\n\nMakes sense. I would drop the export, though, because $OVERWRITING_FAIL\nshould only be handled within the shell environment. We're never calling\nany external commands that need to know about this variable.\n\nOn a tangent, I got a response[1] from the dash people about the\n\"single-shot environment export\" propagating past a function. It seems\nlike in the most updated version of POSIX addresses this and it's up to\nthe implementers whether or not variables propagate past a function\ninvocation.\n\nThanks,\n\nDenton\n\n[1]: https://www.mail-archive.com/dash@vger.kernel.org/msg01925.html\n"},{"id":"396771","messageId":"xmqq8siboayy.fsf@gitster.c.googlers.com","threadId":"53350","inReplyTo":"20200501093554.GA49619@generichostname","subject":"Re: [PATCH v1.1] lib-submodule-update: pass OVERWRITING_FAIL","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-05-01T16:51:01Z","receivedAt":"2020-05-01T16:51:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Denton Liu <liu.denton@gmail.com> writes:\n\n> Does this commit message increase the clarity?\n> \n> \tlib-submodule-update: pass OVERWRITING_FAIL\n>\n> \tWe are using `test_must_fail $command`. However, $command is not\n> \tnecessarily a git command; it could be a test helper function.\n>\n> \tIn an effort to stop using test_must_fail with non-git commands, instead\n> \tof invoking `test_must_fail $command`, run\n> \t`OVERWRITING_FAIL=test_must_fail $command` instead in\n> \ttest_submodule_switch_common().\n>\n> \tIn the case where $command is a git command,\n> \ttest_submodule_switch_common() is called by one of\n> \ttest_submodule_switch() or test_submodule_forced_switch(). In those two\n> \tfunctions, pass $command like this:\n>\n> \t\ttest_submodule_switch_common \"eval \\$OVERWRITING_FAIL git $command\"\n>\n> \tIn the case where $command is a test helper function, increase the\n> \tgranularity of the test helper function by marking the git invocation\n> \twhich was meant to fail like this:\n>\n> \t\t$OVERWRITING_FAIL git checkout \"$1\"\n>\n> \tThis is useful because currently, when we run a test helper function, we\n> \tjust mark the whole thing as `test_must_fail`. However, it's possible\n> \tthat the helper function might fail earlier or later than expected due\n> \tto an introduced bug. If this happens, then the test case will still\n> \treport as passing but it should really be marked as failing since it\n> \tdidn't actually display the intended behaviour.\n>\n> \tWhile we're at it, some helper functions have git commands piping into\n> \tanother git command. Break these pipes up into two separate invocations\n> \twith a file buffer so that the return code of the first command is not\n> \tlost.\n>\n> \tThis patch can be better viewed with `--ignore-all-space`.\n\nIt may be better, but not all that much.  I think it comes from the\ndesign that this change is hard to understand.  Anybody who wants to\nwrite more of these tests would need a much better guidance than\n\"just use OVERWRITING_FAIL=test_must_fail where you would normally\nwrite test_must_fail and you'd be OK\", as that is not what is going\non.  Before doing so, they would make sure that the place where they\nare tempted to write test_must_fail MUST be called by these three\nwrappers, or this guidance does not apply, for example.\n\n>> If we have given up the \"single-shot environment export\" for\n>> compatibility reasons (which is a sound decision to follow), we\n>> should make sure it is clear to our readers that we are not using\n>> that shell feature.  I.e.\n>> \n>> \t\t\texport OVERWRITING_FAIL=test_must_fail &&\n>> \t\t\t$command replace_sub1_with_directory &&\n>> \t\t\tunset OVERWRITING_FAIL &&\n>\n> Makes sense. I would drop the export, though, because $OVERWRITING_FAIL\n> should only be handled within the shell environment. We're never calling\n> any external commands that need to know about this variable.\n\nYup, not pretending that this affects anywhere outside of shell by\nexporting is a bad idea.\n\n> On a tangent, I got a response[1] from the dash people about the\n> \"single-shot environment export\" propagating past a function. It seems\n> like in the most updated version of POSIX addresses this and it's up to\n> the implementers whether or not variables propagate past a function\n> invocation.\n\nYes, it is the reason why we discourage the unportable use of the\npattern in our tests.\n"},{"id":"397077","messageId":"be2f55bbc86958154e63234945d0030f59c964be.1588678640.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"f0d8dcf7dc52fe5ad2f1e173cd744bfdeb55eb45.1588242122.git.liu.denton@gmail.com","subject":"[PATCH v1.2] lib-submodule-update: pass OVERWRITING_FAIL","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-05-05T11:43:02Z","receivedAt":"2020-05-05T11:43:15Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"We are using `test_must_fail $command`. However, $command is not\nnecessarily a git command; it could be a test helper function.\n\nIn an effort to stop using test_must_fail with non-git commands, instead\nof invoking `test_must_fail $command`, run\n`OVERWRITING_FAIL=test_must_fail $command` instead in\ntest_submodule_switch_common().\n\nIn the case where $command is a git command,\ntest_submodule_switch_common() is called by one of\ntest_submodule_switch() or test_submodule_forced_switch(). In those two\nfunctions, pass $command like this:\n\n\ttest_submodule_switch_common \"eval \\$OVERWRITING_FAIL git $command\"\n\nWhen $command is a helper function, the parent function calling\ntest_submodule_switch_common() is test_submodule_switch_func(). For all\ntest_submodule_switch_func() invocations, increase the granularity of\nthe argument test helper function by prefixing the git invocation which is\nmeant to fail with $OVERWRITING_FAIL like this:\n\n\t$OVERWRITING_FAIL git checkout \"$1\"\n\nThis is useful because currently, when we run a test helper function, we\njust mark the whole thing as `test_must_fail`. However, it's possible\nthat the helper function might fail earlier or later than expected due\nto an introduced bug. If this happens, then the test case will still\nreport as passing but it should really be marked as failing since it\ndidn't actually display the intended behaviour.\n\nWhile we're at it, some helper functions have git commands piping into\nanother git command. Break these pipes up into two separate invocations\nwith a file buffer so that the return code of the first command is not\nlost.\n\nThis patch can be better viewed with `--ignore-all-space`.\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\nChanges since v1.1:\n\n\t* unset OVERWRITING_FAIL in more places that I missed earlier\n\n\t* clarify that the helper functions passed to\n\t  test_submodule_switch_func() are the ones that have been\n\t  modified (I'm not 100% if I understood your complaint with\n\t  the text so perhaps the commit message may still need further\n\t  refinement)\n\n t/lib-submodule-update.sh   | 33 +++++++++++++++++++++++++--------\n t/t3426-rebase-submodule.sh |  4 ++--\n t/t3513-revert-submodule.sh | 20 ++++++++++++--------\n t/t3906-stash-submodule.sh  | 15 +++++++++------\n t/t4137-apply-submodule.sh  |  6 ++++--\n t/t4255-am-submodule.sh     |  6 ++++--\n t/t5572-pull-submodule.sh   |  8 ++++----\n t/t6041-bisect-submodule.sh | 33 ++++++++++++++++++---------------\n 8 files changed, 78 insertions(+), 47 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex cd80d77707..67d9d8615a 100644\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -304,12 +304,15 @@ test_submodule_content () {\n # a removed submodule.\n #\n # Removing a submodule containing a .git directory must fail even when forced\n-# to protect the history!\n+# to protect the history! If we are testing this case,\n+# OVERWRITING_FAIL=test_must_fail, otherwise OVERWRITING_FAIL will be the empty\n+# string.\n #\n \n # Internal function; use test_submodule_switch_func(), test_submodule_switch_func(),\n # or test_submodule_forced_switch() instead.\n test_submodule_switch_common () {\n+\tOVERWRITING_FAIL=\n \tcommand=\"$1\"\n \t######################### Appearing submodule #########################\n \t# Switching to a commit letting a submodule appear creates empty dir ...\n@@ -443,7 +446,9 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\tOVERWRITING_FAIL=test_must_fail &&\n+\t\t\t$command replace_sub1_with_directory &&\n+\t\t\tOVERWRITING_FAIL= &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -456,7 +461,9 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\tOVERWRITING_FAIL=test_must_fail &&\n+\t\t\t$command replace_sub1_with_directory &&\n+\t\t\tOVERWRITING_FAIL= &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -470,7 +477,9 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\tOVERWRITING_FAIL=test_must_fail &&\n+\t\t\t$command replace_sub1_with_file &&\n+\t\t\tOVERWRITING_FAIL= &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -484,7 +493,9 @@ test_submodule_switch_common () {\n \t\t\tcd submodule_update &&\n \t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n \t\t\treplace_gitfile_with_git_dir sub1 &&\n-\t\t\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\tOVERWRITING_FAIL=test_must_fail &&\n+\t\t\t$command replace_sub1_with_file &&\n+\t\t\tOVERWRITING_FAIL= &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -559,6 +570,11 @@ test_submodule_switch_common () {\n # conditions, set the appropriate KNOWN_FAILURE_* variable used in the tests\n # below to 1.\n #\n+# Removing a submodule containing a .git directory must fail even when forced\n+# to protect the history! If we are testing this case,\n+# OVERWRITING_FAIL=test_must_fail, otherwise OVERWRITING_FAIL will be the empty\n+# string.\n+#\n # Use as follows:\n #\n # my_func () {\n@@ -568,6 +584,7 @@ test_submodule_switch_common () {\n # }\n # test_submodule_switch_func \"my_func\"\n test_submodule_switch_func () {\n+\tOVERWRITING_FAIL=\n \tcommand=\"$1\"\n \ttest_submodule_switch_common \"$command\"\n \n@@ -580,7 +597,7 @@ test_submodule_switch_func () {\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\tOVERWRITING_FAIL=test_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@@ -588,7 +605,7 @@ test_submodule_switch_func () {\n }\n \n test_submodule_switch () {\n-\ttest_submodule_switch_func \"git $1\"\n+\ttest_submodule_switch_func \"eval \\$OVERWRITING_FAIL git $1\"\n }\n \n # Same as test_submodule_switch(), except that throwing away local changes in\n@@ -596,7 +613,7 @@ test_submodule_switch () {\n test_submodule_forced_switch () {\n \tcommand=\"$1\"\n \tKNOWN_FAILURE_FORCED_SWITCH_TESTS=1\n-\ttest_submodule_switch_common \"git $command\"\n+\ttest_submodule_switch_common \"eval \\$OVERWRITING_FAIL git $command\"\n \n \t# When forced, a file in the superproject does not prevent creating a\n \t# submodule of the same name.\ndiff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh\nindex 788605ccc0..c6a7f584ed 100755\n--- a/t/t3426-rebase-submodule.sh\n+++ b/t/t3426-rebase-submodule.sh\n@@ -17,7 +17,7 @@ git_rebase () {\n \tgit status -su >actual &&\n \tls -1pR * >>actual &&\n \ttest_cmp expect actual &&\n-\tgit rebase \"$1\"\n+\t$OVERWRITING_FAIL git rebase \"$1\"\n }\n \n test_submodule_switch_func \"git_rebase\"\n@@ -35,7 +35,7 @@ git_rebase_interactive () {\n \ttest_cmp expect actual &&\n \tset_fake_editor &&\n \techo \"fake-editor.sh\" >.git/info/exclude &&\n-\tgit rebase -i \"$1\"\n+\t$OVERWRITING_FAIL git rebase -i \"$1\"\n }\n \n test_submodule_switch_func \"git_rebase_interactive\"\ndiff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh\nindex 95a7f64471..6c899db7e1 100755\n--- a/t/t3513-revert-submodule.sh\n+++ b/t/t3513-revert-submodule.sh\n@@ -15,14 +15,18 @@ git_revert () {\n \tgit status -su >expect &&\n \tls -1pR * >>expect &&\n \ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n-\tgit checkout \"$1\" &&\n-\tgit revert HEAD &&\n-\trm -rf * &&\n-\ttar xf \"$TRASH_DIRECTORY/tmp.tar\" &&\n-\tgit status -su >actual &&\n-\tls -1pR * >>actual &&\n-\ttest_cmp expect actual &&\n-\tgit revert HEAD\n+\t$OVERWRITING_FAIL git checkout \"$1\" &&\n+\tif test -z \"$OVERWRITING_FAIL\"\n+\tthen\n+\t\tgit checkout \"$1\" &&\n+\t\tgit revert HEAD &&\n+\t\trm -rf * &&\n+\t\ttar xf \"$TRASH_DIRECTORY/tmp.tar\" &&\n+\t\tgit status -su >actual &&\n+\t\tls -1pR * >>actual &&\n+\t\ttest_cmp expect actual &&\n+\t\tgit revert HEAD\n+\tfi\n }\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\ndiff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh\nindex 6a7e801ca0..860940072d 100755\n--- a/t/t3906-stash-submodule.sh\n+++ b/t/t3906-stash-submodule.sh\n@@ -8,12 +8,15 @@ test_description='stash can handle submodules'\n git_stash () {\n \tgit status -su >expect &&\n \tls -1pR * >>expect &&\n-\tgit read-tree -u -m \"$1\" &&\n-\tgit stash &&\n-\tgit status -su >actual &&\n-\tls -1pR * >>actual &&\n-\ttest_cmp expect actual &&\n-\tgit stash apply\n+\t$OVERWRITING_FAIL git read-tree -u -m \"$1\" &&\n+\tif test -z \"$OVERWRITING_FAIL\"\n+\tthen\n+\t\tgit stash &&\n+\t\tgit status -su >actual &&\n+\t\tls -1pR * >>actual &&\n+\t\ttest_cmp expect actual &&\n+\t\tgit stash apply\n+\tfi\n }\n \n KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES=1\ndiff --git a/t/t4137-apply-submodule.sh b/t/t4137-apply-submodule.sh\nindex b645e303a0..dd08d9e1a4 100755\n--- a/t/t4137-apply-submodule.sh\n+++ b/t/t4137-apply-submodule.sh\n@@ -6,13 +6,15 @@ test_description='git apply handling submodules'\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n apply_index () {\n-\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --index -\n+\tgit diff --ignore-submodules=dirty \"..$1\" >diff &&\n+\t$OVERWRITING_FAIL git apply --index - <diff\n }\n \n test_submodule_switch_func \"apply_index\"\n \n apply_3way () {\n-\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --3way -\n+\tgit diff --ignore-submodules=dirty \"..$1\" >diff &&\n+\t$OVERWRITING_FAIL git apply --3way - <diff\n }\n \n test_submodule_switch_func \"apply_3way\"\ndiff --git a/t/t4255-am-submodule.sh b/t/t4255-am-submodule.sh\nindex 1b179d5f45..b0fe78a956 100755\n--- a/t/t4255-am-submodule.sh\n+++ b/t/t4255-am-submodule.sh\n@@ -6,13 +6,15 @@ test_description='git am handling submodules'\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n am () {\n-\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am -\n+\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" >patch &&\n+\t$OVERWRITING_FAIL git am - <patch\n }\n \n test_submodule_switch_func \"am\"\n \n am_3way () {\n-\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am --3way -\n+\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" >patch &&\n+\t$OVERWRITING_FAIL git am --3way - <patch\n }\n \n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\ndiff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh\nindex f911bf631e..4dd9913b6b 100755\n--- a/t/t5572-pull-submodule.sh\n+++ b/t/t5572-pull-submodule.sh\n@@ -13,7 +13,7 @@ reset_branch_to_HEAD () {\n \n git_pull () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull\n+\t$OVERWRITING_FAIL git pull\n }\n \n # pulls without conflicts\n@@ -21,21 +21,21 @@ test_submodule_switch_func \"git_pull\"\n \n git_pull_ff () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --ff\n+\t$OVERWRITING_FAIL git pull --ff\n }\n \n test_submodule_switch_func \"git_pull_ff\"\n \n git_pull_ff_only () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --ff-only\n+\t$OVERWRITING_FAIL git pull --ff-only\n }\n \n test_submodule_switch_func \"git_pull_ff_only\"\n \n git_pull_noff () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --no-ff\n+\t$OVERWRITING_FAIL git pull --no-ff\n }\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\ndiff --git a/t/t6041-bisect-submodule.sh b/t/t6041-bisect-submodule.sh\nindex 0e0cdf638d..714d393899 100755\n--- a/t/t6041-bisect-submodule.sh\n+++ b/t/t6041-bisect-submodule.sh\n@@ -10,21 +10,24 @@ git_bisect () {\n \tls -1pR * >>expect &&\n \ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n \tGOOD=$(git rev-parse --verify HEAD) &&\n-\tgit checkout \"$1\" &&\n-\techo \"foo\" >bar &&\n-\tgit add bar &&\n-\tgit commit -m \"bisect bad\" &&\n-\tBAD=$(git rev-parse --verify HEAD) &&\n-\tgit reset --hard HEAD^^ &&\n-\tgit submodule update &&\n-\tgit bisect start &&\n-\tgit bisect good $GOOD &&\n-\trm -rf * &&\n-\ttar xf \"$TRASH_DIRECTORY/tmp.tar\" &&\n-\tgit status -su >actual &&\n-\tls -1pR * >>actual &&\n-\ttest_cmp expect actual &&\n-\tgit bisect bad $BAD\n+\t$OVERWRITING_FAIL git checkout \"$1\" &&\n+\tif test -z \"$OVERWRITING_FAIL\"\n+\tthen\n+\t\techo \"foo\" >bar &&\n+\t\tgit add bar &&\n+\t\tgit commit -m \"bisect bad\" &&\n+\t\tBAD=$(git rev-parse --verify HEAD) &&\n+\t\tgit reset --hard HEAD^^ &&\n+\t\tgit submodule update &&\n+\t\tgit bisect start &&\n+\t\tgit bisect good $GOOD &&\n+\t\trm -rf * &&\n+\t\ttar xf \"$TRASH_DIRECTORY/tmp.tar\" &&\n+\t\tgit status -su >actual &&\n+\t\tls -1pR * >>actual &&\n+\t\ttest_cmp expect actual &&\n+\t\tgit bisect bad $BAD\n+\tfi\n }\n \n test_submodule_switch_func \"git_bisect\"\n-- \n2.26.2.548.gbb00c8a0a9\n\n"},{"id":"398311","messageId":"cover.1590019226.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1588162842.git.liu.denton@gmail.com","subject":"[PATCH v2 0/4] t: replace incorrect test_must_fail usage (part 5)","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-05-21T00:24:14Z","receivedAt":"2020-05-21T00:24:44Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"Hi all,\n\nThis is mostly a resend of what's currently queued in\n\"dl/test-must-fail-fixes-5\" except with a tiny bit of cleanup on the tip\npatch. I'd appreciate a review on this series so that we can finally get\nrid of that \"Needs review\" on the What's Cooking messages ;)\n\n\nThe overall scope of these patches is to replace inappropriate uses of\ntest_must_fail. IOW, we should only allow test_must_fail to run on `git`\nand `test-tool`. Ultimately, we will conclude by making test_must_fail\nerror out on non-git commands. An advance view of the final series can\nbe found here[1].\n\nThis is the fifth part. It focuses on lib-submodule-update.sh and tests\nthat make use of it.\n\nThe first part can be found here[2]. The second part can be found\nhere[3]. The third part can be found here[4]. The fourth part can be\nfound here[5].\n\nChanges since v1.2:\n\n* In \"lib-submodule-update: pass OVERWRITING_FAIL\", use if-then return\n  to reduce the amount of code churn\n\n[1]: (may be rebased at any time) https://github.com/Denton-L/git/tree/ready/cleanup-test-must-fail2\n[2]: https://lore.kernel.org/git/cover.1576583819.git.liu.denton@gmail.com/\n[3]: https://lore.kernel.org/git/cover.1577454401.git.liu.denton@gmail.com/\n[4]: https://lore.kernel.org/git/cover.1585209554.git.liu.denton@gmail.com/\n[5]: https://lore.kernel.org/git/cover.1587372771.git.liu.denton@gmail.com/\n\nDenton Liu (4):\n  lib-submodule-update: add space after function name\n  lib-submodule-update: consolidate --recurse-submodules\n  lib-submodule-update: prepend \"git\" to $command\n  lib-submodule-update: pass OVERWRITING_FAIL\n\n t/lib-submodule-update.sh        | 55 ++++++++++++++++++++++----------\n t/t1013-read-tree-submodule.sh   |  4 +--\n t/t2013-checkout-submodule.sh    |  4 +--\n t/t3426-rebase-submodule.sh      |  8 ++---\n t/t3512-cherry-pick-submodule.sh |  2 +-\n t/t3513-revert-submodule.sh      |  7 +++-\n t/t3906-stash-submodule.sh       |  8 +++--\n t/t4137-apply-submodule.sh       | 10 +++---\n t/t4255-am-submodule.sh          | 10 +++---\n t/t5572-pull-submodule.sh        | 16 +++++-----\n t/t6041-bisect-submodule.sh      |  8 +++--\n t/t7112-reset-submodule.sh       |  6 ++--\n t/t7613-merge-submodule.sh       |  8 ++---\n 13 files changed, 92 insertions(+), 54 deletions(-)\n\nRange-diff against v1:\n1:  f148526dae = 1:  ba2f642e0f lib-submodule-update: add space after function name\n2:  b7d7d0d761 = 2:  16d0a3eb9a lib-submodule-update: consolidate --recurse-submodules\n3:  4922e75f2a = 3:  578bab6f1a lib-submodule-update: prepend \"git\" to $command\n4:  a0a8fbd881 ! 4:  48598e3f98 lib-submodule-update: pass OVERWRITING_FAIL\n    @@ Commit message\n         with a file buffer so that the return code of the first command is not\n         lost.\n     \n    -    This patch can be better viewed with `--ignore-all-space`.\n    -\n      ## t/lib-submodule-update.sh ##\n     @@ t/lib-submodule-update.sh: test_submodule_content () {\n      # a removed submodule.\n    @@ t/t3513-revert-submodule.sh: git_revert () {\n      \tgit status -su >expect &&\n      \tls -1pR * >>expect &&\n      \ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n    --\tgit checkout \"$1\" &&\n    --\tgit revert HEAD &&\n    --\trm -rf * &&\n    --\ttar xf \"$TRASH_DIRECTORY/tmp.tar\" &&\n    --\tgit status -su >actual &&\n    --\tls -1pR * >>actual &&\n    --\ttest_cmp expect actual &&\n    --\tgit revert HEAD\n     +\t$OVERWRITING_FAIL git checkout \"$1\" &&\n    -+\tif test -z \"$OVERWRITING_FAIL\"\n    ++\tif test -n \"$OVERWRITING_FAIL\"\n     +\tthen\n    -+\t\tgit checkout \"$1\" &&\n    -+\t\tgit revert HEAD &&\n    -+\t\trm -rf * &&\n    -+\t\ttar xf \"$TRASH_DIRECTORY/tmp.tar\" &&\n    -+\t\tgit status -su >actual &&\n    -+\t\tls -1pR * >>actual &&\n    -+\t\ttest_cmp expect actual &&\n    -+\t\tgit revert HEAD\n    -+\tfi\n    - }\n    - \n    - KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n    ++\t\treturn\n    ++\tfi &&\n    + \tgit checkout \"$1\" &&\n    + \tgit revert HEAD &&\n    + \trm -rf * &&\n     \n      ## t/t3906-stash-submodule.sh ##\n     @@ t/t3906-stash-submodule.sh: test_description='stash can handle submodules'\n    @@ t/t3906-stash-submodule.sh: test_description='stash can handle submodules'\n      \tgit status -su >expect &&\n      \tls -1pR * >>expect &&\n     -\tgit read-tree -u -m \"$1\" &&\n    --\tgit stash &&\n    --\tgit status -su >actual &&\n    --\tls -1pR * >>actual &&\n    --\ttest_cmp expect actual &&\n    --\tgit stash apply\n     +\t$OVERWRITING_FAIL git read-tree -u -m \"$1\" &&\n    -+\tif test -z \"$OVERWRITING_FAIL\"\n    ++\tif test -n \"$OVERWRITING_FAIL\"\n     +\tthen\n    -+\t\tgit stash &&\n    -+\t\tgit status -su >actual &&\n    -+\t\tls -1pR * >>actual &&\n    -+\t\ttest_cmp expect actual &&\n    -+\t\tgit stash apply\n    -+\tfi\n    - }\n    - \n    - KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES=1\n    ++\t\treturn\n    ++\tfi &&\n    + \tgit stash &&\n    + \tgit status -su >actual &&\n    + \tls -1pR * >>actual &&\n     \n      ## t/t4137-apply-submodule.sh ##\n     @@ t/t4137-apply-submodule.sh: test_description='git apply handling submodules'\n    @@ t/t6041-bisect-submodule.sh: git_bisect () {\n      \ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n      \tGOOD=$(git rev-parse --verify HEAD) &&\n     -\tgit checkout \"$1\" &&\n    --\techo \"foo\" >bar &&\n    --\tgit add bar &&\n    --\tgit commit -m \"bisect bad\" &&\n    --\tBAD=$(git rev-parse --verify HEAD) &&\n    --\tgit reset --hard HEAD^^ &&\n    --\tgit submodule update &&\n    --\tgit bisect start &&\n    --\tgit bisect good $GOOD &&\n    --\trm -rf * &&\n    --\ttar xf \"$TRASH_DIRECTORY/tmp.tar\" &&\n    --\tgit status -su >actual &&\n    --\tls -1pR * >>actual &&\n    --\ttest_cmp expect actual &&\n    --\tgit bisect bad $BAD\n     +\t$OVERWRITING_FAIL git checkout \"$1\" &&\n    -+\tif test -z \"$OVERWRITING_FAIL\"\n    ++\tif test -n \"$OVERWRITING_FAIL\"\n     +\tthen\n    -+\t\techo \"foo\" >bar &&\n    -+\t\tgit add bar &&\n    -+\t\tgit commit -m \"bisect bad\" &&\n    -+\t\tBAD=$(git rev-parse --verify HEAD) &&\n    -+\t\tgit reset --hard HEAD^^ &&\n    -+\t\tgit submodule update &&\n    -+\t\tgit bisect start &&\n    -+\t\tgit bisect good $GOOD &&\n    -+\t\trm -rf * &&\n    -+\t\ttar xf \"$TRASH_DIRECTORY/tmp.tar\" &&\n    -+\t\tgit status -su >actual &&\n    -+\t\tls -1pR * >>actual &&\n    -+\t\ttest_cmp expect actual &&\n    -+\t\tgit bisect bad $BAD\n    -+\tfi\n    - }\n    - \n    - test_submodule_switch_func \"git_bisect\"\n    ++\t\treturn\n    ++\tfi &&\n    + \techo \"foo\" >bar &&\n    + \tgit add bar &&\n    + \tgit commit -m \"bisect bad\" &&\n-- \n2.27.0.rc0.114.g141fe7d276\n\n"},{"id":"398312","messageId":"ba2f642e0f505730d5d740207128036448787c8c.1590019226.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1590019226.git.liu.denton@gmail.com","subject":"[PATCH v2 1/4] lib-submodule-update: add space after function name","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-05-21T00:24:15Z","receivedAt":"2020-05-21T00:24:48Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"In the shell scripts in this codebase, the usual style is to include a\nspace between the function name and the (). Add these missing spaces to\nconform to the usual style of the code.\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\n t/lib-submodule-update.sh | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 1dd17fc03e..122554acd6 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -183,7 +183,7 @@ test_git_directory_is_unchanged () {\n \t)\n }\n \n-test_git_directory_exists() {\n+test_git_directory_exists () {\n \ttest -e \".git/modules/$1\" &&\n \tif test -f sub1/.git\n \tthen\n@@ -309,7 +309,7 @@ test_submodule_content () {\n \n # Internal function; use test_submodule_switch() or\n # test_submodule_forced_switch() instead.\n-test_submodule_switch_common() {\n+test_submodule_switch_common () {\n \tcommand=\"$1\"\n \t######################### Appearing submodule #########################\n \t# Switching to a commit letting a submodule appear creates empty dir ...\n@@ -629,7 +629,7 @@ test_submodule_forced_switch () {\n \n # Internal function; use test_submodule_switch_recursing_with_args() or\n # test_submodule_forced_switch_recursing_with_args() instead.\n-test_submodule_recursing_with_args_common() {\n+test_submodule_recursing_with_args_common () {\n \tcommand=\"$1\"\n \n \t######################### Appearing submodule #########################\n-- \n2.27.0.rc0.114.g141fe7d276\n\n"},{"id":"398313","messageId":"16d0a3eb9ac8dcda701433a9e67cde5103949432.1590019226.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1590019226.git.liu.denton@gmail.com","subject":"[PATCH v2 2/4] lib-submodule-update: consolidate --recurse-submodules","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-05-21T00:24:16Z","receivedAt":"2020-05-21T00:24:49Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"Both test_submodule_switch_recursing_with_args() and\ntest_submodule_forced_switch_recursing_with_args() call the internal\nfunction test_submodule_recursing_with_args_common() with the final\nargument of `--recurse-submodules`. Consolidate this duplication by\nappending the argument in test_submodule_recursing_with_args_common().\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\n t/lib-submodule-update.sh | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 122554acd6..bb36287803 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -630,7 +630,7 @@ test_submodule_forced_switch () {\n # Internal function; use test_submodule_switch_recursing_with_args() or\n # test_submodule_forced_switch_recursing_with_args() instead.\n test_submodule_recursing_with_args_common () {\n-\tcommand=\"$1\"\n+\tcommand=\"$1 --recurse-submodules\"\n \n \t######################### Appearing submodule #########################\n \t# Switching to a commit letting a submodule appear checks it out ...\n@@ -809,7 +809,7 @@ test_submodule_recursing_with_args_common () {\n # test_submodule_switch_recursing_with_args \"$GIT_COMMAND\"\n test_submodule_switch_recursing_with_args () {\n \tcmd_args=\"$1\"\n-\tcommand=\"git $cmd_args --recurse-submodules\"\n+\tcommand=\"git $cmd_args\"\n \ttest_submodule_recursing_with_args_common \"$command\"\n \n \tRESULTDS=success\n@@ -927,7 +927,7 @@ test_submodule_switch_recursing_with_args () {\n # away local changes in the superproject is allowed.\n test_submodule_forced_switch_recursing_with_args () {\n \tcmd_args=\"$1\"\n-\tcommand=\"git $cmd_args --recurse-submodules\"\n+\tcommand=\"git $cmd_args\"\n \ttest_submodule_recursing_with_args_common \"$command\"\n \n \tRESULT=success\n-- \n2.27.0.rc0.114.g141fe7d276\n\n"},{"id":"398314","messageId":"578bab6f1af351fd3721d56bea78abec6c9ae2f9.1590019226.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1590019226.git.liu.denton@gmail.com","subject":"[PATCH v2 3/4] lib-submodule-update: prepend \"git\" to $command","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-05-21T00:24:17Z","receivedAt":"2020-05-21T00:24:51Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"Since all invocations of test_submodule_forced_switch() are git\ncommands, automatically prepend \"git\" before invoking\ntest_submodule_switch_common().\n\nSimilarly, many invocations of test_submodule_switch() are also git\ncommands so automatically prepend \"git\" before invoking\ntest_submodule_switch_common() as well.\n\nFinally, for invocations of test_submodule_switch() that invoke a custom\nfunction, rename the old function to test_submodule_switch_func().\n\nThis is necessary because in a future commit, we will be adding some\nlogic that needs to distinguish between an invocation of a plain git\ncomamnd and an invocation of a test helper function.\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\n t/lib-submodule-update.sh        | 14 +++++++++-----\n t/t1013-read-tree-submodule.sh   |  4 ++--\n t/t2013-checkout-submodule.sh    |  4 ++--\n t/t3426-rebase-submodule.sh      |  4 ++--\n t/t3512-cherry-pick-submodule.sh |  2 +-\n t/t3513-revert-submodule.sh      |  2 +-\n t/t3906-stash-submodule.sh       |  2 +-\n t/t4137-apply-submodule.sh       |  4 ++--\n t/t4255-am-submodule.sh          |  4 ++--\n t/t5572-pull-submodule.sh        |  8 ++++----\n t/t6041-bisect-submodule.sh      |  2 +-\n t/t7112-reset-submodule.sh       |  6 +++---\n t/t7613-merge-submodule.sh       |  8 ++++----\n 13 files changed, 34 insertions(+), 30 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex bb36287803..fb6c0f3d4f 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -307,8 +307,8 @@ test_submodule_content () {\n # to protect the history!\n #\n \n-# Internal function; use test_submodule_switch() or\n-# test_submodule_forced_switch() instead.\n+# Internal function; use test_submodule_switch_func(), test_submodule_switch_func(),\n+# or test_submodule_forced_switch() instead.\n test_submodule_switch_common () {\n \tcommand=\"$1\"\n \t######################### Appearing submodule #########################\n@@ -566,8 +566,8 @@ test_submodule_switch_common () {\n #   # Do something here that updates the worktree and index to match target,\n #   # but not any submodule directories.\n # }\n-# test_submodule_switch \"my_func\"\n-test_submodule_switch () {\n+# test_submodule_switch_func \"my_func\"\n+test_submodule_switch_func () {\n \tcommand=\"$1\"\n \ttest_submodule_switch_common \"$command\"\n \n@@ -587,12 +587,16 @@ test_submodule_switch () {\n \t'\n }\n \n+test_submodule_switch () {\n+\ttest_submodule_switch_func \"git $1\"\n+}\n+\n # Same as test_submodule_switch(), except that throwing away local changes in\n # the superproject is allowed.\n test_submodule_forced_switch () {\n \tcommand=\"$1\"\n \tKNOWN_FAILURE_FORCED_SWITCH_TESTS=1\n-\ttest_submodule_switch_common \"$command\"\n+\ttest_submodule_switch_common \"git $command\"\n \n \t# When forced, a file in the superproject does not prevent creating a\n \t# submodule of the same name.\ndiff --git a/t/t1013-read-tree-submodule.sh b/t/t1013-read-tree-submodule.sh\nindex 91a6fafcb4..b6df7444c0 100755\n--- a/t/t1013-read-tree-submodule.sh\n+++ b/t/t1013-read-tree-submodule.sh\n@@ -12,8 +12,8 @@ test_submodule_switch_recursing_with_args \"read-tree -u -m\"\n \n test_submodule_forced_switch_recursing_with_args \"read-tree -u --reset\"\n \n-test_submodule_switch \"git read-tree -u -m\"\n+test_submodule_switch \"read-tree -u -m\"\n \n-test_submodule_forced_switch \"git read-tree -u --reset\"\n+test_submodule_forced_switch \"read-tree -u --reset\"\n \n test_done\ndiff --git a/t/t2013-checkout-submodule.sh b/t/t2013-checkout-submodule.sh\nindex 8f86b5f4b2..b2bdd1fcb4 100755\n--- a/t/t2013-checkout-submodule.sh\n+++ b/t/t2013-checkout-submodule.sh\n@@ -68,8 +68,8 @@ test_submodule_switch_recursing_with_args \"checkout\"\n \n test_submodule_forced_switch_recursing_with_args \"checkout -f\"\n \n-test_submodule_switch \"git checkout\"\n+test_submodule_switch \"checkout\"\n \n-test_submodule_forced_switch \"git checkout -f\"\n+test_submodule_forced_switch \"checkout -f\"\n \n test_done\ndiff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh\nindex a2bba04ba9..788605ccc0 100755\n--- a/t/t3426-rebase-submodule.sh\n+++ b/t/t3426-rebase-submodule.sh\n@@ -20,7 +20,7 @@ git_rebase () {\n \tgit rebase \"$1\"\n }\n \n-test_submodule_switch \"git_rebase\"\n+test_submodule_switch_func \"git_rebase\"\n \n git_rebase_interactive () {\n \tgit status -su >expect &&\n@@ -38,7 +38,7 @@ git_rebase_interactive () {\n \tgit rebase -i \"$1\"\n }\n \n-test_submodule_switch \"git_rebase_interactive\"\n+test_submodule_switch_func \"git_rebase_interactive\"\n \n test_expect_success 'rebase interactive ignores modified submodules' '\n \ttest_when_finished \"rm -rf super sub\" &&\ndiff --git a/t/t3512-cherry-pick-submodule.sh b/t/t3512-cherry-pick-submodule.sh\nindex bd78287841..6ece1d8573 100755\n--- a/t/t3512-cherry-pick-submodule.sh\n+++ b/t/t3512-cherry-pick-submodule.sh\n@@ -7,7 +7,7 @@ test_description='cherry-pick can handle submodules'\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-test_submodule_switch \"git cherry-pick\"\n+test_submodule_switch \"cherry-pick\"\n \n test_expect_success 'unrelated submodule/file conflict is ignored' '\n \ttest_create_repo sub &&\ndiff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh\nindex 5e39fcdb66..95a7f64471 100755\n--- a/t/t3513-revert-submodule.sh\n+++ b/t/t3513-revert-submodule.sh\n@@ -26,6 +26,6 @@ git_revert () {\n }\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-test_submodule_switch \"git_revert\"\n+test_submodule_switch_func \"git_revert\"\n \n test_done\ndiff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh\nindex b93d1d74da..6a7e801ca0 100755\n--- a/t/t3906-stash-submodule.sh\n+++ b/t/t3906-stash-submodule.sh\n@@ -19,7 +19,7 @@ git_stash () {\n KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES=1\n KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1\n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-test_submodule_switch \"git_stash\"\n+test_submodule_switch_func \"git_stash\"\n \n setup_basic () {\n \ttest_when_finished \"rm -rf main sub\" &&\ndiff --git a/t/t4137-apply-submodule.sh b/t/t4137-apply-submodule.sh\nindex a9bd40a6d0..b645e303a0 100755\n--- a/t/t4137-apply-submodule.sh\n+++ b/t/t4137-apply-submodule.sh\n@@ -9,12 +9,12 @@ apply_index () {\n \tgit diff --ignore-submodules=dirty \"..$1\" | git apply --index -\n }\n \n-test_submodule_switch \"apply_index\"\n+test_submodule_switch_func \"apply_index\"\n \n apply_3way () {\n \tgit diff --ignore-submodules=dirty \"..$1\" | git apply --3way -\n }\n \n-test_submodule_switch \"apply_3way\"\n+test_submodule_switch_func \"apply_3way\"\n \n test_done\ndiff --git a/t/t4255-am-submodule.sh b/t/t4255-am-submodule.sh\nindex 0ba8194403..1b179d5f45 100755\n--- a/t/t4255-am-submodule.sh\n+++ b/t/t4255-am-submodule.sh\n@@ -9,14 +9,14 @@ am () {\n \tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am -\n }\n \n-test_submodule_switch \"am\"\n+test_submodule_switch_func \"am\"\n \n am_3way () {\n \tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am --3way -\n }\n \n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-test_submodule_switch \"am_3way\"\n+test_submodule_switch_func \"am_3way\"\n \n test_expect_success 'setup diff.submodule' '\n \ttest_commit one &&\ndiff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh\nindex f916729a12..f911bf631e 100755\n--- a/t/t5572-pull-submodule.sh\n+++ b/t/t5572-pull-submodule.sh\n@@ -17,21 +17,21 @@ git_pull () {\n }\n \n # pulls without conflicts\n-test_submodule_switch \"git_pull\"\n+test_submodule_switch_func \"git_pull\"\n \n git_pull_ff () {\n \treset_branch_to_HEAD \"$1\" &&\n \tgit pull --ff\n }\n \n-test_submodule_switch \"git_pull_ff\"\n+test_submodule_switch_func \"git_pull_ff\"\n \n git_pull_ff_only () {\n \treset_branch_to_HEAD \"$1\" &&\n \tgit pull --ff-only\n }\n \n-test_submodule_switch \"git_pull_ff_only\"\n+test_submodule_switch_func \"git_pull_ff_only\"\n \n git_pull_noff () {\n \treset_branch_to_HEAD \"$1\" &&\n@@ -40,7 +40,7 @@ git_pull_noff () {\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-test_submodule_switch \"git_pull_noff\"\n+test_submodule_switch_func \"git_pull_noff\"\n \n test_expect_success 'pull --recurse-submodule setup' '\n \ttest_create_repo child &&\ndiff --git a/t/t6041-bisect-submodule.sh b/t/t6041-bisect-submodule.sh\nindex 62b8a2e7bb..0e0cdf638d 100755\n--- a/t/t6041-bisect-submodule.sh\n+++ b/t/t6041-bisect-submodule.sh\n@@ -27,6 +27,6 @@ git_bisect () {\n \tgit bisect bad $BAD\n }\n \n-test_submodule_switch \"git_bisect\"\n+test_submodule_switch_func \"git_bisect\"\n \n test_done\ndiff --git a/t/t7112-reset-submodule.sh b/t/t7112-reset-submodule.sh\nindex a1cb9ff858..8741b665c9 100755\n--- a/t/t7112-reset-submodule.sh\n+++ b/t/t7112-reset-submodule.sh\n@@ -13,10 +13,10 @@ test_submodule_switch_recursing_with_args \"reset --keep\"\n \n test_submodule_forced_switch_recursing_with_args \"reset --hard\"\n \n-test_submodule_switch \"git reset --keep\"\n+test_submodule_switch \"reset --keep\"\n \n-test_submodule_switch \"git reset --merge\"\n+test_submodule_switch \"reset --merge\"\n \n-test_submodule_forced_switch \"git reset --hard\"\n+test_submodule_forced_switch \"reset --hard\"\n \n test_done\ndiff --git a/t/t7613-merge-submodule.sh b/t/t7613-merge-submodule.sh\nindex d1e9fcc781..04bf4be7d7 100755\n--- a/t/t7613-merge-submodule.sh\n+++ b/t/t7613-merge-submodule.sh\n@@ -6,14 +6,14 @@ test_description='merge can handle submodules'\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n # merges without conflicts\n-test_submodule_switch \"git merge\"\n+test_submodule_switch \"merge\"\n \n-test_submodule_switch \"git merge --ff\"\n+test_submodule_switch \"merge --ff\"\n \n-test_submodule_switch \"git merge --ff-only\"\n+test_submodule_switch \"merge --ff-only\"\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-test_submodule_switch \"git merge --no-ff\"\n+test_submodule_switch \"merge --no-ff\"\n \n test_done\n-- \n2.27.0.rc0.114.g141fe7d276\n\n"},{"id":"398315","messageId":"48598e3f9859dc525ec878cd7f3eaadee8bb61b1.1590019226.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1590019226.git.liu.denton@gmail.com","subject":"[PATCH v2 4/4] lib-submodule-update: pass OVERWRITING_FAIL","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-05-21T00:24:18Z","receivedAt":"2020-05-21T00:24:52Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"We are using `test_must_fail $command`. However, $command is not\nnecessarily a git command; it could be a test helper function.\n\nIn an effort to stop using test_must_fail with non-git commands, instead\nof invoking `test_must_fail $command`, run\n`OVERWRITING_FAIL=test_must_fail $command` instead in\ntest_submodule_switch_common().\n\nIn the case where $command is a git command,\ntest_submodule_switch_common() is called by one of\ntest_submodule_switch() or test_submodule_forced_switch(). In those two\nfunctions, pass $command like this:\n\n\ttest_submodule_switch_common \"eval \\$OVERWRITING_FAIL git $command\"\n\nWhen $command is a helper function, the parent function calling\ntest_submodule_switch_common() is test_submodule_switch_func(). For all\ntest_submodule_switch_func() invocations, increase the granularity of\nthe argument test helper function by prefixing the git invocation which is\nmeant to fail with $OVERWRITING_FAIL like this:\n\n\t$OVERWRITING_FAIL git checkout \"$1\"\n\nThis is useful because currently, when we run a test helper function, we\njust mark the whole thing as `test_must_fail`. However, it's possible\nthat the helper function might fail earlier or later than expected due\nto an introduced bug. If this happens, then the test case will still\nreport as passing but it should really be marked as failing since it\ndidn't actually display the intended behaviour.\n\nWhile we're at it, some helper functions have git commands piping into\nanother git command. Break these pipes up into two separate invocations\nwith a file buffer so that the return code of the first command is not\nlost.\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\n t/lib-submodule-update.sh   | 33 +++++++++++++++++++++++++--------\n t/t3426-rebase-submodule.sh |  4 ++--\n t/t3513-revert-submodule.sh |  5 +++++\n t/t3906-stash-submodule.sh  |  6 +++++-\n t/t4137-apply-submodule.sh  |  6 ++++--\n t/t4255-am-submodule.sh     |  6 ++++--\n t/t5572-pull-submodule.sh   |  8 ++++----\n t/t6041-bisect-submodule.sh |  6 +++++-\n 8 files changed, 54 insertions(+), 20 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex fb6c0f3d4f..a0274c03de 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -304,12 +304,15 @@ test_submodule_content () {\n # a removed submodule.\n #\n # Removing a submodule containing a .git directory must fail even when forced\n-# to protect the history!\n+# to protect the history! If we are testing this case,\n+# OVERWRITING_FAIL=test_must_fail, otherwise OVERWRITING_FAIL will be the empty\n+# string.\n #\n \n # Internal function; use test_submodule_switch_func(), test_submodule_switch_func(),\n # or test_submodule_forced_switch() instead.\n test_submodule_switch_common () {\n+\tOVERWRITING_FAIL=\n \tcommand=\"$1\"\n \t######################### Appearing submodule #########################\n \t# Switching to a commit letting a submodule appear creates empty dir ...\n@@ -443,7 +446,9 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\tOVERWRITING_FAIL=test_must_fail &&\n+\t\t\t$command replace_sub1_with_directory &&\n+\t\t\tOVERWRITING_FAIL= &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -456,7 +461,9 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\tOVERWRITING_FAIL=test_must_fail &&\n+\t\t\t$command replace_sub1_with_directory &&\n+\t\t\tOVERWRITING_FAIL= &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -470,7 +477,9 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\tOVERWRITING_FAIL=test_must_fail &&\n+\t\t\t$command replace_sub1_with_file &&\n+\t\t\tOVERWRITING_FAIL= &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -484,7 +493,9 @@ test_submodule_switch_common () {\n \t\t\tcd submodule_update &&\n \t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n \t\t\treplace_gitfile_with_git_dir sub1 &&\n-\t\t\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\tOVERWRITING_FAIL=test_must_fail &&\n+\t\t\t$command replace_sub1_with_file &&\n+\t\t\tOVERWRITING_FAIL= &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -559,6 +570,11 @@ test_submodule_switch_common () {\n # conditions, set the appropriate KNOWN_FAILURE_* variable used in the tests\n # below to 1.\n #\n+# Removing a submodule containing a .git directory must fail even when forced\n+# to protect the history! If we are testing this case,\n+# OVERWRITING_FAIL=test_must_fail, otherwise OVERWRITING_FAIL will be the empty\n+# string.\n+#\n # Use as follows:\n #\n # my_func () {\n@@ -568,6 +584,7 @@ test_submodule_switch_common () {\n # }\n # test_submodule_switch_func \"my_func\"\n test_submodule_switch_func () {\n+\tOVERWRITING_FAIL=\n \tcommand=\"$1\"\n \ttest_submodule_switch_common \"$command\"\n \n@@ -580,7 +597,7 @@ test_submodule_switch_func () {\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\tOVERWRITING_FAIL=test_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@@ -588,7 +605,7 @@ test_submodule_switch_func () {\n }\n \n test_submodule_switch () {\n-\ttest_submodule_switch_func \"git $1\"\n+\ttest_submodule_switch_func \"eval \\$OVERWRITING_FAIL git $1\"\n }\n \n # Same as test_submodule_switch(), except that throwing away local changes in\n@@ -596,7 +613,7 @@ test_submodule_switch () {\n test_submodule_forced_switch () {\n \tcommand=\"$1\"\n \tKNOWN_FAILURE_FORCED_SWITCH_TESTS=1\n-\ttest_submodule_switch_common \"git $command\"\n+\ttest_submodule_switch_common \"eval \\$OVERWRITING_FAIL git $command\"\n \n \t# When forced, a file in the superproject does not prevent creating a\n \t# submodule of the same name.\ndiff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh\nindex 788605ccc0..c6a7f584ed 100755\n--- a/t/t3426-rebase-submodule.sh\n+++ b/t/t3426-rebase-submodule.sh\n@@ -17,7 +17,7 @@ git_rebase () {\n \tgit status -su >actual &&\n \tls -1pR * >>actual &&\n \ttest_cmp expect actual &&\n-\tgit rebase \"$1\"\n+\t$OVERWRITING_FAIL git rebase \"$1\"\n }\n \n test_submodule_switch_func \"git_rebase\"\n@@ -35,7 +35,7 @@ git_rebase_interactive () {\n \ttest_cmp expect actual &&\n \tset_fake_editor &&\n \techo \"fake-editor.sh\" >.git/info/exclude &&\n-\tgit rebase -i \"$1\"\n+\t$OVERWRITING_FAIL git rebase -i \"$1\"\n }\n \n test_submodule_switch_func \"git_rebase_interactive\"\ndiff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh\nindex 95a7f64471..e41f0f2009 100755\n--- a/t/t3513-revert-submodule.sh\n+++ b/t/t3513-revert-submodule.sh\n@@ -15,6 +15,11 @@ git_revert () {\n \tgit status -su >expect &&\n \tls -1pR * >>expect &&\n \ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n+\t$OVERWRITING_FAIL git checkout \"$1\" &&\n+\tif test -n \"$OVERWRITING_FAIL\"\n+\tthen\n+\t\treturn\n+\tfi &&\n \tgit checkout \"$1\" &&\n \tgit revert HEAD &&\n \trm -rf * &&\ndiff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh\nindex 6a7e801ca0..6e8dac9669 100755\n--- a/t/t3906-stash-submodule.sh\n+++ b/t/t3906-stash-submodule.sh\n@@ -8,7 +8,11 @@ test_description='stash can handle submodules'\n git_stash () {\n \tgit status -su >expect &&\n \tls -1pR * >>expect &&\n-\tgit read-tree -u -m \"$1\" &&\n+\t$OVERWRITING_FAIL git read-tree -u -m \"$1\" &&\n+\tif test -n \"$OVERWRITING_FAIL\"\n+\tthen\n+\t\treturn\n+\tfi &&\n \tgit stash &&\n \tgit status -su >actual &&\n \tls -1pR * >>actual &&\ndiff --git a/t/t4137-apply-submodule.sh b/t/t4137-apply-submodule.sh\nindex b645e303a0..dd08d9e1a4 100755\n--- a/t/t4137-apply-submodule.sh\n+++ b/t/t4137-apply-submodule.sh\n@@ -6,13 +6,15 @@ test_description='git apply handling submodules'\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n apply_index () {\n-\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --index -\n+\tgit diff --ignore-submodules=dirty \"..$1\" >diff &&\n+\t$OVERWRITING_FAIL git apply --index - <diff\n }\n \n test_submodule_switch_func \"apply_index\"\n \n apply_3way () {\n-\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --3way -\n+\tgit diff --ignore-submodules=dirty \"..$1\" >diff &&\n+\t$OVERWRITING_FAIL git apply --3way - <diff\n }\n \n test_submodule_switch_func \"apply_3way\"\ndiff --git a/t/t4255-am-submodule.sh b/t/t4255-am-submodule.sh\nindex 1b179d5f45..b0fe78a956 100755\n--- a/t/t4255-am-submodule.sh\n+++ b/t/t4255-am-submodule.sh\n@@ -6,13 +6,15 @@ test_description='git am handling submodules'\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n am () {\n-\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am -\n+\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" >patch &&\n+\t$OVERWRITING_FAIL git am - <patch\n }\n \n test_submodule_switch_func \"am\"\n \n am_3way () {\n-\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am --3way -\n+\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" >patch &&\n+\t$OVERWRITING_FAIL git am --3way - <patch\n }\n \n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\ndiff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh\nindex f911bf631e..4dd9913b6b 100755\n--- a/t/t5572-pull-submodule.sh\n+++ b/t/t5572-pull-submodule.sh\n@@ -13,7 +13,7 @@ reset_branch_to_HEAD () {\n \n git_pull () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull\n+\t$OVERWRITING_FAIL git pull\n }\n \n # pulls without conflicts\n@@ -21,21 +21,21 @@ test_submodule_switch_func \"git_pull\"\n \n git_pull_ff () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --ff\n+\t$OVERWRITING_FAIL git pull --ff\n }\n \n test_submodule_switch_func \"git_pull_ff\"\n \n git_pull_ff_only () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --ff-only\n+\t$OVERWRITING_FAIL git pull --ff-only\n }\n \n test_submodule_switch_func \"git_pull_ff_only\"\n \n git_pull_noff () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --no-ff\n+\t$OVERWRITING_FAIL git pull --no-ff\n }\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\ndiff --git a/t/t6041-bisect-submodule.sh b/t/t6041-bisect-submodule.sh\nindex 0e0cdf638d..759890b721 100755\n--- a/t/t6041-bisect-submodule.sh\n+++ b/t/t6041-bisect-submodule.sh\n@@ -10,7 +10,11 @@ git_bisect () {\n \tls -1pR * >>expect &&\n \ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n \tGOOD=$(git rev-parse --verify HEAD) &&\n-\tgit checkout \"$1\" &&\n+\t$OVERWRITING_FAIL git checkout \"$1\" &&\n+\tif test -n \"$OVERWRITING_FAIL\"\n+\tthen\n+\t\treturn\n+\tfi &&\n \techo \"foo\" >bar &&\n \tgit add bar &&\n \tgit commit -m \"bisect bad\" &&\n-- \n2.27.0.rc0.114.g141fe7d276\n\n"},{"id":"398348","messageId":"1746f977-64cc-ede0-04f7-7cfd1afb1691@iee.email","threadId":"53350","inReplyTo":"578bab6f1af351fd3721d56bea78abec6c9ae2f9.1590019226.git.liu.denton@gmail.com","subject":"Re: [PATCH v2 3/4] lib-submodule-update: prepend \"git\" to $command","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.email","sentAt":"2020-05-21T10:39:48Z","receivedAt":"2020-05-21T10:40:00Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"Hi Denton,\n\nOn 21/05/2020 01:24, Denton Liu wrote:\n> Since all invocations of test_submodule_forced_switch() are git\n> commands, automatically prepend \"git\" before invoking\n> test_submodule_switch_common().\n>\n> Similarly, many invocations of test_submodule_switch() are also git\n> commands so automatically prepend \"git\" before invoking\n> test_submodule_switch_common() as well.\n>\n> Finally, for invocations of test_submodule_switch() that invoke a custom\n> function, rename the old function to test_submodule_switch_func().\n>\n> This is necessary because in a future commit, we will be adding some\n> logic that needs to distinguish between an invocation of a plain git\n> comamnd and an invocation of a test helper function.\n>\n> Signed-off-by: Denton Liu <liu.denton@gmail.com>\n> ---\n>  t/lib-submodule-update.sh        | 14 +++++++++-----\n>  t/t1013-read-tree-submodule.sh   |  4 ++--\n>  t/t2013-checkout-submodule.sh    |  4 ++--\n>  t/t3426-rebase-submodule.sh      |  4 ++--\n>  t/t3512-cherry-pick-submodule.sh |  2 +-\n>  t/t3513-revert-submodule.sh      |  2 +-\n>  t/t3906-stash-submodule.sh       |  2 +-\n>  t/t4137-apply-submodule.sh       |  4 ++--\n>  t/t4255-am-submodule.sh          |  4 ++--\n>  t/t5572-pull-submodule.sh        |  8 ++++----\n>  t/t6041-bisect-submodule.sh      |  2 +-\n>  t/t7112-reset-submodule.sh       |  6 +++---\n>  t/t7613-merge-submodule.sh       |  8 ++++----\n>  13 files changed, 34 insertions(+), 30 deletions(-)\n>\n> diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\n> index bb36287803..fb6c0f3d4f 100755\n> --- a/t/lib-submodule-update.sh\n> +++ b/t/lib-submodule-update.sh\n> @@ -307,8 +307,8 @@ test_submodule_content () {\n>  # to protect the history!\n>  #\n>  \n> -# Internal function; use test_submodule_switch() or\n> -# test_submodule_forced_switch() instead.\n> +# Internal function; use test_submodule_switch_func(), test_submodule_switch_func(),\nIs this an accidental duplication of  test_submodule_switch_func(),?\n(spotted in passing)\n--\nPhilip\n> +# or test_submodule_forced_switch() instead.\n>  test_submodule_switch_common () {\n>  \tcommand=\"$1\"\n>  \t######################### Appearing submodule #########################\n> @@ -566,8 +566,8 @@ test_submodule_switch_common () {\n>  #   # Do something here that updates the worktree and index to match target,\n>  #   # but not any submodule directories.\n>  # }\n> -# test_submodule_switch \"my_func\"\n> -test_submodule_switch () {\n> +# test_submodule_switch_func \"my_func\"\n> +test_submodule_switch_func () {\n>  \tcommand=\"$1\"\n>  \ttest_submodule_switch_common \"$command\"\n>  \n> @@ -587,12 +587,16 @@ test_submodule_switch () {\n>  \t'\n>  }\n>  \n> +test_submodule_switch () {\n> +\ttest_submodule_switch_func \"git $1\"\n> +}\n> +\n>  # Same as test_submodule_switch(), except that throwing away local changes in\n>  # the superproject is allowed.\n>  test_submodule_forced_switch () {\n>  \tcommand=\"$1\"\n>  \tKNOWN_FAILURE_FORCED_SWITCH_TESTS=1\n> -\ttest_submodule_switch_common \"$command\"\n> +\ttest_submodule_switch_common \"git $command\"\n>  \n>  \t# When forced, a file in the superproject does not prevent creating a\n>  \t# submodule of the same name.\n> diff --git a/t/t1013-read-tree-submodule.sh b/t/t1013-read-tree-submodule.sh\n> index 91a6fafcb4..b6df7444c0 100755\n> --- a/t/t1013-read-tree-submodule.sh\n> +++ b/t/t1013-read-tree-submodule.sh\n> @@ -12,8 +12,8 @@ test_submodule_switch_recursing_with_args \"read-tree -u -m\"\n>  \n>  test_submodule_forced_switch_recursing_with_args \"read-tree -u --reset\"\n>  \n> -test_submodule_switch \"git read-tree -u -m\"\n> +test_submodule_switch \"read-tree -u -m\"\n>  \n> -test_submodule_forced_switch \"git read-tree -u --reset\"\n> +test_submodule_forced_switch \"read-tree -u --reset\"\n>  \n>  test_done\n> diff --git a/t/t2013-checkout-submodule.sh b/t/t2013-checkout-submodule.sh\n> index 8f86b5f4b2..b2bdd1fcb4 100755\n> --- a/t/t2013-checkout-submodule.sh\n> +++ b/t/t2013-checkout-submodule.sh\n> @@ -68,8 +68,8 @@ test_submodule_switch_recursing_with_args \"checkout\"\n>  \n>  test_submodule_forced_switch_recursing_with_args \"checkout -f\"\n>  \n> -test_submodule_switch \"git checkout\"\n> +test_submodule_switch \"checkout\"\n>  \n> -test_submodule_forced_switch \"git checkout -f\"\n> +test_submodule_forced_switch \"checkout -f\"\n>  \n>  test_done\n> diff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh\n> index a2bba04ba9..788605ccc0 100755\n> --- a/t/t3426-rebase-submodule.sh\n> +++ b/t/t3426-rebase-submodule.sh\n> @@ -20,7 +20,7 @@ git_rebase () {\n>  \tgit rebase \"$1\"\n>  }\n>  \n> -test_submodule_switch \"git_rebase\"\n> +test_submodule_switch_func \"git_rebase\"\n>  \n>  git_rebase_interactive () {\n>  \tgit status -su >expect &&\n> @@ -38,7 +38,7 @@ git_rebase_interactive () {\n>  \tgit rebase -i \"$1\"\n>  }\n>  \n> -test_submodule_switch \"git_rebase_interactive\"\n> +test_submodule_switch_func \"git_rebase_interactive\"\n>  \n>  test_expect_success 'rebase interactive ignores modified submodules' '\n>  \ttest_when_finished \"rm -rf super sub\" &&\n> diff --git a/t/t3512-cherry-pick-submodule.sh b/t/t3512-cherry-pick-submodule.sh\n> index bd78287841..6ece1d8573 100755\n> --- a/t/t3512-cherry-pick-submodule.sh\n> +++ b/t/t3512-cherry-pick-submodule.sh\n> @@ -7,7 +7,7 @@ test_description='cherry-pick can handle submodules'\n>  \n>  KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n>  KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n> -test_submodule_switch \"git cherry-pick\"\n> +test_submodule_switch \"cherry-pick\"\n>  \n>  test_expect_success 'unrelated submodule/file conflict is ignored' '\n>  \ttest_create_repo sub &&\n> diff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh\n> index 5e39fcdb66..95a7f64471 100755\n> --- a/t/t3513-revert-submodule.sh\n> +++ b/t/t3513-revert-submodule.sh\n> @@ -26,6 +26,6 @@ git_revert () {\n>  }\n>  \n>  KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n> -test_submodule_switch \"git_revert\"\n> +test_submodule_switch_func \"git_revert\"\n>  \n>  test_done\n> diff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh\n> index b93d1d74da..6a7e801ca0 100755\n> --- a/t/t3906-stash-submodule.sh\n> +++ b/t/t3906-stash-submodule.sh\n> @@ -19,7 +19,7 @@ git_stash () {\n>  KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES=1\n>  KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1\n>  KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n> -test_submodule_switch \"git_stash\"\n> +test_submodule_switch_func \"git_stash\"\n>  \n>  setup_basic () {\n>  \ttest_when_finished \"rm -rf main sub\" &&\n> diff --git a/t/t4137-apply-submodule.sh b/t/t4137-apply-submodule.sh\n> index a9bd40a6d0..b645e303a0 100755\n> --- a/t/t4137-apply-submodule.sh\n> +++ b/t/t4137-apply-submodule.sh\n> @@ -9,12 +9,12 @@ apply_index () {\n>  \tgit diff --ignore-submodules=dirty \"..$1\" | git apply --index -\n>  }\n>  \n> -test_submodule_switch \"apply_index\"\n> +test_submodule_switch_func \"apply_index\"\n>  \n>  apply_3way () {\n>  \tgit diff --ignore-submodules=dirty \"..$1\" | git apply --3way -\n>  }\n>  \n> -test_submodule_switch \"apply_3way\"\n> +test_submodule_switch_func \"apply_3way\"\n>  \n>  test_done\n> diff --git a/t/t4255-am-submodule.sh b/t/t4255-am-submodule.sh\n> index 0ba8194403..1b179d5f45 100755\n> --- a/t/t4255-am-submodule.sh\n> +++ b/t/t4255-am-submodule.sh\n> @@ -9,14 +9,14 @@ am () {\n>  \tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am -\n>  }\n>  \n> -test_submodule_switch \"am\"\n> +test_submodule_switch_func \"am\"\n>  \n>  am_3way () {\n>  \tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am --3way -\n>  }\n>  \n>  KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n> -test_submodule_switch \"am_3way\"\n> +test_submodule_switch_func \"am_3way\"\n>  \n>  test_expect_success 'setup diff.submodule' '\n>  \ttest_commit one &&\n> diff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh\n> index f916729a12..f911bf631e 100755\n> --- a/t/t5572-pull-submodule.sh\n> +++ b/t/t5572-pull-submodule.sh\n> @@ -17,21 +17,21 @@ git_pull () {\n>  }\n>  \n>  # pulls without conflicts\n> -test_submodule_switch \"git_pull\"\n> +test_submodule_switch_func \"git_pull\"\n>  \n>  git_pull_ff () {\n>  \treset_branch_to_HEAD \"$1\" &&\n>  \tgit pull --ff\n>  }\n>  \n> -test_submodule_switch \"git_pull_ff\"\n> +test_submodule_switch_func \"git_pull_ff\"\n>  \n>  git_pull_ff_only () {\n>  \treset_branch_to_HEAD \"$1\" &&\n>  \tgit pull --ff-only\n>  }\n>  \n> -test_submodule_switch \"git_pull_ff_only\"\n> +test_submodule_switch_func \"git_pull_ff_only\"\n>  \n>  git_pull_noff () {\n>  \treset_branch_to_HEAD \"$1\" &&\n> @@ -40,7 +40,7 @@ git_pull_noff () {\n>  \n>  KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n>  KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n> -test_submodule_switch \"git_pull_noff\"\n> +test_submodule_switch_func \"git_pull_noff\"\n>  \n>  test_expect_success 'pull --recurse-submodule setup' '\n>  \ttest_create_repo child &&\n> diff --git a/t/t6041-bisect-submodule.sh b/t/t6041-bisect-submodule.sh\n> index 62b8a2e7bb..0e0cdf638d 100755\n> --- a/t/t6041-bisect-submodule.sh\n> +++ b/t/t6041-bisect-submodule.sh\n> @@ -27,6 +27,6 @@ git_bisect () {\n>  \tgit bisect bad $BAD\n>  }\n>  \n> -test_submodule_switch \"git_bisect\"\n> +test_submodule_switch_func \"git_bisect\"\n>  \n>  test_done\n> diff --git a/t/t7112-reset-submodule.sh b/t/t7112-reset-submodule.sh\n> index a1cb9ff858..8741b665c9 100755\n> --- a/t/t7112-reset-submodule.sh\n> +++ b/t/t7112-reset-submodule.sh\n> @@ -13,10 +13,10 @@ test_submodule_switch_recursing_with_args \"reset --keep\"\n>  \n>  test_submodule_forced_switch_recursing_with_args \"reset --hard\"\n>  \n> -test_submodule_switch \"git reset --keep\"\n> +test_submodule_switch \"reset --keep\"\n>  \n> -test_submodule_switch \"git reset --merge\"\n> +test_submodule_switch \"reset --merge\"\n>  \n> -test_submodule_forced_switch \"git reset --hard\"\n> +test_submodule_forced_switch \"reset --hard\"\n>  \n>  test_done\n> diff --git a/t/t7613-merge-submodule.sh b/t/t7613-merge-submodule.sh\n> index d1e9fcc781..04bf4be7d7 100755\n> --- a/t/t7613-merge-submodule.sh\n> +++ b/t/t7613-merge-submodule.sh\n> @@ -6,14 +6,14 @@ test_description='merge can handle submodules'\n>  . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n>  \n>  # merges without conflicts\n> -test_submodule_switch \"git merge\"\n> +test_submodule_switch \"merge\"\n>  \n> -test_submodule_switch \"git merge --ff\"\n> +test_submodule_switch \"merge --ff\"\n>  \n> -test_submodule_switch \"git merge --ff-only\"\n> +test_submodule_switch \"merge --ff-only\"\n>  \n>  KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n>  KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n> -test_submodule_switch \"git merge --no-ff\"\n> +test_submodule_switch \"merge --no-ff\"\n>  \n>  test_done\n\n"},{"id":"398352","messageId":"20200521112545.GB581643@generichostname","threadId":"53350","inReplyTo":"1746f977-64cc-ede0-04f7-7cfd1afb1691@iee.email","subject":"Re: [PATCH v2 3/4] lib-submodule-update: prepend \"git\" to $command","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-05-21T11:25:45Z","receivedAt":"2020-05-21T11:25:50Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"Hi Philip,\n\nOn Thu, May 21, 2020 at 11:39:48AM +0100, Philip Oakley wrote:\n> > diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\n> > index bb36287803..fb6c0f3d4f 100755\n> > --- a/t/lib-submodule-update.sh\n> > +++ b/t/lib-submodule-update.sh\n> > @@ -307,8 +307,8 @@ test_submodule_content () {\n> >  # to protect the history!\n> >  #\n> >  \n> > -# Internal function; use test_submodule_switch() or\n> > -# test_submodule_forced_switch() instead.\n> > +# Internal function; use test_submodule_switch_func(), test_submodule_switch_func(),\n> Is this an accidental duplication of  test_submodule_switch_func(),?\n> (spotted in passing)\n\nThanks, good catch. The second one should be test_submodule_switch().\n\n> --\n> Philip\n"},{"id":"398365","messageId":"xmqq8shlteud.fsf@gitster.c.googlers.com","threadId":"53350","inReplyTo":"cover.1590019226.git.liu.denton@gmail.com","subject":"Re: [PATCH v2 0/4] t: replace incorrect test_must_fail usage (part 5)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-05-21T16:47:22Z","receivedAt":"2020-05-21T16:47:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Denton Liu <liu.denton@gmail.com> writes:\n\n> Hi all,\n>\n> This is mostly a resend of what's currently queued in\n> \"dl/test-must-fail-fixes-5\" except with a tiny bit of cleanup on the tip\n> patch. I'd appreciate a review on this series so that we can finally get\n> rid of that \"Needs review\" on the What's Cooking messages ;)\n\nThanks.  \n\nThe OVERWRITING_FAIL one was the only one I was unhappy about, so it\nwould be good to have more eyeballs on it---perhaps other people\nfind the approach acceptable, or can suggest more readable and\nunderstandable approach.\n\n"},{"id":"398377","messageId":"20200521182928.GA1308647@coredump.intra.peff.net","threadId":"53350","inReplyTo":"48598e3f9859dc525ec878cd7f3eaadee8bb61b1.1590019226.git.liu.denton@gmail.com","subject":"Re: [PATCH v2 4/4] lib-submodule-update: pass OVERWRITING_FAIL","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2020-05-21T18:29:28Z","receivedAt":"2020-05-21T18:29:35Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, May 20, 2020 at 08:24:18PM -0400, Denton Liu wrote:\n\n> We are using `test_must_fail $command`. However, $command is not\n> necessarily a git command; it could be a test helper function.\n>\n> In an effort to stop using test_must_fail with non-git commands, instead\n> of invoking `test_must_fail $command`, run\n> `OVERWRITING_FAIL=test_must_fail $command` instead in\n> test_submodule_switch_common().\n\nI think there are really two separate issues being addressed by this\npatch.\n\nOne is using \"test_must_fail\" with a helper function. IMHO this is not\nsomething we should go too far in trying to deal with. It's mostly a\nstyle issue about how test_must_fail is meant to be used, and there's no\nreal downside if we occasionally use it for a non-git command.\n\nI don't mind cleaning up spots where it's obviously misused, but in this\ncase we're introducing a lot of new complexity to handle the \"sometimes\"\nnature of this call. And I'm not sure it's worth it on its own.\n\n> This is useful because currently, when we run a test helper function, we\n> just mark the whole thing as `test_must_fail`. However, it's possible\n> that the helper function might fail earlier or later than expected due\n> to an introduced bug. If this happens, then the test case will still\n> report as passing but it should really be marked as failing since it\n> didn't actually display the intended behaviour.\n\nNow this second concern I think is much more interesting, because it\nimpacts the test results. And it's really not even about test_must_fail\nin particular, but is a general problem with checking failure in any\ncompound operation. We may expect the early parts to succeed, but the\nlater parts to fail, and we want to tell the difference. And that's true\nwhether you're using \"!\", test_must_fail, etc.\n\nYou solve it here by passing OVERWRITING_FAIL down into the callback\nfunctions. And that does work. But I think it may be easier to\nunderstand if we invert the responsibility. Let the outer caller specify\ntwo callbacks: one for setup/prep that must succeed, and one for a\nsingle operation where we might expect success or failure.\n\nThe changes in lib-submodule-update look something like:\n\n  @@ -326,7 +327,8 @@ test_submodule_switch_common() {\n                  (\n                          cd submodule_update &&\n                          git branch -t add_sub1 origin/add_sub1 &&\n  -                       $command add_sub1 &&\n  +                       $prep add_sub1 &&\n  +                       $command &&\n                          test_superproject_content origin/add_sub1 &&\n                          test_dir_is_empty sub1 &&\n                          git submodule update --init --recursive &&\n\nAnd in the caller we can simplify greatly:\n\n  diff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh\n  index f916729a12..e3ae7c89f1 100755\n  --- a/t/t5572-pull-submodule.sh\n  +++ b/t/t5572-pull-submodule.sh\n  @@ -11,36 +11,13 @@ reset_branch_to_HEAD () {\n   \tgit branch --set-upstream-to=\"origin/$1\" \"$1\"\n   }\n   \n  -git_pull () {\n  -\treset_branch_to_HEAD \"$1\" &&\n  -\tgit pull\n  -}\n  -\n   # pulls without conflicts\n  -test_submodule_switch \"git_pull\"\n  -\n  -git_pull_ff () {\n  -\treset_branch_to_HEAD \"$1\" &&\n  -\tgit pull --ff\n  -}\n  -\n  -test_submodule_switch \"git_pull_ff\"\n  -\n  -git_pull_ff_only () {\n  -\treset_branch_to_HEAD \"$1\" &&\n  -\tgit pull --ff-only\n  -}\n  -\n  -test_submodule_switch \"git_pull_ff_only\"\n  -\n  -git_pull_noff () {\n  -\treset_branch_to_HEAD \"$1\" &&\n  -\tgit pull --no-ff\n  -}\n  -\n  +test_submodule_switch \"reset_branch_to_HEAD\" \"git pull\"\n  +test_submodule_switch \"reset_branch_to_HEAD\" \"git pull -ff\"\n  +test_submodule_switch \"reset_branch_to_HEAD\" \"git pull --ff-only\"\n   KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n   KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n  -test_submodule_switch \"git_pull_noff\"\n  +test_submodule_switch \"reset_branch_to_HEAD\" \"git pull --no-ff\"\n   \n   test_expect_success 'pull --recurse-submodule setup' '\n   \ttest_create_repo child &&\n\nI suspect this approach involves touching more lines than yours (it has\nto add $prep everywhere $command is used). But IMHO the result is much\nsimpler to understand, because there's no spooky-action-at-a-distance\nfrom magic environment variables.\n\nA more complete patch is below, which is enough to get t5572 passing. I\nthink it would need the other test_submodule_switch() function updated,\nand other scripts would need to adapt to the 2-arg style.\n\n-Peff\n"},{"id":"398379","messageId":"20200521183459.GB1308647@coredump.intra.peff.net","threadId":"53350","inReplyTo":"48598e3f9859dc525ec878cd7f3eaadee8bb61b1.1590019226.git.liu.denton@gmail.com","subject":"Re: [PATCH v2 4/4] lib-submodule-update: pass OVERWRITING_FAIL","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2020-05-21T18:34:59Z","receivedAt":"2020-05-21T18:35:02Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, May 20, 2020 at 08:24:18PM -0400, Denton Liu wrote:\n\n>  test_submodule_switch () {\n> -\ttest_submodule_switch_func \"git $1\"\n> +\ttest_submodule_switch_func \"eval \\$OVERWRITING_FAIL git $1\"\n>  }\n> [...]\n>  test_submodule_forced_switch () {\n>  \tcommand=\"$1\"\n>  \tKNOWN_FAILURE_FORCED_SWITCH_TESTS=1\n> -\ttest_submodule_switch_common \"git $command\"\n> +\ttest_submodule_switch_common \"eval \\$OVERWRITING_FAIL git $command\"\n\nThese both subject $1 to an extra layer of shell eval. That may not\nmatter since we seem to only pass basic stuff. It could probably be\navoided with an extra variable (though since we're passing along the\neval to be eval'd, I think it gets tricky), so it may not be worth\naddressing.\n\nThough IMHO it is nicer still if we can avoid the eval altogether by\ndoing something like the prep/command split I suggested in a sibling\nreply.\n\n-Peff\n"},{"id":"398380","messageId":"20200521183536.GA1308489@coredump.intra.peff.net","threadId":"53350","inReplyTo":"xmqq8shlteud.fsf@gitster.c.googlers.com","subject":"Re: [PATCH v2 0/4] t: replace incorrect test_must_fail usage (part 5)","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2020-05-21T18:35:36Z","receivedAt":"2020-05-21T18:35:39Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, May 21, 2020 at 09:47:22AM -0700, Junio C Hamano wrote:\n\n> Denton Liu <liu.denton@gmail.com> writes:\n> \n> > Hi all,\n> >\n> > This is mostly a resend of what's currently queued in\n> > \"dl/test-must-fail-fixes-5\" except with a tiny bit of cleanup on the tip\n> > patch. I'd appreciate a review on this series so that we can finally get\n> > rid of that \"Needs review\" on the What's Cooking messages ;)\n> \n> Thanks.  \n> \n> The OVERWRITING_FAIL one was the only one I was unhappy about, so it\n> would be good to have more eyeballs on it---perhaps other people\n> find the approach acceptable, or can suggest more readable and\n> understandable approach.\n\nFWIW, I don't really like it either. :) I gave my best shot at an\nalternative in reply to that patch.\n\n-Peff\n"},{"id":"398389","messageId":"20200521185514.GA615266@generichostname","threadId":"53350","inReplyTo":"20200521182928.GA1308647@coredump.intra.peff.net","subject":"Re: [PATCH v2 4/4] lib-submodule-update: pass OVERWRITING_FAIL","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-05-21T18:55:14Z","receivedAt":"2020-05-21T18:55:20Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"Hi Peff,\n\nOn Thu, May 21, 2020 at 02:29:28PM -0400, Jeff King wrote:\n> > This is useful because currently, when we run a test helper function, we\n> > just mark the whole thing as `test_must_fail`. However, it's possible\n> > that the helper function might fail earlier or later than expected due\n> > to an introduced bug. If this happens, then the test case will still\n> > report as passing but it should really be marked as failing since it\n> > didn't actually display the intended behaviour.\n> \n> Now this second concern I think is much more interesting, because it\n> impacts the test results. And it's really not even about test_must_fail\n> in particular, but is a general problem with checking failure in any\n> compound operation. We may expect the early parts to succeed, but the\n> later parts to fail, and we want to tell the difference. And that's true\n> whether you're using \"!\", test_must_fail, etc.\n> \n> You solve it here by passing OVERWRITING_FAIL down into the callback\n> functions. And that does work. But I think it may be easier to\n> understand if we invert the responsibility. Let the outer caller specify\n> two callbacks: one for setup/prep that must succeed, and one for a\n> single operation where we might expect success or failure.\n\nI believe that we'll need a third optional argument. For example, in\nt3906, we have the following diff\n\n\tdiff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh\n\tindex 6a7e801ca0..6e8dac9669 100755\n\t--- a/t/t3906-stash-submodule.sh\n\t+++ b/t/t3906-stash-submodule.sh\n\t@@ -8,7 +8,11 @@ test_description='stash can handle submodules'\n\t git_stash () {\n\t\tgit status -su >expect &&\n\t\tls -1pR * >>expect &&\n\t-\tgit read-tree -u -m \"$1\" &&\n\t+\t$OVERWRITING_FAIL git read-tree -u -m \"$1\" &&\n\t+\tif test -n \"$OVERWRITING_FAIL\"\n\t+\tthen\n\t+\t\treturn\n\t+\tfi &&\n\t\tgit stash &&\n\t\tgit status -su >actual &&\n\t\tls -1pR * >>actual &&\n\nwhich means, when we're doing test_must_fail, we have to skip the\nremainder of the function otherwise, if the first command succeeds but\nit fails later in the test, then we report success even though it didn't\nfail at the point where we were expecting. I think that we'll have to\nhave an optional third arg for $cleanup or something. The only thing\nthat I'm worried about is that having three separate functions being\npassed in may be too messy.\n\nAside from that, I like this approach much more than mine.\n\nThanks,\n\nDenton\n"},{"id":"398399","messageId":"xmqq8shlro12.fsf@gitster.c.googlers.com","threadId":"53350","inReplyTo":"20200521182928.GA1308647@coredump.intra.peff.net","subject":"Re: [PATCH v2 4/4] lib-submodule-update: pass OVERWRITING_FAIL","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-05-21T21:11:53Z","receivedAt":"2020-05-21T21:12:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> You solve it here by passing OVERWRITING_FAIL down into the callback\n> functions. And that does work. But I think it may be easier to\n> understand if we invert the responsibility. Let the outer caller specify\n> two callbacks: one for setup/prep that must succeed, and one for a\n> single operation where we might expect success or failure.\n>\n> The changes in lib-submodule-update look something like:\n> ...\n> And in the caller we can simplify greatly:\n> ...\n>   +test_submodule_switch \"reset_branch_to_HEAD\" \"git pull\"\n>   +test_submodule_switch \"reset_branch_to_HEAD\" \"git pull -ff\"\n>   +test_submodule_switch \"reset_branch_to_HEAD\" \"git pull --ff-only\"\n>    KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n>    KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n>   -test_submodule_switch \"git_pull_noff\"\n>   +test_submodule_switch \"reset_branch_to_HEAD\" \"git pull --no-ff\"\n>    \n>    test_expect_success 'pull --recurse-submodule setup' '\n>    \ttest_create_repo child &&\n>\n> I suspect this approach involves touching more lines than yours (it has\n> to add $prep everywhere $command is used). But IMHO the result is much\n> simpler to understand, because there's no spooky-action-at-a-distance\n> from magic environment variables.\n\nYes, spooky-action-at-a-distance was what made me go Eeeeek when I\nsaw the original approach.\n\n> A more complete patch is below, which is enough to get t5572 passing. I\n> think it would need the other test_submodule_switch() function updated,\n> and other scripts would need to adapt to the 2-arg style.\n\nbelow where?\n"},{"id":"398406","messageId":"20200521223734.GA1545675@coredump.intra.peff.net","threadId":"53350","inReplyTo":"xmqq8shlro12.fsf@gitster.c.googlers.com","subject":"Re: [PATCH v2 4/4] lib-submodule-update: pass OVERWRITING_FAIL","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2020-05-21T22:37:34Z","receivedAt":"2020-05-21T22:37:37Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, May 21, 2020 at 02:11:53PM -0700, Junio C Hamano wrote:\n\n> > A more complete patch is below, which is enough to get t5572 passing. I\n> > think it would need the other test_submodule_switch() function updated,\n> > and other scripts would need to adapt to the 2-arg style.\n> \n> below where?\n\nOops.\n\n---\n t/lib-submodule-update.sh | 46 ++++++++++++++++++++++++++++++----------------\n t/t5572-pull-submodule.sh | 31 ++++---------------------------\n 2 files changed, 34 insertions(+), 43 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 64fc6487dd..34da02b7fa 100644\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -310,7 +310,8 @@ test_submodule_content () {\n # Internal function; use test_submodule_switch() or\n # test_submodule_forced_switch() instead.\n test_submodule_switch_common() {\n-\tcommand=\"$1\"\n+\tprep=\"$1\"\n+\tcommand=\"$2\"\n \t######################### Appearing submodule #########################\n \t# Switching to a commit letting a submodule appear creates empty dir ...\n \tif test \"$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES\" = 1\n@@ -326,7 +327,8 @@ test_submodule_switch_common() {\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\t$prep add_sub1 &&\n+\t\t\t$command &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n \t\t\tgit submodule update --init --recursive &&\n@@ -341,7 +343,8 @@ test_submodule_switch_common() {\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\t$prep add_sub1 &&\n+\t\t\t$command &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n \t\t\tgit submodule update --init --recursive &&\n@@ -356,7 +359,8 @@ test_submodule_switch_common() {\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\t$prep replace_file_with_sub1 &&\n+\t\t\t$command &&\n \t\t\ttest_superproject_content origin/replace_file_with_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n \t\t\tgit submodule update --init --recursive &&\n@@ -380,7 +384,8 @@ test_submodule_switch_common() {\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\t$prep replace_directory_with_sub1 &&\n+\t\t\t$command &&\n \t\t\ttest_superproject_content origin/replace_directory_with_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n \t\t\tgit submodule update --init --recursive &&\n@@ -402,7 +407,8 @@ test_submodule_switch_common() {\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\t$prep remove_sub1 &&\n+\t\t\t$command &&\n \t\t\ttest_superproject_content origin/remove_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -415,7 +421,8 @@ test_submodule_switch_common() {\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\t$command remove_sub1 &&\n+\t\t\t$prep remove_sub1 &&\n+\t\t\t$command &&\n \t\t\ttest_superproject_content origin/remove_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -443,7 +450,8 @@ test_submodule_switch_common() {\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\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\t$prep replace_sub1_with_directory &&\n+\t\t\ttest_must_fail $command &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -456,7 +464,8 @@ test_submodule_switch_common() {\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\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\t$prep replace_sub1_with_directory &&\n+\t\t\ttest_must_fail $command &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -470,7 +479,8 @@ test_submodule_switch_common() {\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\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\t$prep replace_sub1_with_file &&\n+\t\t\ttest_must_fail $command &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -484,7 +494,8 @@ test_submodule_switch_common() {\n \t\t\tcd submodule_update &&\n \t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n \t\t\treplace_gitfile_with_git_dir sub1 &&\n-\t\t\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\t$prep replace_sub1_with_file &&\n+\t\t\ttest_must_fail $command &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -508,7 +519,8 @@ test_submodule_switch_common() {\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\t$prep modify_sub1 &&\n+\t\t\t$command &&\n \t\t\ttest_superproject_content origin/modify_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n \t\t\tgit submodule update &&\n@@ -523,7 +535,8 @@ test_submodule_switch_common() {\n \t\t(\n \t\t\tcd submodule_update &&\n \t\t\tgit branch -t invalid_sub1 origin/invalid_sub1 &&\n-\t\t\t$command invalid_sub1 &&\n+\t\t\t$prep invalid_sub1 &&\n+\t\t\t$command &&\n \t\t\ttest_superproject_content origin/invalid_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n \t\t\ttest_must_fail git submodule update &&\n@@ -538,7 +551,8 @@ test_submodule_switch_common() {\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\t$prep valid_sub1 &&\n+\t\t\t$command &&\n \t\t\ttest_superproject_content origin/valid_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n \t\t\tgit submodule update --init --recursive &&\n@@ -568,8 +582,8 @@ test_submodule_switch_common() {\n # }\n # test_submodule_switch \"my_func\"\n test_submodule_switch () {\n-\tcommand=\"$1\"\n-\ttest_submodule_switch_common \"$command\"\n+\tcommand=\"$2\"\n+\ttest_submodule_switch_common \"$@\"\n \n \t# An empty directory does not prevent the creation of a submodule of\n \t# the same name, but a file does.\ndiff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh\nindex f916729a12..e3ae7c89f1 100755\n--- a/t/t5572-pull-submodule.sh\n+++ b/t/t5572-pull-submodule.sh\n@@ -11,36 +11,13 @@ reset_branch_to_HEAD () {\n \tgit branch --set-upstream-to=\"origin/$1\" \"$1\"\n }\n \n-git_pull () {\n-\treset_branch_to_HEAD \"$1\" &&\n-\tgit pull\n-}\n-\n # pulls without conflicts\n-test_submodule_switch \"git_pull\"\n-\n-git_pull_ff () {\n-\treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --ff\n-}\n-\n-test_submodule_switch \"git_pull_ff\"\n-\n-git_pull_ff_only () {\n-\treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --ff-only\n-}\n-\n-test_submodule_switch \"git_pull_ff_only\"\n-\n-git_pull_noff () {\n-\treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --no-ff\n-}\n-\n+test_submodule_switch \"reset_branch_to_HEAD\" \"git pull\"\n+test_submodule_switch \"reset_branch_to_HEAD\" \"git pull -ff\"\n+test_submodule_switch \"reset_branch_to_HEAD\" \"git pull --ff-only\"\n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-test_submodule_switch \"git_pull_noff\"\n+test_submodule_switch \"reset_branch_to_HEAD\" \"git pull --no-ff\"\n \n test_expect_success 'pull --recurse-submodule setup' '\n \ttest_create_repo child &&\n"},{"id":"399555","messageId":"cover.1591897173.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1588162842.git.liu.denton@gmail.com","subject":"[PATCH v3 0/4] t: replace incorrect test_must_fail usage (part 5)","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-06-11T17:41:46Z","receivedAt":"2020-06-11T17:42:05Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"Hi all,\n\nSorry for taking so long with the reroll. I've taken Peff's suggestion\nand hopefully this approach is a lot more understandable. Unfortunately,\nwe introduce a few evals in test_submodule_switch_common() in the\nprocess but I think that the end result looks pretty clean.\n\n\nThe overall scope of these patches is to replace inappropriate uses of\ntest_must_fail. IOW, we should only allow test_must_fail to run on `git`\nand `test-tool`. Ultimately, we will conclude by making test_must_fail\nerror out on non-git commands. An advance view of the final series can\nbe found here[1].\n\nThis is the fifth part. It focuses on lib-submodule-update.sh and tests\nthat make use of it.\n\nThe first part can be found here[2]. The second part can be found\nhere[3]. The third part can be found here[4]. The fourth part can be\nfound here[5].\n\nChanges since v1.2:\n\n* In \"lib-submodule-update: pass OVERWRITING_FAIL\", use if-then return\n  to reduce the amount of code churn\n\nChanges since v2:\n\n* Replace the OVERWRITING_FAIL approach with callback functions as\n  suggested by Peff[6]\n\n[1]: (may be rebased at any time) https://github.com/Denton-L/git/tree/ready/cleanup-test-must-fail2\n[2]: https://lore.kernel.org/git/cover.1576583819.git.liu.denton@gmail.com/\n[3]: https://lore.kernel.org/git/cover.1577454401.git.liu.denton@gmail.com/\n[4]: https://lore.kernel.org/git/cover.1585209554.git.liu.denton@gmail.com/\n[5]: https://lore.kernel.org/git/cover.1587372771.git.liu.denton@gmail.com/\n[6]: https://lore.kernel.org/git/20200521182928.GA1308647@coredump.intra.peff.net/\n\nDenton Liu (4):\n  lib-submodule-update: add space after function name\n  lib-submodule-update: consolidate --recurse-submodules\n  lib-submodule-update: prepend \"git\" to $command\n  lib-submodule-update: use callbacks in test_submodule_switch_common()\n\n t/lib-submodule-update.sh        | 115 +++++++++++++++++++++++--------\n t/t1013-read-tree-submodule.sh   |   4 +-\n t/t2013-checkout-submodule.sh    |   4 +-\n t/t3426-rebase-submodule.sh      |  10 ++-\n t/t3512-cherry-pick-submodule.sh |   2 +-\n t/t3513-revert-submodule.sh      |  10 +--\n t/t3906-stash-submodule.sh       |  10 +--\n t/t4137-apply-submodule.sh       |  12 ++--\n t/t4255-am-submodule.sh          |  12 ++--\n t/t5572-pull-submodule.sh        |  28 ++------\n t/t6041-bisect-submodule.sh      |  10 +--\n t/t7112-reset-submodule.sh       |   6 +-\n t/t7613-merge-submodule.sh       |   8 +--\n 13 files changed, 132 insertions(+), 99 deletions(-)\n\nRange-diff against v2:\n1:  ba2f642e0f = 1:  ba2f642e0f lib-submodule-update: add space after function name\n2:  16d0a3eb9a = 2:  16d0a3eb9a lib-submodule-update: consolidate --recurse-submodules\n3:  578bab6f1a ! 3:  09446be5b9 lib-submodule-update: prepend \"git\" to $command\n    @@ t/lib-submodule-update.sh: test_submodule_content () {\n      \n     -# Internal function; use test_submodule_switch() or\n     -# test_submodule_forced_switch() instead.\n    -+# Internal function; use test_submodule_switch_func(), test_submodule_switch_func(),\n    ++# Internal function; use test_submodule_switch_func(), test_submodule_switch(),\n     +# or test_submodule_forced_switch() instead.\n      test_submodule_switch_common () {\n      \tcommand=\"$1\"\n4:  48598e3f98 < -:  ---------- lib-submodule-update: pass OVERWRITING_FAIL\n-:  ---------- > 4:  74e6086da4 lib-submodule-update: use callbacks in test_submodule_switch_common()\n-- \n2.27.0.132.g321788e831\n\n"},{"id":"399556","messageId":"ba2f642e0f505730d5d740207128036448787c8c.1591897173.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1591897173.git.liu.denton@gmail.com","subject":"[PATCH v3 1/4] lib-submodule-update: add space after function name","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-06-11T17:41:47Z","receivedAt":"2020-06-11T17:42:08Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"In the shell scripts in this codebase, the usual style is to include a\nspace between the function name and the (). Add these missing spaces to\nconform to the usual style of the code.\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\n t/lib-submodule-update.sh | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 1dd17fc03e..122554acd6 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -183,7 +183,7 @@ test_git_directory_is_unchanged () {\n \t)\n }\n \n-test_git_directory_exists() {\n+test_git_directory_exists () {\n \ttest -e \".git/modules/$1\" &&\n \tif test -f sub1/.git\n \tthen\n@@ -309,7 +309,7 @@ test_submodule_content () {\n \n # Internal function; use test_submodule_switch() or\n # test_submodule_forced_switch() instead.\n-test_submodule_switch_common() {\n+test_submodule_switch_common () {\n \tcommand=\"$1\"\n \t######################### Appearing submodule #########################\n \t# Switching to a commit letting a submodule appear creates empty dir ...\n@@ -629,7 +629,7 @@ test_submodule_forced_switch () {\n \n # Internal function; use test_submodule_switch_recursing_with_args() or\n # test_submodule_forced_switch_recursing_with_args() instead.\n-test_submodule_recursing_with_args_common() {\n+test_submodule_recursing_with_args_common () {\n \tcommand=\"$1\"\n \n \t######################### Appearing submodule #########################\n-- \n2.27.0.132.g321788e831\n\n"},{"id":"399557","messageId":"16d0a3eb9ac8dcda701433a9e67cde5103949432.1591897173.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1591897173.git.liu.denton@gmail.com","subject":"[PATCH v3 2/4] lib-submodule-update: consolidate --recurse-submodules","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-06-11T17:41:48Z","receivedAt":"2020-06-11T17:42:09Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"Both test_submodule_switch_recursing_with_args() and\ntest_submodule_forced_switch_recursing_with_args() call the internal\nfunction test_submodule_recursing_with_args_common() with the final\nargument of `--recurse-submodules`. Consolidate this duplication by\nappending the argument in test_submodule_recursing_with_args_common().\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\n t/lib-submodule-update.sh | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 122554acd6..bb36287803 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -630,7 +630,7 @@ test_submodule_forced_switch () {\n # Internal function; use test_submodule_switch_recursing_with_args() or\n # test_submodule_forced_switch_recursing_with_args() instead.\n test_submodule_recursing_with_args_common () {\n-\tcommand=\"$1\"\n+\tcommand=\"$1 --recurse-submodules\"\n \n \t######################### Appearing submodule #########################\n \t# Switching to a commit letting a submodule appear checks it out ...\n@@ -809,7 +809,7 @@ test_submodule_recursing_with_args_common () {\n # test_submodule_switch_recursing_with_args \"$GIT_COMMAND\"\n test_submodule_switch_recursing_with_args () {\n \tcmd_args=\"$1\"\n-\tcommand=\"git $cmd_args --recurse-submodules\"\n+\tcommand=\"git $cmd_args\"\n \ttest_submodule_recursing_with_args_common \"$command\"\n \n \tRESULTDS=success\n@@ -927,7 +927,7 @@ test_submodule_switch_recursing_with_args () {\n # away local changes in the superproject is allowed.\n test_submodule_forced_switch_recursing_with_args () {\n \tcmd_args=\"$1\"\n-\tcommand=\"git $cmd_args --recurse-submodules\"\n+\tcommand=\"git $cmd_args\"\n \ttest_submodule_recursing_with_args_common \"$command\"\n \n \tRESULT=success\n-- \n2.27.0.132.g321788e831\n\n"},{"id":"399558","messageId":"09446be5b9e9d6291dae3531a93b588e0b7a1c3f.1591897173.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1591897173.git.liu.denton@gmail.com","subject":"[PATCH v3 3/4] lib-submodule-update: prepend \"git\" to $command","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-06-11T17:41:49Z","receivedAt":"2020-06-11T17:42:11Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"Since all invocations of test_submodule_forced_switch() are git\ncommands, automatically prepend \"git\" before invoking\ntest_submodule_switch_common().\n\nSimilarly, many invocations of test_submodule_switch() are also git\ncommands so automatically prepend \"git\" before invoking\ntest_submodule_switch_common() as well.\n\nFinally, for invocations of test_submodule_switch() that invoke a custom\nfunction, rename the old function to test_submodule_switch_func().\n\nThis is necessary because in a future commit, we will be adding some\nlogic that needs to distinguish between an invocation of a plain git\ncomamnd and an invocation of a test helper function.\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\n t/lib-submodule-update.sh        | 14 +++++++++-----\n t/t1013-read-tree-submodule.sh   |  4 ++--\n t/t2013-checkout-submodule.sh    |  4 ++--\n t/t3426-rebase-submodule.sh      |  4 ++--\n t/t3512-cherry-pick-submodule.sh |  2 +-\n t/t3513-revert-submodule.sh      |  2 +-\n t/t3906-stash-submodule.sh       |  2 +-\n t/t4137-apply-submodule.sh       |  4 ++--\n t/t4255-am-submodule.sh          |  4 ++--\n t/t5572-pull-submodule.sh        |  8 ++++----\n t/t6041-bisect-submodule.sh      |  2 +-\n t/t7112-reset-submodule.sh       |  6 +++---\n t/t7613-merge-submodule.sh       |  8 ++++----\n 13 files changed, 34 insertions(+), 30 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex bb36287803..7c3ba1be00 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -307,8 +307,8 @@ test_submodule_content () {\n # to protect the history!\n #\n \n-# Internal function; use test_submodule_switch() or\n-# test_submodule_forced_switch() instead.\n+# Internal function; use test_submodule_switch_func(), test_submodule_switch(),\n+# or test_submodule_forced_switch() instead.\n test_submodule_switch_common () {\n \tcommand=\"$1\"\n \t######################### Appearing submodule #########################\n@@ -566,8 +566,8 @@ test_submodule_switch_common () {\n #   # Do something here that updates the worktree and index to match target,\n #   # but not any submodule directories.\n # }\n-# test_submodule_switch \"my_func\"\n-test_submodule_switch () {\n+# test_submodule_switch_func \"my_func\"\n+test_submodule_switch_func () {\n \tcommand=\"$1\"\n \ttest_submodule_switch_common \"$command\"\n \n@@ -587,12 +587,16 @@ test_submodule_switch () {\n \t'\n }\n \n+test_submodule_switch () {\n+\ttest_submodule_switch_func \"git $1\"\n+}\n+\n # Same as test_submodule_switch(), except that throwing away local changes in\n # the superproject is allowed.\n test_submodule_forced_switch () {\n \tcommand=\"$1\"\n \tKNOWN_FAILURE_FORCED_SWITCH_TESTS=1\n-\ttest_submodule_switch_common \"$command\"\n+\ttest_submodule_switch_common \"git $command\"\n \n \t# When forced, a file in the superproject does not prevent creating a\n \t# submodule of the same name.\ndiff --git a/t/t1013-read-tree-submodule.sh b/t/t1013-read-tree-submodule.sh\nindex 91a6fafcb4..b6df7444c0 100755\n--- a/t/t1013-read-tree-submodule.sh\n+++ b/t/t1013-read-tree-submodule.sh\n@@ -12,8 +12,8 @@ test_submodule_switch_recursing_with_args \"read-tree -u -m\"\n \n test_submodule_forced_switch_recursing_with_args \"read-tree -u --reset\"\n \n-test_submodule_switch \"git read-tree -u -m\"\n+test_submodule_switch \"read-tree -u -m\"\n \n-test_submodule_forced_switch \"git read-tree -u --reset\"\n+test_submodule_forced_switch \"read-tree -u --reset\"\n \n test_done\ndiff --git a/t/t2013-checkout-submodule.sh b/t/t2013-checkout-submodule.sh\nindex 8f86b5f4b2..b2bdd1fcb4 100755\n--- a/t/t2013-checkout-submodule.sh\n+++ b/t/t2013-checkout-submodule.sh\n@@ -68,8 +68,8 @@ test_submodule_switch_recursing_with_args \"checkout\"\n \n test_submodule_forced_switch_recursing_with_args \"checkout -f\"\n \n-test_submodule_switch \"git checkout\"\n+test_submodule_switch \"checkout\"\n \n-test_submodule_forced_switch \"git checkout -f\"\n+test_submodule_forced_switch \"checkout -f\"\n \n test_done\ndiff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh\nindex a2bba04ba9..788605ccc0 100755\n--- a/t/t3426-rebase-submodule.sh\n+++ b/t/t3426-rebase-submodule.sh\n@@ -20,7 +20,7 @@ git_rebase () {\n \tgit rebase \"$1\"\n }\n \n-test_submodule_switch \"git_rebase\"\n+test_submodule_switch_func \"git_rebase\"\n \n git_rebase_interactive () {\n \tgit status -su >expect &&\n@@ -38,7 +38,7 @@ git_rebase_interactive () {\n \tgit rebase -i \"$1\"\n }\n \n-test_submodule_switch \"git_rebase_interactive\"\n+test_submodule_switch_func \"git_rebase_interactive\"\n \n test_expect_success 'rebase interactive ignores modified submodules' '\n \ttest_when_finished \"rm -rf super sub\" &&\ndiff --git a/t/t3512-cherry-pick-submodule.sh b/t/t3512-cherry-pick-submodule.sh\nindex bd78287841..6ece1d8573 100755\n--- a/t/t3512-cherry-pick-submodule.sh\n+++ b/t/t3512-cherry-pick-submodule.sh\n@@ -7,7 +7,7 @@ test_description='cherry-pick can handle submodules'\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-test_submodule_switch \"git cherry-pick\"\n+test_submodule_switch \"cherry-pick\"\n \n test_expect_success 'unrelated submodule/file conflict is ignored' '\n \ttest_create_repo sub &&\ndiff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh\nindex 5e39fcdb66..95a7f64471 100755\n--- a/t/t3513-revert-submodule.sh\n+++ b/t/t3513-revert-submodule.sh\n@@ -26,6 +26,6 @@ git_revert () {\n }\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-test_submodule_switch \"git_revert\"\n+test_submodule_switch_func \"git_revert\"\n \n test_done\ndiff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh\nindex b93d1d74da..6a7e801ca0 100755\n--- a/t/t3906-stash-submodule.sh\n+++ b/t/t3906-stash-submodule.sh\n@@ -19,7 +19,7 @@ git_stash () {\n KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES=1\n KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1\n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-test_submodule_switch \"git_stash\"\n+test_submodule_switch_func \"git_stash\"\n \n setup_basic () {\n \ttest_when_finished \"rm -rf main sub\" &&\ndiff --git a/t/t4137-apply-submodule.sh b/t/t4137-apply-submodule.sh\nindex a9bd40a6d0..b645e303a0 100755\n--- a/t/t4137-apply-submodule.sh\n+++ b/t/t4137-apply-submodule.sh\n@@ -9,12 +9,12 @@ apply_index () {\n \tgit diff --ignore-submodules=dirty \"..$1\" | git apply --index -\n }\n \n-test_submodule_switch \"apply_index\"\n+test_submodule_switch_func \"apply_index\"\n \n apply_3way () {\n \tgit diff --ignore-submodules=dirty \"..$1\" | git apply --3way -\n }\n \n-test_submodule_switch \"apply_3way\"\n+test_submodule_switch_func \"apply_3way\"\n \n test_done\ndiff --git a/t/t4255-am-submodule.sh b/t/t4255-am-submodule.sh\nindex 0ba8194403..1b179d5f45 100755\n--- a/t/t4255-am-submodule.sh\n+++ b/t/t4255-am-submodule.sh\n@@ -9,14 +9,14 @@ am () {\n \tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am -\n }\n \n-test_submodule_switch \"am\"\n+test_submodule_switch_func \"am\"\n \n am_3way () {\n \tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am --3way -\n }\n \n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-test_submodule_switch \"am_3way\"\n+test_submodule_switch_func \"am_3way\"\n \n test_expect_success 'setup diff.submodule' '\n \ttest_commit one &&\ndiff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh\nindex f916729a12..f911bf631e 100755\n--- a/t/t5572-pull-submodule.sh\n+++ b/t/t5572-pull-submodule.sh\n@@ -17,21 +17,21 @@ git_pull () {\n }\n \n # pulls without conflicts\n-test_submodule_switch \"git_pull\"\n+test_submodule_switch_func \"git_pull\"\n \n git_pull_ff () {\n \treset_branch_to_HEAD \"$1\" &&\n \tgit pull --ff\n }\n \n-test_submodule_switch \"git_pull_ff\"\n+test_submodule_switch_func \"git_pull_ff\"\n \n git_pull_ff_only () {\n \treset_branch_to_HEAD \"$1\" &&\n \tgit pull --ff-only\n }\n \n-test_submodule_switch \"git_pull_ff_only\"\n+test_submodule_switch_func \"git_pull_ff_only\"\n \n git_pull_noff () {\n \treset_branch_to_HEAD \"$1\" &&\n@@ -40,7 +40,7 @@ git_pull_noff () {\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-test_submodule_switch \"git_pull_noff\"\n+test_submodule_switch_func \"git_pull_noff\"\n \n test_expect_success 'pull --recurse-submodule setup' '\n \ttest_create_repo child &&\ndiff --git a/t/t6041-bisect-submodule.sh b/t/t6041-bisect-submodule.sh\nindex 62b8a2e7bb..0e0cdf638d 100755\n--- a/t/t6041-bisect-submodule.sh\n+++ b/t/t6041-bisect-submodule.sh\n@@ -27,6 +27,6 @@ git_bisect () {\n \tgit bisect bad $BAD\n }\n \n-test_submodule_switch \"git_bisect\"\n+test_submodule_switch_func \"git_bisect\"\n \n test_done\ndiff --git a/t/t7112-reset-submodule.sh b/t/t7112-reset-submodule.sh\nindex a1cb9ff858..8741b665c9 100755\n--- a/t/t7112-reset-submodule.sh\n+++ b/t/t7112-reset-submodule.sh\n@@ -13,10 +13,10 @@ test_submodule_switch_recursing_with_args \"reset --keep\"\n \n test_submodule_forced_switch_recursing_with_args \"reset --hard\"\n \n-test_submodule_switch \"git reset --keep\"\n+test_submodule_switch \"reset --keep\"\n \n-test_submodule_switch \"git reset --merge\"\n+test_submodule_switch \"reset --merge\"\n \n-test_submodule_forced_switch \"git reset --hard\"\n+test_submodule_forced_switch \"reset --hard\"\n \n test_done\ndiff --git a/t/t7613-merge-submodule.sh b/t/t7613-merge-submodule.sh\nindex d1e9fcc781..04bf4be7d7 100755\n--- a/t/t7613-merge-submodule.sh\n+++ b/t/t7613-merge-submodule.sh\n@@ -6,14 +6,14 @@ test_description='merge can handle submodules'\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n # merges without conflicts\n-test_submodule_switch \"git merge\"\n+test_submodule_switch \"merge\"\n \n-test_submodule_switch \"git merge --ff\"\n+test_submodule_switch \"merge --ff\"\n \n-test_submodule_switch \"git merge --ff-only\"\n+test_submodule_switch \"merge --ff-only\"\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-test_submodule_switch \"git merge --no-ff\"\n+test_submodule_switch \"merge --no-ff\"\n \n test_done\n-- \n2.27.0.132.g321788e831\n\n"},{"id":"399559","messageId":"74e6086da451a4ce2ac52b04a2399ef332d61047.1591897173.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1591897173.git.liu.denton@gmail.com","subject":"[PATCH v3 4/4] lib-submodule-update: use callbacks in test_submodule_switch_common()","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-06-11T17:41:50Z","receivedAt":"2020-06-11T17:42:12Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"When we run a test helper function in test_submodule_switch_common(), we\nsometimes specify a whole helper function as the $command. When we do\nthis, in some test cases, we just mark the whole function with\n`test_must_fail`. However, it's possible that the helper function might\nfail earlier or later than expected due to an introduced bug. If this\nhappens, then the test case will still report as passing but it should\nreally be marked as failing since it didn't actually display the\nintended behaviour.\n\nInstead of invoking $command as one monolithic helper function, break it\nup into three parts:\n\n\t1. $command which is always a git command.\n\t2. $before which is a callback function that runs just prior to\n\t   $command.\n\t3. $after which is a callback function that runs just after\n\t   $command.\n\nIf the command requires a filename argument, specify it as `\\$arg` since\nthat variable will be set and the whole $command string will be eval'd.\nUnfortunately, there is no way to get rid of the eval as some of the\ncommands are passed (such as the `git pull` tests) require that no\nadditional arguments are passed so we must have some mechanism for the\ncaller to specify whether or not it wants the filename argument.\n\nThe $before and $after callback functions will be passed the filename as\nthe first arg. These callback functions are optional and, if missing,\nwill be replaced with `true`. Also, in the case where we have a\n`test_must_fail` test, $after will not be executed, similar to how the\nhelper functions currently behave when the git command fails and exits\nthe &&-chain.\n\nFinally, as an added bonus, `test_must_fail` will only run on $command\nwhich is guaranteed to be a git command.\n\nAn alternate design was considered where the $OVERWRITING_FAIL is set\nfrom the test_submodule_switch_common() function and passed to the\nhelper function. This approach was considered too difficult to\nunderstand due to the fact that using a signalling magic environment\nvariable might be too indirect.\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\n t/lib-submodule-update.sh   | 95 +++++++++++++++++++++++++++++--------\n t/t3426-rebase-submodule.sh | 10 ++--\n t/t3513-revert-submodule.sh | 10 ++--\n t/t3906-stash-submodule.sh  | 10 ++--\n t/t4137-apply-submodule.sh  | 12 ++---\n t/t4255-am-submodule.sh     | 12 ++---\n t/t5572-pull-submodule.sh   | 28 ++---------\n t/t6041-bisect-submodule.sh | 10 ++--\n 8 files changed, 108 insertions(+), 79 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 7c3ba1be00..988d85bd7d 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -310,7 +310,20 @@ test_submodule_content () {\n # Internal function; use test_submodule_switch_func(), test_submodule_switch(),\n # or test_submodule_forced_switch() instead.\n test_submodule_switch_common () {\n-\tcommand=\"$1\"\n+\tcommand=\"$1\" # should be a git command\n+\tbefore=\"$2\"\n+\tafter=\"$3\"\n+\n+\tif test -z \"$before\"\n+\tthen\n+\t\tbefore=true\n+\tfi\n+\n+\tif test -z \"$after\"\n+\tthen\n+\t\tafter=true\n+\tfi\n+\n \t######################### Appearing submodule #########################\n \t# Switching to a commit letting a submodule appear creates empty dir ...\n \tif test \"$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES\" = 1\n@@ -326,7 +339,10 @@ test_submodule_switch_common () {\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\targ=add_sub1 &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval $command &&\n+\t\t\t$after \"$arg\" &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n \t\t\tgit submodule update --init --recursive &&\n@@ -341,7 +357,10 @@ test_submodule_switch_common () {\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\targ=add_sub1 &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval $command &&\n+\t\t\t$after \"$arg\" &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n \t\t\tgit submodule update --init --recursive &&\n@@ -356,7 +375,10 @@ test_submodule_switch_common () {\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\targ=replace_file_with_sub1 &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval $command &&\n+\t\t\t$after \"$arg\" &&\n \t\t\ttest_superproject_content origin/replace_file_with_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n \t\t\tgit submodule update --init --recursive &&\n@@ -380,7 +402,10 @@ test_submodule_switch_common () {\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\targ=replace_directory_with_sub1  &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval $command &&\n+\t\t\t$after \"$arg\" &&\n \t\t\ttest_superproject_content origin/replace_directory_with_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n \t\t\tgit submodule update --init --recursive &&\n@@ -402,7 +427,10 @@ test_submodule_switch_common () {\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\targ=remove_sub1 &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval $command &&\n+\t\t\t$after \"$arg\" &&\n \t\t\ttest_superproject_content origin/remove_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -415,7 +443,10 @@ test_submodule_switch_common () {\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\t$command remove_sub1 &&\n+\t\t\targ=remove_sub1 &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval $command &&\n+\t\t\t$after \"$arg\" &&\n \t\t\ttest_superproject_content origin/remove_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -443,7 +474,9 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\targ=replace_sub1_with_directory &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval test_must_fail $command &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -456,7 +489,9 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\targ=replace_sub1_with_directory &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval test_must_fail $command &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -470,7 +505,9 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\targ=replace_sub1_with_file &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval test_must_fail $command &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -484,7 +521,9 @@ test_submodule_switch_common () {\n \t\t\tcd submodule_update &&\n \t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n \t\t\treplace_gitfile_with_git_dir sub1 &&\n-\t\t\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\targ=replace_sub1_with_file &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval test_must_fail $command &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -508,7 +547,10 @@ test_submodule_switch_common () {\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\targ=modify_sub1 &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval $command &&\n+\t\t\t$after \"$arg\" &&\n \t\t\ttest_superproject_content origin/modify_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n \t\t\tgit submodule update &&\n@@ -523,7 +565,10 @@ test_submodule_switch_common () {\n \t\t(\n \t\t\tcd submodule_update &&\n \t\t\tgit branch -t invalid_sub1 origin/invalid_sub1 &&\n-\t\t\t$command invalid_sub1 &&\n+\t\t\targ=invalid_sub1 &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval $command &&\n+\t\t\t$after \"$arg\" &&\n \t\t\ttest_superproject_content origin/invalid_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n \t\t\ttest_must_fail git submodule update &&\n@@ -538,7 +583,10 @@ test_submodule_switch_common () {\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\targ=valid_sub1 &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval $command &&\n+\t\t\t$after \"$arg\" &&\n \t\t\ttest_superproject_content origin/valid_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n \t\t\tgit submodule update --init --recursive &&\n@@ -568,8 +616,10 @@ test_submodule_switch_common () {\n # }\n # test_submodule_switch_func \"my_func\"\n test_submodule_switch_func () {\n-\tcommand=\"$1\"\n-\ttest_submodule_switch_common \"$command\"\n+\tcommand=\"git $1\"\n+\tbefore=\"$2\"\n+\tafter=\"$3\"\n+\ttest_submodule_switch_common \"$command\" \"$before\" \"$after\"\n \n \t# An empty directory does not prevent the creation of a submodule of\n \t# the same name, but a file does.\n@@ -580,7 +630,9 @@ test_submodule_switch_func () {\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\targ=add_sub1 &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval test_must_fail $command &&\n \t\t\ttest_superproject_content origin/no_submodule &&\n \t\t\ttest_must_be_empty sub1\n \t\t)\n@@ -588,15 +640,15 @@ test_submodule_switch_func () {\n }\n \n test_submodule_switch () {\n-\ttest_submodule_switch_func \"git $1\"\n+\ttest_submodule_switch_func \"$1 \\$arg\"\n }\n \n # Same as test_submodule_switch(), except that throwing away local changes in\n # the superproject is allowed.\n test_submodule_forced_switch () {\n-\tcommand=\"$1\"\n+\tcommand=\"git $1 \\$arg\"\n \tKNOWN_FAILURE_FORCED_SWITCH_TESTS=1\n-\ttest_submodule_switch_common \"git $command\"\n+\ttest_submodule_switch_common \"$command\"\n \n \t# When forced, a file in the superproject does not prevent creating a\n \t# submodule of the same name.\n@@ -607,7 +659,8 @@ test_submodule_forced_switch () {\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\targ=add_sub1 &&\n+\t\t\teval $command &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_dir_is_empty sub1\n \t\t)\ndiff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh\nindex 788605ccc0..d31e6487bd 100755\n--- a/t/t3426-rebase-submodule.sh\n+++ b/t/t3426-rebase-submodule.sh\n@@ -16,11 +16,10 @@ git_rebase () {\n \tgit revert HEAD &&\n \tgit status -su >actual &&\n \tls -1pR * >>actual &&\n-\ttest_cmp expect actual &&\n-\tgit rebase \"$1\"\n+\ttest_cmp expect actual\n }\n \n-test_submodule_switch_func \"git_rebase\"\n+test_submodule_switch_func \"rebase \\$arg\" \"git_rebase\"\n \n git_rebase_interactive () {\n \tgit status -su >expect &&\n@@ -34,11 +33,10 @@ git_rebase_interactive () {\n \tls -1pR * >>actual &&\n \ttest_cmp expect actual &&\n \tset_fake_editor &&\n-\techo \"fake-editor.sh\" >.git/info/exclude &&\n-\tgit rebase -i \"$1\"\n+\techo \"fake-editor.sh\" >.git/info/exclude\n }\n \n-test_submodule_switch_func \"git_rebase_interactive\"\n+test_submodule_switch_func \"rebase -i \\$arg\" \"git_rebase_interactive\"\n \n test_expect_success 'rebase interactive ignores modified submodules' '\n \ttest_when_finished \"rm -rf super sub\" &&\ndiff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh\nindex 95a7f64471..994cdc40f0 100755\n--- a/t/t3513-revert-submodule.sh\n+++ b/t/t3513-revert-submodule.sh\n@@ -11,11 +11,13 @@ test_description='revert can handle submodules'\n # first so we can restore the work tree test setup after doing the checkout\n # and revert.  We test here that the restored work tree content is identical\n # to that at the beginning. The last revert is then tested by the framework.\n-git_revert () {\n+git_revert_before () {\n \tgit status -su >expect &&\n \tls -1pR * >>expect &&\n-\ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n-\tgit checkout \"$1\" &&\n+\ttar cf \"$TRASH_DIRECTORY/tmp.tar\" *\n+}\n+\n+git_revert_after () {\n \tgit revert HEAD &&\n \trm -rf * &&\n \ttar xf \"$TRASH_DIRECTORY/tmp.tar\" &&\n@@ -26,6 +28,6 @@ git_revert () {\n }\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-test_submodule_switch_func \"git_revert\"\n+test_submodule_switch_func \"checkout \\$arg\" \"git_revert_before\" \"git_revert_after\"\n \n test_done\ndiff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh\nindex 6a7e801ca0..358a625124 100755\n--- a/t/t3906-stash-submodule.sh\n+++ b/t/t3906-stash-submodule.sh\n@@ -5,10 +5,12 @@ test_description='stash can handle submodules'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n-git_stash () {\n+git_stash_before () {\n \tgit status -su >expect &&\n-\tls -1pR * >>expect &&\n-\tgit read-tree -u -m \"$1\" &&\n+\tls -1pR * >>expect\n+}\n+\n+git_stash_after () {\n \tgit stash &&\n \tgit status -su >actual &&\n \tls -1pR * >>actual &&\n@@ -19,7 +21,7 @@ git_stash () {\n KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES=1\n KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1\n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-test_submodule_switch_func \"git_stash\"\n+test_submodule_switch_func \"read-tree -u -m \\$arg\" \"git_stash_before\" \"git_stash_after\"\n \n setup_basic () {\n \ttest_when_finished \"rm -rf main sub\" &&\ndiff --git a/t/t4137-apply-submodule.sh b/t/t4137-apply-submodule.sh\nindex b645e303a0..fe5ebeaa41 100755\n--- a/t/t4137-apply-submodule.sh\n+++ b/t/t4137-apply-submodule.sh\n@@ -5,16 +5,12 @@ test_description='git apply handling submodules'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n-apply_index () {\n-\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --index -\n+create_diff () {\n+\tgit diff --ignore-submodules=dirty \"..$1\" >diff\n }\n \n-test_submodule_switch_func \"apply_index\"\n+test_submodule_switch_func \"apply --index diff\" \"create_diff\"\n \n-apply_3way () {\n-\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --3way -\n-}\n-\n-test_submodule_switch_func \"apply_3way\"\n+test_submodule_switch_func \"apply --3way diff\" \"create_diff\"\n \n test_done\ndiff --git a/t/t4255-am-submodule.sh b/t/t4255-am-submodule.sh\nindex 1b179d5f45..5305280dfd 100755\n--- a/t/t4255-am-submodule.sh\n+++ b/t/t4255-am-submodule.sh\n@@ -5,18 +5,14 @@ test_description='git am handling submodules'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n-am () {\n-\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am -\n+create_patch () {\n+\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" >patch\n }\n \n-test_submodule_switch_func \"am\"\n-\n-am_3way () {\n-\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am --3way -\n-}\n+test_submodule_switch_func \"am patch\" \"create_patch\"\n \n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-test_submodule_switch_func \"am_3way\"\n+test_submodule_switch_func \"am --3way patch\" \"create_patch\"\n \n test_expect_success 'setup diff.submodule' '\n \ttest_commit one &&\ndiff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh\nindex f911bf631e..3b37853537 100755\n--- a/t/t5572-pull-submodule.sh\n+++ b/t/t5572-pull-submodule.sh\n@@ -11,36 +11,16 @@ reset_branch_to_HEAD () {\n \tgit branch --set-upstream-to=\"origin/$1\" \"$1\"\n }\n \n-git_pull () {\n-\treset_branch_to_HEAD \"$1\" &&\n-\tgit pull\n-}\n-\n # pulls without conflicts\n-test_submodule_switch_func \"git_pull\"\n+test_submodule_switch_func \"pull\" \"reset_branch_to_HEAD\"\n \n-git_pull_ff () {\n-\treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --ff\n-}\n+test_submodule_switch_func \"pull --ff\" \"reset_branch_to_HEAD\"\n \n-test_submodule_switch_func \"git_pull_ff\"\n-\n-git_pull_ff_only () {\n-\treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --ff-only\n-}\n-\n-test_submodule_switch_func \"git_pull_ff_only\"\n-\n-git_pull_noff () {\n-\treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --no-ff\n-}\n+test_submodule_switch_func \"pull --ff-only\" \"reset_branch_to_HEAD\"\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-test_submodule_switch_func \"git_pull_noff\"\n+test_submodule_switch_func \"pull --no-ff\" \"reset_branch_to_HEAD\"\n \n test_expect_success 'pull --recurse-submodule setup' '\n \ttest_create_repo child &&\ndiff --git a/t/t6041-bisect-submodule.sh b/t/t6041-bisect-submodule.sh\nindex 0e0cdf638d..b99e81d55d 100755\n--- a/t/t6041-bisect-submodule.sh\n+++ b/t/t6041-bisect-submodule.sh\n@@ -5,12 +5,14 @@ test_description='bisect can handle submodules'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n-git_bisect () {\n+git_bisect_before () {\n \tgit status -su >expect &&\n \tls -1pR * >>expect &&\n \ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n-\tGOOD=$(git rev-parse --verify HEAD) &&\n-\tgit checkout \"$1\" &&\n+\tGOOD=$(git rev-parse --verify HEAD)\n+}\n+\n+git_bisect_after () {\n \techo \"foo\" >bar &&\n \tgit add bar &&\n \tgit commit -m \"bisect bad\" &&\n@@ -27,6 +29,6 @@ git_bisect () {\n \tgit bisect bad $BAD\n }\n \n-test_submodule_switch_func \"git_bisect\"\n+test_submodule_switch_func \"checkout \\$arg\" \"git_bisect_before\" \"git_bisect_after\"\n \n test_done\n-- \n2.27.0.132.g321788e831\n\n"},{"id":"399627","messageId":"xmqqy2os15s0.fsf@gitster.c.googlers.com","threadId":"53350","inReplyTo":"74e6086da451a4ce2ac52b04a2399ef332d61047.1591897173.git.liu.denton@gmail.com","subject":"Re: [PATCH v3 4/4] lib-submodule-update: use callbacks in test_submodule_switch_common()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-06-12T18:46:23Z","receivedAt":"2020-06-12T18:46:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Denton Liu <liu.denton@gmail.com> writes:\n\n>  test_submodule_switch_common () {\n> -\tcommand=\"$1\"\n> +\tcommand=\"$1\" # should be a git command\n> +\tbefore=\"$2\"\n> +\tafter=\"$3\"\n> +\n> +\tif test -z \"$before\"\n> +\tthen\n> +\t\tbefore=true\n> +\tfi\n> +\n> +\tif test -z \"$after\"\n> +\tthen\n> +\t\tafter=true\n> +\tfi\n> +\n\n\tcommand=\"$1\" before=${2:-true} after=${3:-true}\n\nshould be sufficient?  Spelling 'true' as ':' would make it even\nshorter but probably too cryptic ;-)\n\n> diff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh\n> index 788605ccc0..d31e6487bd 100755\n> --- a/t/t3426-rebase-submodule.sh\n> +++ b/t/t3426-rebase-submodule.sh\n> @@ -16,11 +16,10 @@ git_rebase () {\n>  \tgit revert HEAD &&\n>  \tgit status -su >actual &&\n>  \tls -1pR * >>actual &&\n> -\ttest_cmp expect actual &&\n> -\tgit rebase \"$1\"\n> +\ttest_cmp expect actual\n\nWe used to run \"git rebase\" in this helper, but that is the thing we\nexpect to succeed or to fail, so with the revamped test framework,\nthis is split out to just be the \"before testing\" helper function?\n\nMakes sense.\n\n> -test_submodule_switch_func \"git_rebase\"\n> +test_submodule_switch_func \"rebase \\$arg\" \"git_rebase\"\n\n>  git_rebase_interactive () {\n>  \tgit status -su >expect &&\n> @@ -34,11 +33,10 @@ git_rebase_interactive () {\n>  \tls -1pR * >>actual &&\n>  \ttest_cmp expect actual &&\n>  \tset_fake_editor &&\n> -\techo \"fake-editor.sh\" >.git/info/exclude &&\n> -\tgit rebase -i \"$1\"\n> +\techo \"fake-editor.sh\" >.git/info/exclude\n>  }\n>  \n> -test_submodule_switch_func \"git_rebase_interactive\"\n> +test_submodule_switch_func \"rebase -i \\$arg\" \"git_rebase_interactive\"\n\nLikewise.\n"},{"id":"400028","messageId":"xmqq4kr8rji6.fsf@gitster.c.googlers.com","threadId":"53350","inReplyTo":"74e6086da451a4ce2ac52b04a2399ef332d61047.1591897173.git.liu.denton@gmail.com","subject":"Re: [PATCH v3 4/4] lib-submodule-update: use callbacks in test_submodule_switch_common()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-06-18T06:11:13Z","receivedAt":"2020-06-18T06:11:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Denton Liu <liu.denton@gmail.com> writes:\n\n> When we run a test helper function in test_submodule_switch_common(), we\n> sometimes specify a whole helper function as the $command. When we do\n> this, in some test cases, we just mark the whole function with\n> `test_must_fail`. However, it's possible that the helper function might\n> fail earlier or later than expected due to an introduced bug. If this\n> happens, then the test case will still report as passing but it should\n> really be marked as failing since it didn't actually display the\n> intended behaviour.\n>\n> Instead of invoking $command as one monolithic helper function, break it\n> up into three parts:\n>\n> \t1. $command which is always a git command.\n> \t2. $before which is a callback function that runs just prior to\n> \t   $command.\n> \t3. $after which is a callback function that runs just after\n> \t   $command.\n>\n> If the command requires a filename argument, specify it as `\\$arg` since\n> that variable will be set and the whole $command string will be eval'd.\n> Unfortunately, there is no way to get rid of the eval as some of the\n> commands are passed (such as the `git pull` tests) require that no\n> additional arguments are passed so we must have some mechanism for the\n> caller to specify whether or not it wants the filename argument.\n>\n> The $before and $after callback functions will be passed the filename as\n> the first arg. These callback functions are optional and, if missing,\n> will be replaced with `true`. Also, in the case where we have a\n> `test_must_fail` test, $after will not be executed, similar to how the\n> helper functions currently behave when the git command fails and exits\n> the &&-chain.\n>\n> Finally, as an added bonus, `test_must_fail` will only run on $command\n> which is guaranteed to be a git command.\n>\n> An alternate design was considered where the $OVERWRITING_FAIL is set\n> from the test_submodule_switch_common() function and passed to the\n> helper function. This approach was considered too difficult to\n> understand due to the fact that using a signalling magic environment\n> variable might be too indirect.\n>\n> Signed-off-by: Denton Liu <liu.denton@gmail.com>\n> ---\n\nPeff, I think the previous round of this had all-caps OVERWRITING_FAIL\nbut the reversal of the role to feed the actual code that gets run\nbefore and after the tested snippet by the caller was made in\nresponse to your sugestion <20200521182928.GA1308647@coredump.intra.peff.net>.\n\nI think I've already said that the helper function in the early part\ncan be vastly simplified but in any case the calling sideprobably\nhas become somewhat easier to follow (but not all that much, I am\nafraid).  \n\nIs there anything else we missed?\n\nThanks.\n\n>  t/lib-submodule-update.sh   | 95 +++++++++++++++++++++++++++++--------\n>  t/t3426-rebase-submodule.sh | 10 ++--\n>  t/t3513-revert-submodule.sh | 10 ++--\n>  t/t3906-stash-submodule.sh  | 10 ++--\n>  t/t4137-apply-submodule.sh  | 12 ++---\n>  t/t4255-am-submodule.sh     | 12 ++---\n>  t/t5572-pull-submodule.sh   | 28 ++---------\n>  t/t6041-bisect-submodule.sh | 10 ++--\n>  8 files changed, 108 insertions(+), 79 deletions(-)\n>\n> diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\n> index 7c3ba1be00..988d85bd7d 100755\n> --- a/t/lib-submodule-update.sh\n> +++ b/t/lib-submodule-update.sh\n> @@ -310,7 +310,20 @@ test_submodule_content () {\n>  # Internal function; use test_submodule_switch_func(), test_submodule_switch(),\n>  # or test_submodule_forced_switch() instead.\n>  test_submodule_switch_common () {\n> -\tcommand=\"$1\"\n> +\tcommand=\"$1\" # should be a git command\n> +\tbefore=\"$2\"\n> +\tafter=\"$3\"\n> +\n> +\tif test -z \"$before\"\n> +\tthen\n> +\t\tbefore=true\n> +\tfi\n> +\n> +\tif test -z \"$after\"\n> +\tthen\n> +\t\tafter=true\n> +\tfi\n> +\n>  \t######################### Appearing submodule #########################\n>  \t# Switching to a commit letting a submodule appear creates empty dir ...\n>  \tif test \"$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES\" = 1\n> @@ -326,7 +339,10 @@ test_submodule_switch_common () {\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\targ=add_sub1 &&\n> +\t\t\t$before \"$arg\" &&\n> +\t\t\teval $command &&\n> +\t\t\t$after \"$arg\" &&\n>  \t\t\ttest_superproject_content origin/add_sub1 &&\n>  \t\t\ttest_dir_is_empty sub1 &&\n>  \t\t\tgit submodule update --init --recursive &&\n> @@ -341,7 +357,10 @@ test_submodule_switch_common () {\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\targ=add_sub1 &&\n> +\t\t\t$before \"$arg\" &&\n> +\t\t\teval $command &&\n> +\t\t\t$after \"$arg\" &&\n>  \t\t\ttest_superproject_content origin/add_sub1 &&\n>  \t\t\ttest_dir_is_empty sub1 &&\n>  \t\t\tgit submodule update --init --recursive &&\n> @@ -356,7 +375,10 @@ test_submodule_switch_common () {\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\targ=replace_file_with_sub1 &&\n> +\t\t\t$before \"$arg\" &&\n> +\t\t\teval $command &&\n> +\t\t\t$after \"$arg\" &&\n>  \t\t\ttest_superproject_content origin/replace_file_with_sub1 &&\n>  \t\t\ttest_dir_is_empty sub1 &&\n>  \t\t\tgit submodule update --init --recursive &&\n> @@ -380,7 +402,10 @@ test_submodule_switch_common () {\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\targ=replace_directory_with_sub1  &&\n> +\t\t\t$before \"$arg\" &&\n> +\t\t\teval $command &&\n> +\t\t\t$after \"$arg\" &&\n>  \t\t\ttest_superproject_content origin/replace_directory_with_sub1 &&\n>  \t\t\ttest_dir_is_empty sub1 &&\n>  \t\t\tgit submodule update --init --recursive &&\n> @@ -402,7 +427,10 @@ test_submodule_switch_common () {\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\targ=remove_sub1 &&\n> +\t\t\t$before \"$arg\" &&\n> +\t\t\teval $command &&\n> +\t\t\t$after \"$arg\" &&\n>  \t\t\ttest_superproject_content origin/remove_sub1 &&\n>  \t\t\ttest_submodule_content sub1 origin/add_sub1\n>  \t\t)\n> @@ -415,7 +443,10 @@ test_submodule_switch_common () {\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\t$command remove_sub1 &&\n> +\t\t\targ=remove_sub1 &&\n> +\t\t\t$before \"$arg\" &&\n> +\t\t\teval $command &&\n> +\t\t\t$after \"$arg\" &&\n>  \t\t\ttest_superproject_content origin/remove_sub1 &&\n>  \t\t\ttest_git_directory_is_unchanged sub1 &&\n>  \t\t\ttest_submodule_content sub1 origin/add_sub1\n> @@ -443,7 +474,9 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_directory &&\n> +\t\t\targ=replace_sub1_with_directory &&\n> +\t\t\t$before \"$arg\" &&\n> +\t\t\teval test_must_fail $command &&\n>  \t\t\ttest_superproject_content origin/add_sub1 &&\n>  \t\t\ttest_submodule_content sub1 origin/add_sub1\n>  \t\t)\n> @@ -456,7 +489,9 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_directory &&\n> +\t\t\targ=replace_sub1_with_directory &&\n> +\t\t\t$before \"$arg\" &&\n> +\t\t\teval test_must_fail $command &&\n>  \t\t\ttest_superproject_content origin/add_sub1 &&\n>  \t\t\ttest_git_directory_is_unchanged sub1 &&\n>  \t\t\ttest_submodule_content sub1 origin/add_sub1\n> @@ -470,7 +505,9 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_file &&\n> +\t\t\targ=replace_sub1_with_file &&\n> +\t\t\t$before \"$arg\" &&\n> +\t\t\teval test_must_fail $command &&\n>  \t\t\ttest_superproject_content origin/add_sub1 &&\n>  \t\t\ttest_submodule_content sub1 origin/add_sub1\n>  \t\t)\n> @@ -484,7 +521,9 @@ test_submodule_switch_common () {\n>  \t\t\tcd submodule_update &&\n>  \t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n>  \t\t\treplace_gitfile_with_git_dir sub1 &&\n> -\t\t\ttest_must_fail $command replace_sub1_with_file &&\n> +\t\t\targ=replace_sub1_with_file &&\n> +\t\t\t$before \"$arg\" &&\n> +\t\t\teval test_must_fail $command &&\n>  \t\t\ttest_superproject_content origin/add_sub1 &&\n>  \t\t\ttest_git_directory_is_unchanged sub1 &&\n>  \t\t\ttest_submodule_content sub1 origin/add_sub1\n> @@ -508,7 +547,10 @@ test_submodule_switch_common () {\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\targ=modify_sub1 &&\n> +\t\t\t$before \"$arg\" &&\n> +\t\t\teval $command &&\n> +\t\t\t$after \"$arg\" &&\n>  \t\t\ttest_superproject_content origin/modify_sub1 &&\n>  \t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n>  \t\t\tgit submodule update &&\n> @@ -523,7 +565,10 @@ test_submodule_switch_common () {\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n>  \t\t\tgit branch -t invalid_sub1 origin/invalid_sub1 &&\n> -\t\t\t$command invalid_sub1 &&\n> +\t\t\targ=invalid_sub1 &&\n> +\t\t\t$before \"$arg\" &&\n> +\t\t\teval $command &&\n> +\t\t\t$after \"$arg\" &&\n>  \t\t\ttest_superproject_content origin/invalid_sub1 &&\n>  \t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n>  \t\t\ttest_must_fail git submodule update &&\n> @@ -538,7 +583,10 @@ test_submodule_switch_common () {\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\targ=valid_sub1 &&\n> +\t\t\t$before \"$arg\" &&\n> +\t\t\teval $command &&\n> +\t\t\t$after \"$arg\" &&\n>  \t\t\ttest_superproject_content origin/valid_sub1 &&\n>  \t\t\ttest_dir_is_empty sub1 &&\n>  \t\t\tgit submodule update --init --recursive &&\n> @@ -568,8 +616,10 @@ test_submodule_switch_common () {\n>  # }\n>  # test_submodule_switch_func \"my_func\"\n>  test_submodule_switch_func () {\n> -\tcommand=\"$1\"\n> -\ttest_submodule_switch_common \"$command\"\n> +\tcommand=\"git $1\"\n> +\tbefore=\"$2\"\n> +\tafter=\"$3\"\n> +\ttest_submodule_switch_common \"$command\" \"$before\" \"$after\"\n>  \n>  \t# An empty directory does not prevent the creation of a submodule of\n>  \t# the same name, but a file does.\n> @@ -580,7 +630,9 @@ test_submodule_switch_func () {\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\targ=add_sub1 &&\n> +\t\t\t$before \"$arg\" &&\n> +\t\t\teval test_must_fail $command &&\n>  \t\t\ttest_superproject_content origin/no_submodule &&\n>  \t\t\ttest_must_be_empty sub1\n>  \t\t)\n> @@ -588,15 +640,15 @@ test_submodule_switch_func () {\n>  }\n>  \n>  test_submodule_switch () {\n> -\ttest_submodule_switch_func \"git $1\"\n> +\ttest_submodule_switch_func \"$1 \\$arg\"\n>  }\n>  \n>  # Same as test_submodule_switch(), except that throwing away local changes in\n>  # the superproject is allowed.\n>  test_submodule_forced_switch () {\n> -\tcommand=\"$1\"\n> +\tcommand=\"git $1 \\$arg\"\n>  \tKNOWN_FAILURE_FORCED_SWITCH_TESTS=1\n> -\ttest_submodule_switch_common \"git $command\"\n> +\ttest_submodule_switch_common \"$command\"\n>  \n>  \t# When forced, a file in the superproject does not prevent creating a\n>  \t# submodule of the same name.\n> @@ -607,7 +659,8 @@ test_submodule_forced_switch () {\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\targ=add_sub1 &&\n> +\t\t\teval $command &&\n>  \t\t\ttest_superproject_content origin/add_sub1 &&\n>  \t\t\ttest_dir_is_empty sub1\n>  \t\t)\n> diff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh\n> index 788605ccc0..d31e6487bd 100755\n> --- a/t/t3426-rebase-submodule.sh\n> +++ b/t/t3426-rebase-submodule.sh\n> @@ -16,11 +16,10 @@ git_rebase () {\n>  \tgit revert HEAD &&\n>  \tgit status -su >actual &&\n>  \tls -1pR * >>actual &&\n> -\ttest_cmp expect actual &&\n> -\tgit rebase \"$1\"\n> +\ttest_cmp expect actual\n>  }\n>  \n> -test_submodule_switch_func \"git_rebase\"\n> +test_submodule_switch_func \"rebase \\$arg\" \"git_rebase\"\n>  \n>  git_rebase_interactive () {\n>  \tgit status -su >expect &&\n> @@ -34,11 +33,10 @@ git_rebase_interactive () {\n>  \tls -1pR * >>actual &&\n>  \ttest_cmp expect actual &&\n>  \tset_fake_editor &&\n> -\techo \"fake-editor.sh\" >.git/info/exclude &&\n> -\tgit rebase -i \"$1\"\n> +\techo \"fake-editor.sh\" >.git/info/exclude\n>  }\n>  \n> -test_submodule_switch_func \"git_rebase_interactive\"\n> +test_submodule_switch_func \"rebase -i \\$arg\" \"git_rebase_interactive\"\n>  \n>  test_expect_success 'rebase interactive ignores modified submodules' '\n>  \ttest_when_finished \"rm -rf super sub\" &&\n> diff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh\n> index 95a7f64471..994cdc40f0 100755\n> --- a/t/t3513-revert-submodule.sh\n> +++ b/t/t3513-revert-submodule.sh\n> @@ -11,11 +11,13 @@ test_description='revert can handle submodules'\n>  # first so we can restore the work tree test setup after doing the checkout\n>  # and revert.  We test here that the restored work tree content is identical\n>  # to that at the beginning. The last revert is then tested by the framework.\n> -git_revert () {\n> +git_revert_before () {\n>  \tgit status -su >expect &&\n>  \tls -1pR * >>expect &&\n> -\ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n> -\tgit checkout \"$1\" &&\n> +\ttar cf \"$TRASH_DIRECTORY/tmp.tar\" *\n> +}\n> +\n> +git_revert_after () {\n>  \tgit revert HEAD &&\n>  \trm -rf * &&\n>  \ttar xf \"$TRASH_DIRECTORY/tmp.tar\" &&\n> @@ -26,6 +28,6 @@ git_revert () {\n>  }\n>  \n>  KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n> -test_submodule_switch_func \"git_revert\"\n> +test_submodule_switch_func \"checkout \\$arg\" \"git_revert_before\" \"git_revert_after\"\n>  \n>  test_done\n> diff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh\n> index 6a7e801ca0..358a625124 100755\n> --- a/t/t3906-stash-submodule.sh\n> +++ b/t/t3906-stash-submodule.sh\n> @@ -5,10 +5,12 @@ test_description='stash can handle submodules'\n>  . ./test-lib.sh\n>  . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n>  \n> -git_stash () {\n> +git_stash_before () {\n>  \tgit status -su >expect &&\n> -\tls -1pR * >>expect &&\n> -\tgit read-tree -u -m \"$1\" &&\n> +\tls -1pR * >>expect\n> +}\n> +\n> +git_stash_after () {\n>  \tgit stash &&\n>  \tgit status -su >actual &&\n>  \tls -1pR * >>actual &&\n> @@ -19,7 +21,7 @@ git_stash () {\n>  KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES=1\n>  KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1\n>  KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n> -test_submodule_switch_func \"git_stash\"\n> +test_submodule_switch_func \"read-tree -u -m \\$arg\" \"git_stash_before\" \"git_stash_after\"\n>  \n>  setup_basic () {\n>  \ttest_when_finished \"rm -rf main sub\" &&\n> diff --git a/t/t4137-apply-submodule.sh b/t/t4137-apply-submodule.sh\n> index b645e303a0..fe5ebeaa41 100755\n> --- a/t/t4137-apply-submodule.sh\n> +++ b/t/t4137-apply-submodule.sh\n> @@ -5,16 +5,12 @@ test_description='git apply handling submodules'\n>  . ./test-lib.sh\n>  . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n>  \n> -apply_index () {\n> -\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --index -\n> +create_diff () {\n> +\tgit diff --ignore-submodules=dirty \"..$1\" >diff\n>  }\n>  \n> -test_submodule_switch_func \"apply_index\"\n> +test_submodule_switch_func \"apply --index diff\" \"create_diff\"\n>  \n> -apply_3way () {\n> -\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --3way -\n> -}\n> -\n> -test_submodule_switch_func \"apply_3way\"\n> +test_submodule_switch_func \"apply --3way diff\" \"create_diff\"\n>  \n>  test_done\n> diff --git a/t/t4255-am-submodule.sh b/t/t4255-am-submodule.sh\n> index 1b179d5f45..5305280dfd 100755\n> --- a/t/t4255-am-submodule.sh\n> +++ b/t/t4255-am-submodule.sh\n> @@ -5,18 +5,14 @@ test_description='git am handling submodules'\n>  . ./test-lib.sh\n>  . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n>  \n> -am () {\n> -\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am -\n> +create_patch () {\n> +\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" >patch\n>  }\n>  \n> -test_submodule_switch_func \"am\"\n> -\n> -am_3way () {\n> -\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am --3way -\n> -}\n> +test_submodule_switch_func \"am patch\" \"create_patch\"\n>  \n>  KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n> -test_submodule_switch_func \"am_3way\"\n> +test_submodule_switch_func \"am --3way patch\" \"create_patch\"\n>  \n>  test_expect_success 'setup diff.submodule' '\n>  \ttest_commit one &&\n> diff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh\n> index f911bf631e..3b37853537 100755\n> --- a/t/t5572-pull-submodule.sh\n> +++ b/t/t5572-pull-submodule.sh\n> @@ -11,36 +11,16 @@ reset_branch_to_HEAD () {\n>  \tgit branch --set-upstream-to=\"origin/$1\" \"$1\"\n>  }\n>  \n> -git_pull () {\n> -\treset_branch_to_HEAD \"$1\" &&\n> -\tgit pull\n> -}\n> -\n>  # pulls without conflicts\n> -test_submodule_switch_func \"git_pull\"\n> +test_submodule_switch_func \"pull\" \"reset_branch_to_HEAD\"\n>  \n> -git_pull_ff () {\n> -\treset_branch_to_HEAD \"$1\" &&\n> -\tgit pull --ff\n> -}\n> +test_submodule_switch_func \"pull --ff\" \"reset_branch_to_HEAD\"\n>  \n> -test_submodule_switch_func \"git_pull_ff\"\n> -\n> -git_pull_ff_only () {\n> -\treset_branch_to_HEAD \"$1\" &&\n> -\tgit pull --ff-only\n> -}\n> -\n> -test_submodule_switch_func \"git_pull_ff_only\"\n> -\n> -git_pull_noff () {\n> -\treset_branch_to_HEAD \"$1\" &&\n> -\tgit pull --no-ff\n> -}\n> +test_submodule_switch_func \"pull --ff-only\" \"reset_branch_to_HEAD\"\n>  \n>  KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n>  KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n> -test_submodule_switch_func \"git_pull_noff\"\n> +test_submodule_switch_func \"pull --no-ff\" \"reset_branch_to_HEAD\"\n>  \n>  test_expect_success 'pull --recurse-submodule setup' '\n>  \ttest_create_repo child &&\n> diff --git a/t/t6041-bisect-submodule.sh b/t/t6041-bisect-submodule.sh\n> index 0e0cdf638d..b99e81d55d 100755\n> --- a/t/t6041-bisect-submodule.sh\n> +++ b/t/t6041-bisect-submodule.sh\n> @@ -5,12 +5,14 @@ test_description='bisect can handle submodules'\n>  . ./test-lib.sh\n>  . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n>  \n> -git_bisect () {\n> +git_bisect_before () {\n>  \tgit status -su >expect &&\n>  \tls -1pR * >>expect &&\n>  \ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n> -\tGOOD=$(git rev-parse --verify HEAD) &&\n> -\tgit checkout \"$1\" &&\n> +\tGOOD=$(git rev-parse --verify HEAD)\n> +}\n> +\n> +git_bisect_after () {\n>  \techo \"foo\" >bar &&\n>  \tgit add bar &&\n>  \tgit commit -m \"bisect bad\" &&\n> @@ -27,6 +29,6 @@ git_bisect () {\n>  \tgit bisect bad $BAD\n>  }\n>  \n> -test_submodule_switch_func \"git_bisect\"\n> +test_submodule_switch_func \"checkout \\$arg\" \"git_bisect_before\" \"git_bisect_after\"\n>  \n>  test_done\n"},{"id":"400040","messageId":"cover.1592470068.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1591897173.git.liu.denton@gmail.com","subject":"[PATCH v4 0/4] t: replace incorrect test_must_fail usage (part 5)","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-06-18T08:49:10Z","receivedAt":"2020-06-18T08:49:26Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"Hi all,\n\nThis revision of the series just improves on some of the documentation\nand add addresses one of Junio's comments. Aside from that, the code\nremains the same.\n\n\nThe overall scope of these patches is to replace inappropriate uses of\ntest_must_fail. IOW, we should only allow test_must_fail to run on `git`\nand `test-tool`. Ultimately, we will conclude by making test_must_fail\nerror out on non-git commands. An advance view of the final series can\nbe found here[1].\n\nThis is the fifth part. It focuses on lib-submodule-update.sh and tests\nthat make use of it.\n\nThe first part can be found here[2]. The second part can be found\nhere[3]. The third part can be found here[4]. The fourth part can be\nfound here[5].\n\nChanges since v1.2:\n\n* In \"lib-submodule-update: pass OVERWRITING_FAIL\", use if-then return\n  to reduce the amount of code churn\n\nChanges since v2:\n\n* Replace the OVERWRITING_FAIL approach with callback functions as\n  suggested by Peff[6]\n\nChanges since v3:\n\n* Simply handling of empty $before and $after\n\n* Add more comments on the usage of the helper functions\n\n[1]: (may be rebased at any time) https://github.com/Denton-L/git/tree/ready/cleanup-test-must-fail2\n[2]: https://lore.kernel.org/git/cover.1576583819.git.liu.denton@gmail.com/\n[3]: https://lore.kernel.org/git/cover.1577454401.git.liu.denton@gmail.com/\n[4]: https://lore.kernel.org/git/cover.1585209554.git.liu.denton@gmail.com/\n[5]: https://lore.kernel.org/git/cover.1587372771.git.liu.denton@gmail.com/\n[6]: https://lore.kernel.org/git/20200521182928.GA1308647@coredump.intra.peff.net/\n\nDenton Liu (4):\n  lib-submodule-update: add space after function name\n  lib-submodule-update: consolidate --recurse-submodules\n  lib-submodule-update: prepend \"git\" to $command\n  lib-submodule-update: use callbacks in test_submodule_switch_common()\n\n t/lib-submodule-update.sh        | 135 +++++++++++++++++++++++--------\n t/t1013-read-tree-submodule.sh   |   4 +-\n t/t2013-checkout-submodule.sh    |   4 +-\n t/t3426-rebase-submodule.sh      |  10 +--\n t/t3512-cherry-pick-submodule.sh |   2 +-\n t/t3513-revert-submodule.sh      |  10 ++-\n t/t3906-stash-submodule.sh       |  10 ++-\n t/t4137-apply-submodule.sh       |  12 +--\n t/t4255-am-submodule.sh          |  12 +--\n t/t5572-pull-submodule.sh        |  28 +------\n t/t6041-bisect-submodule.sh      |  10 ++-\n t/t7112-reset-submodule.sh       |   6 +-\n t/t7613-merge-submodule.sh       |   8 +-\n 13 files changed, 148 insertions(+), 103 deletions(-)\n\nRange-diff against v3:\n1:  ba2f642e0f = 1:  ba2f642e0f lib-submodule-update: add space after function name\n2:  16d0a3eb9a = 2:  16d0a3eb9a lib-submodule-update: consolidate --recurse-submodules\n3:  09446be5b9 = 3:  09446be5b9 lib-submodule-update: prepend \"git\" to $command\n4:  74e6086da4 ! 4:  35d07117e6 lib-submodule-update: use callbacks in test_submodule_switch_common()\n    @@ Commit message\n         If the command requires a filename argument, specify it as `\\$arg` since\n         that variable will be set and the whole $command string will be eval'd.\n         Unfortunately, there is no way to get rid of the eval as some of the\n    -    commands are passed (such as the `git pull` tests) require that no\n    +    commands that are passed (such as the `git pull` tests) require that no\n         additional arguments are passed so we must have some mechanism for the\n         caller to specify whether or not it wants the filename argument.\n     \n    @@ Commit message\n         Finally, as an added bonus, `test_must_fail` will only run on $command\n         which is guaranteed to be a git command.\n     \n    -    An alternate design was considered where the $OVERWRITING_FAIL is set\n    -    from the test_submodule_switch_common() function and passed to the\n    -    helper function. This approach was considered too difficult to\n    -    understand due to the fact that using a signalling magic environment\n    -    variable might be too indirect.\n    +    An alternate design was considered where $OVERWRITING_FAIL is set from\n    +    test_submodule_switch_common() and exposed to the helper function. This\n    +    approach was considered too difficult to understand due to the fact that\n    +    using a signalling magic environment variable might be too indirect.\n     \n      ## t/lib-submodule-update.sh ##\n     @@ t/lib-submodule-update.sh: test_submodule_content () {\n    + # Removing a submodule containing a .git directory must fail even when forced\n    + # to protect the history!\n    + #\n    ++# $1: The git command to be eval'd and tested. The submodule being operated on\n    ++# will be available as $arg.\n    ++#\n    ++# $2: The function that will run before the git command. It will be passed the\n    ++# submodule being operated on as the only argument. This argument is optional.\n    ++#\n    ++# $3: The function that will run after $1. It will be passed the submodule\n    ++# being operated on as the only argument. This argument is optional. It will\n    ++# not be run when testing a case where the git command is expected to fail.\n    + \n      # Internal function; use test_submodule_switch_func(), test_submodule_switch(),\n      # or test_submodule_forced_switch() instead.\n      test_submodule_switch_common () {\n     -\tcommand=\"$1\"\n    -+\tcommand=\"$1\" # should be a git command\n    -+\tbefore=\"$2\"\n    -+\tafter=\"$3\"\n    -+\n    -+\tif test -z \"$before\"\n    -+\tthen\n    -+\t\tbefore=true\n    -+\tfi\n    -+\n    -+\tif test -z \"$after\"\n    -+\tthen\n    -+\t\tafter=true\n    -+\tfi\n    ++\tcommand=\"$1\" before=\"${2:-true}\" after=\"${3:-true}\"\n     +\n      \t######################### Appearing submodule #########################\n      \t# Switching to a commit letting a submodule appear creates empty dir ...\n    @@ t/lib-submodule-update.sh: test_submodule_switch_common () {\n      \t\t\ttest_dir_is_empty sub1 &&\n      \t\t\tgit submodule update --init --recursive &&\n     @@ t/lib-submodule-update.sh: test_submodule_switch_common () {\n    + # conditions, set the appropriate KNOWN_FAILURE_* variable used in the tests\n    + # below to 1.\n    + #\n    +-# Use as follows:\n    ++# $1: The git command to be eval'd and tested. The submodule being operated on\n    ++# will be available as $arg. Do not include the leading \"git\".\n    + #\n    +-# my_func () {\n    ++# $2: The function that will run before the git command. It will be passed the\n    ++# submodule being operated on as the only argument. This argument is optional.\n    ++#\n    ++# $3: The function that will run after $1. It will be passed the submodule\n    ++# being operated on as the only argument. This argument is optional. It will\n    ++# not be run when testing a case where the git command is expected to fail.\n    ++#\n    ++# The following example uses `git some-command` as an example command to be\n    ++# tested. It updates the worktree and index to match a target, but not any\n    ++# submodule directories.\n    ++#\n    ++# my_func_before () {\n    + #   target=$1\n    +-#   # Do something here that updates the worktree and index to match target,\n    +-#   # but not any submodule directories.\n    ++#   # Prepare for git some-command to be run\n      # }\n    - # test_submodule_switch_func \"my_func\"\n    +-# test_submodule_switch_func \"my_func\"\n    ++# my_func_after () {\n    ++#   target=$1\n    ++#   # Check the state after git some-command is run\n    ++# }\n    ++# test_submodule_switch_func \"some-command \\$arg\" \"my_func_before\" \"my_func_after\"\n      test_submodule_switch_func () {\n     -\tcommand=\"$1\"\n     -\ttest_submodule_switch_common \"$command\"\n-- \n2.27.0.132.g321788e831\n\n"},{"id":"400041","messageId":"ba2f642e0f505730d5d740207128036448787c8c.1592470068.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1592470068.git.liu.denton@gmail.com","subject":"[PATCH v4 1/4] lib-submodule-update: add space after function name","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-06-18T08:49:11Z","receivedAt":"2020-06-18T08:49:26Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"In the shell scripts in this codebase, the usual style is to include a\nspace between the function name and the (). Add these missing spaces to\nconform to the usual style of the code.\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\n t/lib-submodule-update.sh | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 1dd17fc03e..122554acd6 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -183,7 +183,7 @@ test_git_directory_is_unchanged () {\n \t)\n }\n \n-test_git_directory_exists() {\n+test_git_directory_exists () {\n \ttest -e \".git/modules/$1\" &&\n \tif test -f sub1/.git\n \tthen\n@@ -309,7 +309,7 @@ test_submodule_content () {\n \n # Internal function; use test_submodule_switch() or\n # test_submodule_forced_switch() instead.\n-test_submodule_switch_common() {\n+test_submodule_switch_common () {\n \tcommand=\"$1\"\n \t######################### Appearing submodule #########################\n \t# Switching to a commit letting a submodule appear creates empty dir ...\n@@ -629,7 +629,7 @@ test_submodule_forced_switch () {\n \n # Internal function; use test_submodule_switch_recursing_with_args() or\n # test_submodule_forced_switch_recursing_with_args() instead.\n-test_submodule_recursing_with_args_common() {\n+test_submodule_recursing_with_args_common () {\n \tcommand=\"$1\"\n \n \t######################### Appearing submodule #########################\n-- \n2.27.0.132.g321788e831\n\n"},{"id":"400042","messageId":"16d0a3eb9ac8dcda701433a9e67cde5103949432.1592470068.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1592470068.git.liu.denton@gmail.com","subject":"[PATCH v4 2/4] lib-submodule-update: consolidate --recurse-submodules","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-06-18T08:49:12Z","receivedAt":"2020-06-18T08:49:33Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"Both test_submodule_switch_recursing_with_args() and\ntest_submodule_forced_switch_recursing_with_args() call the internal\nfunction test_submodule_recursing_with_args_common() with the final\nargument of `--recurse-submodules`. Consolidate this duplication by\nappending the argument in test_submodule_recursing_with_args_common().\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\n t/lib-submodule-update.sh | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 122554acd6..bb36287803 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -630,7 +630,7 @@ test_submodule_forced_switch () {\n # Internal function; use test_submodule_switch_recursing_with_args() or\n # test_submodule_forced_switch_recursing_with_args() instead.\n test_submodule_recursing_with_args_common () {\n-\tcommand=\"$1\"\n+\tcommand=\"$1 --recurse-submodules\"\n \n \t######################### Appearing submodule #########################\n \t# Switching to a commit letting a submodule appear checks it out ...\n@@ -809,7 +809,7 @@ test_submodule_recursing_with_args_common () {\n # test_submodule_switch_recursing_with_args \"$GIT_COMMAND\"\n test_submodule_switch_recursing_with_args () {\n \tcmd_args=\"$1\"\n-\tcommand=\"git $cmd_args --recurse-submodules\"\n+\tcommand=\"git $cmd_args\"\n \ttest_submodule_recursing_with_args_common \"$command\"\n \n \tRESULTDS=success\n@@ -927,7 +927,7 @@ test_submodule_switch_recursing_with_args () {\n # away local changes in the superproject is allowed.\n test_submodule_forced_switch_recursing_with_args () {\n \tcmd_args=\"$1\"\n-\tcommand=\"git $cmd_args --recurse-submodules\"\n+\tcommand=\"git $cmd_args\"\n \ttest_submodule_recursing_with_args_common \"$command\"\n \n \tRESULT=success\n-- \n2.27.0.132.g321788e831\n\n"},{"id":"400043","messageId":"09446be5b9e9d6291dae3531a93b588e0b7a1c3f.1592470068.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1592470068.git.liu.denton@gmail.com","subject":"[PATCH v4 3/4] lib-submodule-update: prepend \"git\" to $command","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-06-18T08:49:13Z","receivedAt":"2020-06-18T08:49:37Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"Since all invocations of test_submodule_forced_switch() are git\ncommands, automatically prepend \"git\" before invoking\ntest_submodule_switch_common().\n\nSimilarly, many invocations of test_submodule_switch() are also git\ncommands so automatically prepend \"git\" before invoking\ntest_submodule_switch_common() as well.\n\nFinally, for invocations of test_submodule_switch() that invoke a custom\nfunction, rename the old function to test_submodule_switch_func().\n\nThis is necessary because in a future commit, we will be adding some\nlogic that needs to distinguish between an invocation of a plain git\ncomamnd and an invocation of a test helper function.\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\n t/lib-submodule-update.sh        | 14 +++++++++-----\n t/t1013-read-tree-submodule.sh   |  4 ++--\n t/t2013-checkout-submodule.sh    |  4 ++--\n t/t3426-rebase-submodule.sh      |  4 ++--\n t/t3512-cherry-pick-submodule.sh |  2 +-\n t/t3513-revert-submodule.sh      |  2 +-\n t/t3906-stash-submodule.sh       |  2 +-\n t/t4137-apply-submodule.sh       |  4 ++--\n t/t4255-am-submodule.sh          |  4 ++--\n t/t5572-pull-submodule.sh        |  8 ++++----\n t/t6041-bisect-submodule.sh      |  2 +-\n t/t7112-reset-submodule.sh       |  6 +++---\n t/t7613-merge-submodule.sh       |  8 ++++----\n 13 files changed, 34 insertions(+), 30 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex bb36287803..7c3ba1be00 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -307,8 +307,8 @@ test_submodule_content () {\n # to protect the history!\n #\n \n-# Internal function; use test_submodule_switch() or\n-# test_submodule_forced_switch() instead.\n+# Internal function; use test_submodule_switch_func(), test_submodule_switch(),\n+# or test_submodule_forced_switch() instead.\n test_submodule_switch_common () {\n \tcommand=\"$1\"\n \t######################### Appearing submodule #########################\n@@ -566,8 +566,8 @@ test_submodule_switch_common () {\n #   # Do something here that updates the worktree and index to match target,\n #   # but not any submodule directories.\n # }\n-# test_submodule_switch \"my_func\"\n-test_submodule_switch () {\n+# test_submodule_switch_func \"my_func\"\n+test_submodule_switch_func () {\n \tcommand=\"$1\"\n \ttest_submodule_switch_common \"$command\"\n \n@@ -587,12 +587,16 @@ test_submodule_switch () {\n \t'\n }\n \n+test_submodule_switch () {\n+\ttest_submodule_switch_func \"git $1\"\n+}\n+\n # Same as test_submodule_switch(), except that throwing away local changes in\n # the superproject is allowed.\n test_submodule_forced_switch () {\n \tcommand=\"$1\"\n \tKNOWN_FAILURE_FORCED_SWITCH_TESTS=1\n-\ttest_submodule_switch_common \"$command\"\n+\ttest_submodule_switch_common \"git $command\"\n \n \t# When forced, a file in the superproject does not prevent creating a\n \t# submodule of the same name.\ndiff --git a/t/t1013-read-tree-submodule.sh b/t/t1013-read-tree-submodule.sh\nindex 91a6fafcb4..b6df7444c0 100755\n--- a/t/t1013-read-tree-submodule.sh\n+++ b/t/t1013-read-tree-submodule.sh\n@@ -12,8 +12,8 @@ test_submodule_switch_recursing_with_args \"read-tree -u -m\"\n \n test_submodule_forced_switch_recursing_with_args \"read-tree -u --reset\"\n \n-test_submodule_switch \"git read-tree -u -m\"\n+test_submodule_switch \"read-tree -u -m\"\n \n-test_submodule_forced_switch \"git read-tree -u --reset\"\n+test_submodule_forced_switch \"read-tree -u --reset\"\n \n test_done\ndiff --git a/t/t2013-checkout-submodule.sh b/t/t2013-checkout-submodule.sh\nindex 8f86b5f4b2..b2bdd1fcb4 100755\n--- a/t/t2013-checkout-submodule.sh\n+++ b/t/t2013-checkout-submodule.sh\n@@ -68,8 +68,8 @@ test_submodule_switch_recursing_with_args \"checkout\"\n \n test_submodule_forced_switch_recursing_with_args \"checkout -f\"\n \n-test_submodule_switch \"git checkout\"\n+test_submodule_switch \"checkout\"\n \n-test_submodule_forced_switch \"git checkout -f\"\n+test_submodule_forced_switch \"checkout -f\"\n \n test_done\ndiff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh\nindex a2bba04ba9..788605ccc0 100755\n--- a/t/t3426-rebase-submodule.sh\n+++ b/t/t3426-rebase-submodule.sh\n@@ -20,7 +20,7 @@ git_rebase () {\n \tgit rebase \"$1\"\n }\n \n-test_submodule_switch \"git_rebase\"\n+test_submodule_switch_func \"git_rebase\"\n \n git_rebase_interactive () {\n \tgit status -su >expect &&\n@@ -38,7 +38,7 @@ git_rebase_interactive () {\n \tgit rebase -i \"$1\"\n }\n \n-test_submodule_switch \"git_rebase_interactive\"\n+test_submodule_switch_func \"git_rebase_interactive\"\n \n test_expect_success 'rebase interactive ignores modified submodules' '\n \ttest_when_finished \"rm -rf super sub\" &&\ndiff --git a/t/t3512-cherry-pick-submodule.sh b/t/t3512-cherry-pick-submodule.sh\nindex bd78287841..6ece1d8573 100755\n--- a/t/t3512-cherry-pick-submodule.sh\n+++ b/t/t3512-cherry-pick-submodule.sh\n@@ -7,7 +7,7 @@ test_description='cherry-pick can handle submodules'\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-test_submodule_switch \"git cherry-pick\"\n+test_submodule_switch \"cherry-pick\"\n \n test_expect_success 'unrelated submodule/file conflict is ignored' '\n \ttest_create_repo sub &&\ndiff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh\nindex 5e39fcdb66..95a7f64471 100755\n--- a/t/t3513-revert-submodule.sh\n+++ b/t/t3513-revert-submodule.sh\n@@ -26,6 +26,6 @@ git_revert () {\n }\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-test_submodule_switch \"git_revert\"\n+test_submodule_switch_func \"git_revert\"\n \n test_done\ndiff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh\nindex b93d1d74da..6a7e801ca0 100755\n--- a/t/t3906-stash-submodule.sh\n+++ b/t/t3906-stash-submodule.sh\n@@ -19,7 +19,7 @@ git_stash () {\n KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES=1\n KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1\n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-test_submodule_switch \"git_stash\"\n+test_submodule_switch_func \"git_stash\"\n \n setup_basic () {\n \ttest_when_finished \"rm -rf main sub\" &&\ndiff --git a/t/t4137-apply-submodule.sh b/t/t4137-apply-submodule.sh\nindex a9bd40a6d0..b645e303a0 100755\n--- a/t/t4137-apply-submodule.sh\n+++ b/t/t4137-apply-submodule.sh\n@@ -9,12 +9,12 @@ apply_index () {\n \tgit diff --ignore-submodules=dirty \"..$1\" | git apply --index -\n }\n \n-test_submodule_switch \"apply_index\"\n+test_submodule_switch_func \"apply_index\"\n \n apply_3way () {\n \tgit diff --ignore-submodules=dirty \"..$1\" | git apply --3way -\n }\n \n-test_submodule_switch \"apply_3way\"\n+test_submodule_switch_func \"apply_3way\"\n \n test_done\ndiff --git a/t/t4255-am-submodule.sh b/t/t4255-am-submodule.sh\nindex 0ba8194403..1b179d5f45 100755\n--- a/t/t4255-am-submodule.sh\n+++ b/t/t4255-am-submodule.sh\n@@ -9,14 +9,14 @@ am () {\n \tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am -\n }\n \n-test_submodule_switch \"am\"\n+test_submodule_switch_func \"am\"\n \n am_3way () {\n \tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am --3way -\n }\n \n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-test_submodule_switch \"am_3way\"\n+test_submodule_switch_func \"am_3way\"\n \n test_expect_success 'setup diff.submodule' '\n \ttest_commit one &&\ndiff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh\nindex f916729a12..f911bf631e 100755\n--- a/t/t5572-pull-submodule.sh\n+++ b/t/t5572-pull-submodule.sh\n@@ -17,21 +17,21 @@ git_pull () {\n }\n \n # pulls without conflicts\n-test_submodule_switch \"git_pull\"\n+test_submodule_switch_func \"git_pull\"\n \n git_pull_ff () {\n \treset_branch_to_HEAD \"$1\" &&\n \tgit pull --ff\n }\n \n-test_submodule_switch \"git_pull_ff\"\n+test_submodule_switch_func \"git_pull_ff\"\n \n git_pull_ff_only () {\n \treset_branch_to_HEAD \"$1\" &&\n \tgit pull --ff-only\n }\n \n-test_submodule_switch \"git_pull_ff_only\"\n+test_submodule_switch_func \"git_pull_ff_only\"\n \n git_pull_noff () {\n \treset_branch_to_HEAD \"$1\" &&\n@@ -40,7 +40,7 @@ git_pull_noff () {\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-test_submodule_switch \"git_pull_noff\"\n+test_submodule_switch_func \"git_pull_noff\"\n \n test_expect_success 'pull --recurse-submodule setup' '\n \ttest_create_repo child &&\ndiff --git a/t/t6041-bisect-submodule.sh b/t/t6041-bisect-submodule.sh\nindex 62b8a2e7bb..0e0cdf638d 100755\n--- a/t/t6041-bisect-submodule.sh\n+++ b/t/t6041-bisect-submodule.sh\n@@ -27,6 +27,6 @@ git_bisect () {\n \tgit bisect bad $BAD\n }\n \n-test_submodule_switch \"git_bisect\"\n+test_submodule_switch_func \"git_bisect\"\n \n test_done\ndiff --git a/t/t7112-reset-submodule.sh b/t/t7112-reset-submodule.sh\nindex a1cb9ff858..8741b665c9 100755\n--- a/t/t7112-reset-submodule.sh\n+++ b/t/t7112-reset-submodule.sh\n@@ -13,10 +13,10 @@ test_submodule_switch_recursing_with_args \"reset --keep\"\n \n test_submodule_forced_switch_recursing_with_args \"reset --hard\"\n \n-test_submodule_switch \"git reset --keep\"\n+test_submodule_switch \"reset --keep\"\n \n-test_submodule_switch \"git reset --merge\"\n+test_submodule_switch \"reset --merge\"\n \n-test_submodule_forced_switch \"git reset --hard\"\n+test_submodule_forced_switch \"reset --hard\"\n \n test_done\ndiff --git a/t/t7613-merge-submodule.sh b/t/t7613-merge-submodule.sh\nindex d1e9fcc781..04bf4be7d7 100755\n--- a/t/t7613-merge-submodule.sh\n+++ b/t/t7613-merge-submodule.sh\n@@ -6,14 +6,14 @@ test_description='merge can handle submodules'\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n # merges without conflicts\n-test_submodule_switch \"git merge\"\n+test_submodule_switch \"merge\"\n \n-test_submodule_switch \"git merge --ff\"\n+test_submodule_switch \"merge --ff\"\n \n-test_submodule_switch \"git merge --ff-only\"\n+test_submodule_switch \"merge --ff-only\"\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-test_submodule_switch \"git merge --no-ff\"\n+test_submodule_switch \"merge --no-ff\"\n \n test_done\n-- \n2.27.0.132.g321788e831\n\n"},{"id":"400044","messageId":"35d07117e637edf5f9a148a50da6b2294ec0f87f.1592470068.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1592470068.git.liu.denton@gmail.com","subject":"[PATCH v4 4/4] lib-submodule-update: use callbacks in test_submodule_switch_common()","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-06-18T08:49:14Z","receivedAt":"2020-06-18T08:49:39Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"When we run a test helper function in test_submodule_switch_common(), we\nsometimes specify a whole helper function as the $command. When we do\nthis, in some test cases, we just mark the whole function with\n`test_must_fail`. However, it's possible that the helper function might\nfail earlier or later than expected due to an introduced bug. If this\nhappens, then the test case will still report as passing but it should\nreally be marked as failing since it didn't actually display the\nintended behaviour.\n\nInstead of invoking $command as one monolithic helper function, break it\nup into three parts:\n\n\t1. $command which is always a git command.\n\t2. $before which is a callback function that runs just prior to\n\t   $command.\n\t3. $after which is a callback function that runs just after\n\t   $command.\n\nIf the command requires a filename argument, specify it as `\\$arg` since\nthat variable will be set and the whole $command string will be eval'd.\nUnfortunately, there is no way to get rid of the eval as some of the\ncommands that are passed (such as the `git pull` tests) require that no\nadditional arguments are passed so we must have some mechanism for the\ncaller to specify whether or not it wants the filename argument.\n\nThe $before and $after callback functions will be passed the filename as\nthe first arg. These callback functions are optional and, if missing,\nwill be replaced with `true`. Also, in the case where we have a\n`test_must_fail` test, $after will not be executed, similar to how the\nhelper functions currently behave when the git command fails and exits\nthe &&-chain.\n\nFinally, as an added bonus, `test_must_fail` will only run on $command\nwhich is guaranteed to be a git command.\n\nAn alternate design was considered where $OVERWRITING_FAIL is set from\ntest_submodule_switch_common() and exposed to the helper function. This\napproach was considered too difficult to understand due to the fact that\nusing a signalling magic environment variable might be too indirect.\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\n t/lib-submodule-update.sh   | 117 ++++++++++++++++++++++++++++--------\n t/t3426-rebase-submodule.sh |  10 ++-\n t/t3513-revert-submodule.sh |  10 +--\n t/t3906-stash-submodule.sh  |  10 +--\n t/t4137-apply-submodule.sh  |  12 ++--\n t/t4255-am-submodule.sh     |  12 ++--\n t/t5572-pull-submodule.sh   |  28 ++-------\n t/t6041-bisect-submodule.sh |  10 +--\n 8 files changed, 125 insertions(+), 84 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 7c3ba1be00..3401a59ad8 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -306,11 +306,21 @@ test_submodule_content () {\n # Removing a submodule containing a .git directory must fail even when forced\n # to protect the history!\n #\n+# $1: The git command to be eval'd and tested. The submodule being operated on\n+# will be available as $arg.\n+#\n+# $2: The function that will run before the git command. It will be passed the\n+# submodule being operated on as the only argument. This argument is optional.\n+#\n+# $3: The function that will run after $1. It will be passed the submodule\n+# being operated on as the only argument. This argument is optional. It will\n+# not be run when testing a case where the git command is expected to fail.\n \n # Internal function; use test_submodule_switch_func(), test_submodule_switch(),\n # or test_submodule_forced_switch() instead.\n test_submodule_switch_common () {\n-\tcommand=\"$1\"\n+\tcommand=\"$1\" before=\"${2:-true}\" after=\"${3:-true}\"\n+\n \t######################### Appearing submodule #########################\n \t# Switching to a commit letting a submodule appear creates empty dir ...\n \tif test \"$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES\" = 1\n@@ -326,7 +336,10 @@ test_submodule_switch_common () {\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\targ=add_sub1 &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval $command &&\n+\t\t\t$after \"$arg\" &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n \t\t\tgit submodule update --init --recursive &&\n@@ -341,7 +354,10 @@ test_submodule_switch_common () {\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\targ=add_sub1 &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval $command &&\n+\t\t\t$after \"$arg\" &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n \t\t\tgit submodule update --init --recursive &&\n@@ -356,7 +372,10 @@ test_submodule_switch_common () {\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\targ=replace_file_with_sub1 &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval $command &&\n+\t\t\t$after \"$arg\" &&\n \t\t\ttest_superproject_content origin/replace_file_with_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n \t\t\tgit submodule update --init --recursive &&\n@@ -380,7 +399,10 @@ test_submodule_switch_common () {\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\targ=replace_directory_with_sub1  &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval $command &&\n+\t\t\t$after \"$arg\" &&\n \t\t\ttest_superproject_content origin/replace_directory_with_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n \t\t\tgit submodule update --init --recursive &&\n@@ -402,7 +424,10 @@ test_submodule_switch_common () {\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\targ=remove_sub1 &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval $command &&\n+\t\t\t$after \"$arg\" &&\n \t\t\ttest_superproject_content origin/remove_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -415,7 +440,10 @@ test_submodule_switch_common () {\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\t$command remove_sub1 &&\n+\t\t\targ=remove_sub1 &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval $command &&\n+\t\t\t$after \"$arg\" &&\n \t\t\ttest_superproject_content origin/remove_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -443,7 +471,9 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\targ=replace_sub1_with_directory &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval test_must_fail $command &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -456,7 +486,9 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\targ=replace_sub1_with_directory &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval test_must_fail $command &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -470,7 +502,9 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\targ=replace_sub1_with_file &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval test_must_fail $command &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -484,7 +518,9 @@ test_submodule_switch_common () {\n \t\t\tcd submodule_update &&\n \t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n \t\t\treplace_gitfile_with_git_dir sub1 &&\n-\t\t\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\targ=replace_sub1_with_file &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval test_must_fail $command &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -508,7 +544,10 @@ test_submodule_switch_common () {\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\targ=modify_sub1 &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval $command &&\n+\t\t\t$after \"$arg\" &&\n \t\t\ttest_superproject_content origin/modify_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n \t\t\tgit submodule update &&\n@@ -523,7 +562,10 @@ test_submodule_switch_common () {\n \t\t(\n \t\t\tcd submodule_update &&\n \t\t\tgit branch -t invalid_sub1 origin/invalid_sub1 &&\n-\t\t\t$command invalid_sub1 &&\n+\t\t\targ=invalid_sub1 &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval $command &&\n+\t\t\t$after \"$arg\" &&\n \t\t\ttest_superproject_content origin/invalid_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n \t\t\ttest_must_fail git submodule update &&\n@@ -538,7 +580,10 @@ test_submodule_switch_common () {\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\targ=valid_sub1 &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval $command &&\n+\t\t\t$after \"$arg\" &&\n \t\t\ttest_superproject_content origin/valid_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n \t\t\tgit submodule update --init --recursive &&\n@@ -559,17 +604,34 @@ test_submodule_switch_common () {\n # conditions, set the appropriate KNOWN_FAILURE_* variable used in the tests\n # below to 1.\n #\n-# Use as follows:\n+# $1: The git command to be eval'd and tested. The submodule being operated on\n+# will be available as $arg. Do not include the leading \"git\".\n #\n-# my_func () {\n+# $2: The function that will run before the git command. It will be passed the\n+# submodule being operated on as the only argument. This argument is optional.\n+#\n+# $3: The function that will run after $1. It will be passed the submodule\n+# being operated on as the only argument. This argument is optional. It will\n+# not be run when testing a case where the git command is expected to fail.\n+#\n+# The following example uses `git some-command` as an example command to be\n+# tested. It updates the worktree and index to match a target, but not any\n+# submodule directories.\n+#\n+# my_func_before () {\n #   target=$1\n-#   # Do something here that updates the worktree and index to match target,\n-#   # but not any submodule directories.\n+#   # Prepare for git some-command to be run\n # }\n-# test_submodule_switch_func \"my_func\"\n+# my_func_after () {\n+#   target=$1\n+#   # Check the state after git some-command is run\n+# }\n+# test_submodule_switch_func \"some-command \\$arg\" \"my_func_before\" \"my_func_after\"\n test_submodule_switch_func () {\n-\tcommand=\"$1\"\n-\ttest_submodule_switch_common \"$command\"\n+\tcommand=\"git $1\"\n+\tbefore=\"$2\"\n+\tafter=\"$3\"\n+\ttest_submodule_switch_common \"$command\" \"$before\" \"$after\"\n \n \t# An empty directory does not prevent the creation of a submodule of\n \t# the same name, but a file does.\n@@ -580,7 +642,9 @@ test_submodule_switch_func () {\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\targ=add_sub1 &&\n+\t\t\t$before \"$arg\" &&\n+\t\t\teval test_must_fail $command &&\n \t\t\ttest_superproject_content origin/no_submodule &&\n \t\t\ttest_must_be_empty sub1\n \t\t)\n@@ -588,15 +652,15 @@ test_submodule_switch_func () {\n }\n \n test_submodule_switch () {\n-\ttest_submodule_switch_func \"git $1\"\n+\ttest_submodule_switch_func \"$1 \\$arg\"\n }\n \n # Same as test_submodule_switch(), except that throwing away local changes in\n # the superproject is allowed.\n test_submodule_forced_switch () {\n-\tcommand=\"$1\"\n+\tcommand=\"git $1 \\$arg\"\n \tKNOWN_FAILURE_FORCED_SWITCH_TESTS=1\n-\ttest_submodule_switch_common \"git $command\"\n+\ttest_submodule_switch_common \"$command\"\n \n \t# When forced, a file in the superproject does not prevent creating a\n \t# submodule of the same name.\n@@ -607,7 +671,8 @@ test_submodule_forced_switch () {\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\targ=add_sub1 &&\n+\t\t\teval $command &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_dir_is_empty sub1\n \t\t)\ndiff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh\nindex 788605ccc0..d31e6487bd 100755\n--- a/t/t3426-rebase-submodule.sh\n+++ b/t/t3426-rebase-submodule.sh\n@@ -16,11 +16,10 @@ git_rebase () {\n \tgit revert HEAD &&\n \tgit status -su >actual &&\n \tls -1pR * >>actual &&\n-\ttest_cmp expect actual &&\n-\tgit rebase \"$1\"\n+\ttest_cmp expect actual\n }\n \n-test_submodule_switch_func \"git_rebase\"\n+test_submodule_switch_func \"rebase \\$arg\" \"git_rebase\"\n \n git_rebase_interactive () {\n \tgit status -su >expect &&\n@@ -34,11 +33,10 @@ git_rebase_interactive () {\n \tls -1pR * >>actual &&\n \ttest_cmp expect actual &&\n \tset_fake_editor &&\n-\techo \"fake-editor.sh\" >.git/info/exclude &&\n-\tgit rebase -i \"$1\"\n+\techo \"fake-editor.sh\" >.git/info/exclude\n }\n \n-test_submodule_switch_func \"git_rebase_interactive\"\n+test_submodule_switch_func \"rebase -i \\$arg\" \"git_rebase_interactive\"\n \n test_expect_success 'rebase interactive ignores modified submodules' '\n \ttest_when_finished \"rm -rf super sub\" &&\ndiff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh\nindex 95a7f64471..994cdc40f0 100755\n--- a/t/t3513-revert-submodule.sh\n+++ b/t/t3513-revert-submodule.sh\n@@ -11,11 +11,13 @@ test_description='revert can handle submodules'\n # first so we can restore the work tree test setup after doing the checkout\n # and revert.  We test here that the restored work tree content is identical\n # to that at the beginning. The last revert is then tested by the framework.\n-git_revert () {\n+git_revert_before () {\n \tgit status -su >expect &&\n \tls -1pR * >>expect &&\n-\ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n-\tgit checkout \"$1\" &&\n+\ttar cf \"$TRASH_DIRECTORY/tmp.tar\" *\n+}\n+\n+git_revert_after () {\n \tgit revert HEAD &&\n \trm -rf * &&\n \ttar xf \"$TRASH_DIRECTORY/tmp.tar\" &&\n@@ -26,6 +28,6 @@ git_revert () {\n }\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-test_submodule_switch_func \"git_revert\"\n+test_submodule_switch_func \"checkout \\$arg\" \"git_revert_before\" \"git_revert_after\"\n \n test_done\ndiff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh\nindex 6a7e801ca0..358a625124 100755\n--- a/t/t3906-stash-submodule.sh\n+++ b/t/t3906-stash-submodule.sh\n@@ -5,10 +5,12 @@ test_description='stash can handle submodules'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n-git_stash () {\n+git_stash_before () {\n \tgit status -su >expect &&\n-\tls -1pR * >>expect &&\n-\tgit read-tree -u -m \"$1\" &&\n+\tls -1pR * >>expect\n+}\n+\n+git_stash_after () {\n \tgit stash &&\n \tgit status -su >actual &&\n \tls -1pR * >>actual &&\n@@ -19,7 +21,7 @@ git_stash () {\n KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES=1\n KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1\n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-test_submodule_switch_func \"git_stash\"\n+test_submodule_switch_func \"read-tree -u -m \\$arg\" \"git_stash_before\" \"git_stash_after\"\n \n setup_basic () {\n \ttest_when_finished \"rm -rf main sub\" &&\ndiff --git a/t/t4137-apply-submodule.sh b/t/t4137-apply-submodule.sh\nindex b645e303a0..fe5ebeaa41 100755\n--- a/t/t4137-apply-submodule.sh\n+++ b/t/t4137-apply-submodule.sh\n@@ -5,16 +5,12 @@ test_description='git apply handling submodules'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n-apply_index () {\n-\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --index -\n+create_diff () {\n+\tgit diff --ignore-submodules=dirty \"..$1\" >diff\n }\n \n-test_submodule_switch_func \"apply_index\"\n+test_submodule_switch_func \"apply --index diff\" \"create_diff\"\n \n-apply_3way () {\n-\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --3way -\n-}\n-\n-test_submodule_switch_func \"apply_3way\"\n+test_submodule_switch_func \"apply --3way diff\" \"create_diff\"\n \n test_done\ndiff --git a/t/t4255-am-submodule.sh b/t/t4255-am-submodule.sh\nindex 1b179d5f45..5305280dfd 100755\n--- a/t/t4255-am-submodule.sh\n+++ b/t/t4255-am-submodule.sh\n@@ -5,18 +5,14 @@ test_description='git am handling submodules'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n-am () {\n-\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am -\n+create_patch () {\n+\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" >patch\n }\n \n-test_submodule_switch_func \"am\"\n-\n-am_3way () {\n-\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am --3way -\n-}\n+test_submodule_switch_func \"am patch\" \"create_patch\"\n \n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-test_submodule_switch_func \"am_3way\"\n+test_submodule_switch_func \"am --3way patch\" \"create_patch\"\n \n test_expect_success 'setup diff.submodule' '\n \ttest_commit one &&\ndiff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh\nindex f911bf631e..3b37853537 100755\n--- a/t/t5572-pull-submodule.sh\n+++ b/t/t5572-pull-submodule.sh\n@@ -11,36 +11,16 @@ reset_branch_to_HEAD () {\n \tgit branch --set-upstream-to=\"origin/$1\" \"$1\"\n }\n \n-git_pull () {\n-\treset_branch_to_HEAD \"$1\" &&\n-\tgit pull\n-}\n-\n # pulls without conflicts\n-test_submodule_switch_func \"git_pull\"\n+test_submodule_switch_func \"pull\" \"reset_branch_to_HEAD\"\n \n-git_pull_ff () {\n-\treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --ff\n-}\n+test_submodule_switch_func \"pull --ff\" \"reset_branch_to_HEAD\"\n \n-test_submodule_switch_func \"git_pull_ff\"\n-\n-git_pull_ff_only () {\n-\treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --ff-only\n-}\n-\n-test_submodule_switch_func \"git_pull_ff_only\"\n-\n-git_pull_noff () {\n-\treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --no-ff\n-}\n+test_submodule_switch_func \"pull --ff-only\" \"reset_branch_to_HEAD\"\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-test_submodule_switch_func \"git_pull_noff\"\n+test_submodule_switch_func \"pull --no-ff\" \"reset_branch_to_HEAD\"\n \n test_expect_success 'pull --recurse-submodule setup' '\n \ttest_create_repo child &&\ndiff --git a/t/t6041-bisect-submodule.sh b/t/t6041-bisect-submodule.sh\nindex 0e0cdf638d..b99e81d55d 100755\n--- a/t/t6041-bisect-submodule.sh\n+++ b/t/t6041-bisect-submodule.sh\n@@ -5,12 +5,14 @@ test_description='bisect can handle submodules'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n-git_bisect () {\n+git_bisect_before () {\n \tgit status -su >expect &&\n \tls -1pR * >>expect &&\n \ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n-\tGOOD=$(git rev-parse --verify HEAD) &&\n-\tgit checkout \"$1\" &&\n+\tGOOD=$(git rev-parse --verify HEAD)\n+}\n+\n+git_bisect_after () {\n \techo \"foo\" >bar &&\n \tgit add bar &&\n \tgit commit -m \"bisect bad\" &&\n@@ -27,6 +29,6 @@ git_bisect () {\n \tgit bisect bad $BAD\n }\n \n-test_submodule_switch_func \"git_bisect\"\n+test_submodule_switch_func \"checkout \\$arg\" \"git_bisect_before\" \"git_bisect_after\"\n \n test_done\n-- \n2.27.0.132.g321788e831\n\n"},{"id":"400072","messageId":"20200618181533.GA633383@coredump.intra.peff.net","threadId":"53350","inReplyTo":"35d07117e637edf5f9a148a50da6b2294ec0f87f.1592470068.git.liu.denton@gmail.com","subject":"Re: [PATCH v4 4/4] lib-submodule-update: use callbacks in test_submodule_switch_common()","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2020-06-18T18:15:33Z","receivedAt":"2020-06-18T18:15:35Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Jun 18, 2020 at 04:49:14AM -0400, Denton Liu wrote:\n\n> Instead of invoking $command as one monolithic helper function, break it\n> up into three parts:\n> \n> \t1. $command which is always a git command.\n> \t2. $before which is a callback function that runs just prior to\n> \t   $command.\n> \t3. $after which is a callback function that runs just after\n> \t   $command.\n\nThanks for reworking it in this way. I do think it's less confusing than\nthe original.\n\n> If the command requires a filename argument, specify it as `\\$arg` since\n> that variable will be set and the whole $command string will be eval'd.\n> Unfortunately, there is no way to get rid of the eval as some of the\n> commands that are passed (such as the `git pull` tests) require that no\n> additional arguments are passed so we must have some mechanism for the\n> caller to specify whether or not it wants the filename argument.\n\nWe didn't need that \"\\$arg\" thing before because we were passing whole\nfunctions (which then decided to pass the arg or not). Can we just keep\ndoing that (using functions)?\n\nThat puts the onus on callers who want to ignore the arg to wrap any\ncommands in a function, but saves ones who _do_ want to use the arg from\nhaving to do anything. So it's a tradeoff, but I think an extra function\nwrapper is less magical than the \"\\$arg\" eval (plus from skimming the\ndiff, I think most callers do use it).\n\nSo for example, this:\n\n> +test_submodule_switch_func \"apply --3way diff\" \"create_diff\"\n\nbecomes:\n\n  apply_diff () {\n          git apply --3way diff\n  }\n  test_submodule_switch_func apply_diff create_diff\n\nObviously that requires dropping the implicit \"git\" from $command (but\nI'd argue that makes things less magical, too).\n\n> @@ -326,7 +336,10 @@ test_submodule_switch_common () {\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\targ=add_sub1 &&\n> +\t\t\t$before \"$arg\" &&\n> +\t\t\teval $command &&\n> +\t\t\t$after \"$arg\" &&\n\nThis block gets repeated a lot, and I wondered if a helper function\ncould make it better. But:\n\n  1. We'd have to pass in a bunch of variables (or consider them as\n     magic globals).\n\n  2. Some callers want test_must_fail and other's don't.\n\nSo I think it would be something like:\n\n  do_command () {\n    $before \"$1\" &&\n    \"$2\" $command \"$1\" &&\n    $after \"$1\"\n  }\n\n  ...\n  do_command add_sub1 &&\n  ...\n\nThere's definitely still some magic there, but at least it's all\ncontained within the one script. I could go either way on it.\n\n-Peff\n"},{"id":"400352","messageId":"ba2f642e0f505730d5d740207128036448787c8c.1592907663.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1592907663.git.liu.denton@gmail.com","subject":"[PATCH v5 1/4] lib-submodule-update: add space after function name","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-06-23T10:28:02Z","receivedAt":"2020-06-23T10:28:21Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"In the shell scripts in this codebase, the usual style is to include a\nspace between the function name and the (). Add these missing spaces to\nconform to the usual style of the code.\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\n t/lib-submodule-update.sh | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 1dd17fc03e..122554acd6 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -183,7 +183,7 @@ test_git_directory_is_unchanged () {\n \t)\n }\n \n-test_git_directory_exists() {\n+test_git_directory_exists () {\n \ttest -e \".git/modules/$1\" &&\n \tif test -f sub1/.git\n \tthen\n@@ -309,7 +309,7 @@ test_submodule_content () {\n \n # Internal function; use test_submodule_switch() or\n # test_submodule_forced_switch() instead.\n-test_submodule_switch_common() {\n+test_submodule_switch_common () {\n \tcommand=\"$1\"\n \t######################### Appearing submodule #########################\n \t# Switching to a commit letting a submodule appear creates empty dir ...\n@@ -629,7 +629,7 @@ test_submodule_forced_switch () {\n \n # Internal function; use test_submodule_switch_recursing_with_args() or\n # test_submodule_forced_switch_recursing_with_args() instead.\n-test_submodule_recursing_with_args_common() {\n+test_submodule_recursing_with_args_common () {\n \tcommand=\"$1\"\n \n \t######################### Appearing submodule #########################\n-- \n2.27.0.132.g321788e831\n\n"},{"id":"400353","messageId":"cover.1592907663.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1592470068.git.liu.denton@gmail.com","subject":"[PATCH v5 0/4] t: replace incorrect test_must_fail usage (part 5)","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-06-23T10:28:01Z","receivedAt":"2020-06-23T10:28:23Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"Hi Peff,\n\nI've taken your suggestions and rerolled the last patch. Notably, I\ncombined $before and $command into a single function and then passed in\n`test_must_fail` as the second argument if it's expected to fail. I also\ndecided to use a helper function to reduce the duplication of the\ncalling logic but it's still a little verbose because I opted to make\nuse of argument passing over global variables where possible.\n\nOne thing that I'm leaning towards is completely removing $after. We can\ncombine $after with $command like I did in the first few iterations of\nthis series and just write it as:\n\n\tgit_test_thing () {\n\t\t# before...\n\t\t$2 git do-the-thing \"$1\" &&\n\t\tif test -n \"$2\"\n\t\tthen\n\t\t\treturn\n\t\tfi &&\n\t\t# after...\n\t}\n\nbut I'm also okay with leaving it as is.\n\nAlso, one problem that's present is that for tests that use\ntest_submodule_switch() and test_submodule_forced_switch(), $command\nwill be listed as git_test_func, which might make debugging more\ndifficult. I think I'd prefer the version we currently have queued for\nthis reason (and why I did the whole song and dance of $OVERWRITING_FAIL\nin the first place), but if you think that this is fine, I'm fine with\nthis approach as well.\n\nThanks,\n\nDenton\n---\n\nThe overall scope of these patches is to replace inappropriate uses of\ntest_must_fail. IOW, we should only allow test_must_fail to run on `git`\nand `test-tool`. Ultimately, we will conclude by making test_must_fail\nerror out on non-git commands. An advance view of the final series can\nbe found here[1].\n\nThis is the fifth part. It focuses on lib-submodule-update.sh and tests\nthat make use of it.\n\nThe first part can be found here[2]. The second part can be found\nhere[3]. The third part can be found here[4]. The fourth part can be\nfound here[5].\n\nChanges since v1.2:\n\n* In \"lib-submodule-update: pass OVERWRITING_FAIL\", use if-then return\n  to reduce the amount of code churn\n\nChanges since v2:\n\n* Replace the OVERWRITING_FAIL approach with callback functions as\n  suggested by Peff[6]\n\nChanges since v3:\n\n* Simply handling of empty $before and $after\n\n* Add more comments on the usage of the helper functions\n\nChanges since v4:\n\n* Combine $before and $command back together\n\n* Use a helper function to call the callbacks\n\n* Replace eval with proper argument passing\n\n[1]: (may be rebased at any time) https://github.com/Denton-L/git/tree/ready/cleanup-test-must-fail2\n[2]: https://lore.kernel.org/git/cover.1576583819.git.liu.denton@gmail.com/\n[3]: https://lore.kernel.org/git/cover.1577454401.git.liu.denton@gmail.com/\n[4]: https://lore.kernel.org/git/cover.1585209554.git.liu.denton@gmail.com/\n[5]: https://lore.kernel.org/git/cover.1587372771.git.liu.denton@gmail.com/\n[6]: https://lore.kernel.org/git/20200521182928.GA1308647@coredump.intra.peff.net/\n\nDenton Liu (4):\n  lib-submodule-update: add space after function name\n  lib-submodule-update: consolidate --recurse-submodules\n  lib-submodule-update: prepend \"git\" to $command\n  lib-submodule-update: use callbacks in test_submodule_switch_common()\n\n t/lib-submodule-update.sh        | 107 ++++++++++++++++++++++---------\n t/t1013-read-tree-submodule.sh   |   4 +-\n t/t2013-checkout-submodule.sh    |   4 +-\n t/t3426-rebase-submodule.sh      |   8 +--\n t/t3512-cherry-pick-submodule.sh |   2 +-\n t/t3513-revert-submodule.sh      |   7 +-\n t/t3906-stash-submodule.sh       |   7 +-\n t/t4137-apply-submodule.sh       |  10 +--\n t/t4255-am-submodule.sh          |  10 +--\n t/t5572-pull-submodule.sh        |  16 ++---\n t/t6041-bisect-submodule.sh      |   7 +-\n t/t7112-reset-submodule.sh       |   6 +-\n t/t7613-merge-submodule.sh       |   8 +--\n 13 files changed, 127 insertions(+), 69 deletions(-)\n\nRange-diff against v4:\n1:  ba2f642e0f = 1:  ba2f642e0f lib-submodule-update: add space after function name\n2:  16d0a3eb9a = 2:  16d0a3eb9a lib-submodule-update: consolidate --recurse-submodules\n3:  09446be5b9 = 3:  09446be5b9 lib-submodule-update: prepend \"git\" to $command\n4:  35d07117e6 ! 4:  250eee1dd3 lib-submodule-update: use callbacks in test_submodule_switch_common()\n    @@ Commit message\n         intended behaviour.\n     \n         Instead of invoking $command as one monolithic helper function, break it\n    -    up into three parts:\n    +    up into two parts:\n     \n    -            1. $command which is always a git command.\n    -            2. $before which is a callback function that runs just prior to\n    -               $command.\n    -            3. $after which is a callback function that runs just after\n    +            1. $command which is a function containing a git command.\n    +            2. $after which is a callback function that runs just after\n                    $command.\n     \n    -    If the command requires a filename argument, specify it as `\\$arg` since\n    -    that variable will be set and the whole $command string will be eval'd.\n    -    Unfortunately, there is no way to get rid of the eval as some of the\n    -    commands that are passed (such as the `git pull` tests) require that no\n    -    additional arguments are passed so we must have some mechanism for the\n    -    caller to specify whether or not it wants the filename argument.\n    +    If the command requires a filename argument, it will be passed in as\n    +    the first arg.\n     \n    -    The $before and $after callback functions will be passed the filename as\n    -    the first arg. These callback functions are optional and, if missing,\n    -    will be replaced with `true`. Also, in the case where we have a\n    -    `test_must_fail` test, $after will not be executed, similar to how the\n    -    helper functions currently behave when the git command fails and exits\n    -    the &&-chain.\n    +    The $after callback function will be passed the filename as the first\n    +    arg. This callback function is optional and, if missing, will be\n    +    replaced with `true`. Also, in the case where we have a `test_must_fail`\n    +    test, $after will not be executed, similar to how the helper functions\n    +    currently behave when the git command fails and exits the &&-chain.\n     \n    -    Finally, as an added bonus, `test_must_fail` will only run on $command\n    -    which is guaranteed to be a git command.\n    +    Finally, as an added bonus, `test_must_fail` will now only run on git\n    +    commands.\n     \n         An alternate design was considered where $OVERWRITING_FAIL is set from\n         test_submodule_switch_common() and exposed to the helper function. This\n    @@ Commit message\n         using a signalling magic environment variable might be too indirect.\n     \n      ## t/lib-submodule-update.sh ##\n    +@@ t/lib-submodule-update.sh: test_submodule_content () {\n    + \t)\n    + }\n    + \n    ++test_command () {\n    ++\tcommand=\"$1\" after=\"$2\" arg=\"$3\" &&\n    ++\t$command \"$arg\" &&\n    ++\t$after \"$arg\"\n    ++}\n    ++\n    ++test_command_fail () {\n    ++\tcommand=\"$1\" arg=\"$2\" &&\n    ++\t$command \"$arg\" test_must_fail\n    ++}\n    ++\n    + # Test that the following transitions are correctly handled:\n    + # - Updated submodule\n    + # - New submodule\n     @@ t/lib-submodule-update.sh: test_submodule_content () {\n      # Removing a submodule containing a .git directory must fail even when forced\n      # to protect the history!\n      #\n    -+# $1: The git command to be eval'd and tested. The submodule being operated on\n    -+# will be available as $arg.\n    ++# $1: The function which contains the git command. It will be passed two\n    ++# arguments. $1 will be the submodule being operated on. $2 will be\n    ++# \"test_must_fail\" if the git command is expected to fail, else the empty\n    ++# string.\n     +#\n    -+# $2: The function that will run before the git command. It will be passed the\n    -+# submodule being operated on as the only argument. This argument is optional.\n    -+#\n    -+# $3: The function that will run after $1. It will be passed the submodule\n    ++# $2: The function that will run after $1. It will be passed the submodule\n     +# being operated on as the only argument. This argument is optional. It will\n     +# not be run when testing a case where the git command is expected to fail.\n      \n    @@ t/lib-submodule-update.sh: test_submodule_content () {\n      # or test_submodule_forced_switch() instead.\n      test_submodule_switch_common () {\n     -\tcommand=\"$1\"\n    -+\tcommand=\"$1\" before=\"${2:-true}\" after=\"${3:-true}\"\n    ++\tcommand=\"$1\" after=\"${2:-true}\"\n     +\n      \t######################### Appearing submodule #########################\n      \t# Switching to a commit letting a submodule appear creates empty dir ...\n    @@ t/lib-submodule-update.sh: test_submodule_switch_common () {\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\targ=add_sub1 &&\n    -+\t\t\t$before \"$arg\" &&\n    -+\t\t\teval $command &&\n    -+\t\t\t$after \"$arg\" &&\n    ++\t\t\ttest_command \"$command\" \"$after\" add_sub1 &&\n      \t\t\ttest_superproject_content origin/add_sub1 &&\n      \t\t\ttest_dir_is_empty sub1 &&\n      \t\t\tgit submodule update --init --recursive &&\n    @@ t/lib-submodule-update.sh: test_submodule_switch_common () {\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\targ=add_sub1 &&\n    -+\t\t\t$before \"$arg\" &&\n    -+\t\t\teval $command &&\n    -+\t\t\t$after \"$arg\" &&\n    ++\t\t\ttest_command \"$command\" \"$after\" add_sub1 &&\n      \t\t\ttest_superproject_content origin/add_sub1 &&\n      \t\t\ttest_dir_is_empty sub1 &&\n      \t\t\tgit submodule update --init --recursive &&\n    @@ t/lib-submodule-update.sh: test_submodule_switch_common () {\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\targ=replace_file_with_sub1 &&\n    -+\t\t\t$before \"$arg\" &&\n    -+\t\t\teval $command &&\n    -+\t\t\t$after \"$arg\" &&\n    ++\t\t\ttest_command \"$command\" \"$after\" replace_file_with_sub1 &&\n      \t\t\ttest_superproject_content origin/replace_file_with_sub1 &&\n      \t\t\ttest_dir_is_empty sub1 &&\n      \t\t\tgit submodule update --init --recursive &&\n    @@ t/lib-submodule-update.sh: test_submodule_switch_common () {\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\targ=replace_directory_with_sub1  &&\n    -+\t\t\t$before \"$arg\" &&\n    -+\t\t\teval $command &&\n    -+\t\t\t$after \"$arg\" &&\n    ++\t\t\ttest_command \"$command\" \"$after\" replace_directory_with_sub1 &&\n      \t\t\ttest_superproject_content origin/replace_directory_with_sub1 &&\n      \t\t\ttest_dir_is_empty sub1 &&\n      \t\t\tgit submodule update --init --recursive &&\n    @@ t/lib-submodule-update.sh: test_submodule_switch_common () {\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\targ=remove_sub1 &&\n    -+\t\t\t$before \"$arg\" &&\n    -+\t\t\teval $command &&\n    -+\t\t\t$after \"$arg\" &&\n    ++\t\t\ttest_command \"$command\" \"$after\" remove_sub1 &&\n      \t\t\ttest_superproject_content origin/remove_sub1 &&\n      \t\t\ttest_submodule_content sub1 origin/add_sub1\n      \t\t)\n    @@ t/lib-submodule-update.sh: test_submodule_switch_common () {\n      \t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n      \t\t\treplace_gitfile_with_git_dir sub1 &&\n     -\t\t\t$command remove_sub1 &&\n    -+\t\t\targ=remove_sub1 &&\n    -+\t\t\t$before \"$arg\" &&\n    -+\t\t\teval $command &&\n    -+\t\t\t$after \"$arg\" &&\n    ++\t\t\ttest_command \"$command\" \"$after\" remove_sub1 &&\n      \t\t\ttest_superproject_content origin/remove_sub1 &&\n      \t\t\ttest_git_directory_is_unchanged sub1 &&\n      \t\t\ttest_submodule_content sub1 origin/add_sub1\n    @@ t/lib-submodule-update.sh: test_submodule_switch_common () {\n      \t\t\tcd submodule_update &&\n      \t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n     -\t\t\ttest_must_fail $command replace_sub1_with_directory &&\n    -+\t\t\targ=replace_sub1_with_directory &&\n    -+\t\t\t$before \"$arg\" &&\n    -+\t\t\teval test_must_fail $command &&\n    ++\t\t\ttest_command_fail \"$command\" replace_sub1_with_directory &&\n      \t\t\ttest_superproject_content origin/add_sub1 &&\n      \t\t\ttest_submodule_content sub1 origin/add_sub1\n      \t\t)\n    @@ t/lib-submodule-update.sh: test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_directory &&\n    -+\t\t\targ=replace_sub1_with_directory &&\n    -+\t\t\t$before \"$arg\" &&\n    -+\t\t\teval test_must_fail $command &&\n    ++\t\t\ttest_command_fail \"$command\" replace_sub1_with_directory &&\n      \t\t\ttest_superproject_content origin/add_sub1 &&\n      \t\t\ttest_git_directory_is_unchanged sub1 &&\n      \t\t\ttest_submodule_content sub1 origin/add_sub1\n    @@ t/lib-submodule-update.sh: test_submodule_switch_common () {\n      \t\t\tcd submodule_update &&\n      \t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n     -\t\t\ttest_must_fail $command replace_sub1_with_file &&\n    -+\t\t\targ=replace_sub1_with_file &&\n    -+\t\t\t$before \"$arg\" &&\n    -+\t\t\teval test_must_fail $command &&\n    ++\t\t\ttest_command_fail \"$command\" replace_sub1_with_file &&\n      \t\t\ttest_superproject_content origin/add_sub1 &&\n      \t\t\ttest_submodule_content sub1 origin/add_sub1\n      \t\t)\n    @@ t/lib-submodule-update.sh: test_submodule_switch_common () {\n      \t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n      \t\t\treplace_gitfile_with_git_dir sub1 &&\n     -\t\t\ttest_must_fail $command replace_sub1_with_file &&\n    -+\t\t\targ=replace_sub1_with_file &&\n    -+\t\t\t$before \"$arg\" &&\n    -+\t\t\teval test_must_fail $command &&\n    ++\t\t\ttest_command_fail \"$command\" replace_sub1_with_file &&\n      \t\t\ttest_superproject_content origin/add_sub1 &&\n      \t\t\ttest_git_directory_is_unchanged sub1 &&\n      \t\t\ttest_submodule_content sub1 origin/add_sub1\n    @@ t/lib-submodule-update.sh: test_submodule_switch_common () {\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\targ=modify_sub1 &&\n    -+\t\t\t$before \"$arg\" &&\n    -+\t\t\teval $command &&\n    -+\t\t\t$after \"$arg\" &&\n    ++\t\t\ttest_command \"$command\" \"$after\" modify_sub1 &&\n      \t\t\ttest_superproject_content origin/modify_sub1 &&\n      \t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n      \t\t\tgit submodule update &&\n    @@ t/lib-submodule-update.sh: test_submodule_switch_common () {\n      \t\t\tcd submodule_update &&\n      \t\t\tgit branch -t invalid_sub1 origin/invalid_sub1 &&\n     -\t\t\t$command invalid_sub1 &&\n    -+\t\t\targ=invalid_sub1 &&\n    -+\t\t\t$before \"$arg\" &&\n    -+\t\t\teval $command &&\n    -+\t\t\t$after \"$arg\" &&\n    ++\t\t\ttest_command \"$command\" \"$after\" invalid_sub1 &&\n      \t\t\ttest_superproject_content origin/invalid_sub1 &&\n      \t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n      \t\t\ttest_must_fail git submodule update &&\n    @@ t/lib-submodule-update.sh: test_submodule_switch_common () {\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\targ=valid_sub1 &&\n    -+\t\t\t$before \"$arg\" &&\n    -+\t\t\teval $command &&\n    -+\t\t\t$after \"$arg\" &&\n    ++\t\t\ttest_command \"$command\" \"$after\" valid_sub1 &&\n      \t\t\ttest_superproject_content origin/valid_sub1 &&\n      \t\t\ttest_dir_is_empty sub1 &&\n      \t\t\tgit submodule update --init --recursive &&\n    @@ t/lib-submodule-update.sh: test_submodule_switch_common () {\n      # below to 1.\n      #\n     -# Use as follows:\n    -+# $1: The git command to be eval'd and tested. The submodule being operated on\n    -+# will be available as $arg. Do not include the leading \"git\".\n    - #\n    --# my_func () {\n    -+# $2: The function that will run before the git command. It will be passed the\n    -+# submodule being operated on as the only argument. This argument is optional.\n    ++# $1: The function which contains the git command. It will be passed two\n    ++# arguments. $1 will be the submodule being operated on. $2 will be\n    ++# \"test_must_fail\" if the git command is expected to fail, else the empty\n    ++# string.\n     +#\n    -+# $3: The function that will run after $1. It will be passed the submodule\n    ++# $2: The function that will run after $1. It will be passed the submodule\n     +# being operated on as the only argument. This argument is optional. It will\n     +# not be run when testing a case where the git command is expected to fail.\n     +#\n     +# The following example uses `git some-command` as an example command to be\n     +# tested. It updates the worktree and index to match a target, but not any\n     +# submodule directories.\n    -+#\n    -+# my_func_before () {\n    + #\n    + # my_func () {\n      #   target=$1\n     -#   # Do something here that updates the worktree and index to match target,\n     -#   # but not any submodule directories.\n    -+#   # Prepare for git some-command to be run\n    ++#   $2 git some-command $target\n      # }\n     -# test_submodule_switch_func \"my_func\"\n     +# my_func_after () {\n     +#   target=$1\n     +#   # Check the state after git some-command is run\n     +# }\n    -+# test_submodule_switch_func \"some-command \\$arg\" \"my_func_before\" \"my_func_after\"\n    ++# test_submodule_switch_func \"my_func\" \"my_func_after\"\n      test_submodule_switch_func () {\n    --\tcommand=\"$1\"\n    + \tcommand=\"$1\"\n     -\ttest_submodule_switch_common \"$command\"\n    -+\tcommand=\"git $1\"\n    -+\tbefore=\"$2\"\n    -+\tafter=\"$3\"\n    -+\ttest_submodule_switch_common \"$command\" \"$before\" \"$after\"\n    ++\tafter=\"$2\"\n    ++\ttest_submodule_switch_common \"$command\" \"$after\"\n      \n      \t# An empty directory does not prevent the creation of a submodule of\n      \t# the same name, but a file does.\n    @@ t/lib-submodule-update.sh: test_submodule_switch_func () {\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\targ=add_sub1 &&\n    -+\t\t\t$before \"$arg\" &&\n    -+\t\t\teval test_must_fail $command &&\n    ++\t\t\ttest_command_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/lib-submodule-update.sh: test_submodule_switch_func () {\n    + \t'\n      }\n      \n    ++git_test_func () {\n    ++\t$2 git $gitcmd \"$1\"\n    ++}\n    ++\n      test_submodule_switch () {\n     -\ttest_submodule_switch_func \"git $1\"\n    -+\ttest_submodule_switch_func \"$1 \\$arg\"\n    ++\tgitcmd=\"$1\"\n    ++\ttest_submodule_switch_func \"git_test_func\"\n      }\n      \n      # Same as test_submodule_switch(), except that throwing away local changes in\n      # the superproject is allowed.\n      test_submodule_forced_switch () {\n     -\tcommand=\"$1\"\n    -+\tcommand=\"git $1 \\$arg\"\n    ++\tgitcmd=\"$1\"\n    ++\tcommand=\"git_test_func\"\n      \tKNOWN_FAILURE_FORCED_SWITCH_TESTS=1\n     -\ttest_submodule_switch_common \"git $command\"\n     +\ttest_submodule_switch_common \"$command\"\n    @@ t/lib-submodule-update.sh: test_submodule_forced_switch () {\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\targ=add_sub1 &&\n    -+\t\t\teval $command &&\n    ++\t\t\ttest_command \"$command\" true add_sub1 &&\n      \t\t\ttest_superproject_content origin/add_sub1 &&\n      \t\t\ttest_dir_is_empty sub1\n      \t\t)\n     \n      ## t/t3426-rebase-submodule.sh ##\n     @@ t/t3426-rebase-submodule.sh: git_rebase () {\n    - \tgit revert HEAD &&\n      \tgit status -su >actual &&\n      \tls -1pR * >>actual &&\n    --\ttest_cmp expect actual &&\n    + \ttest_cmp expect actual &&\n     -\tgit rebase \"$1\"\n    -+\ttest_cmp expect actual\n    ++\t$2 git rebase \"$1\"\n      }\n      \n    --test_submodule_switch_func \"git_rebase\"\n    -+test_submodule_switch_func \"rebase \\$arg\" \"git_rebase\"\n    - \n    - git_rebase_interactive () {\n    - \tgit status -su >expect &&\n    + test_submodule_switch_func \"git_rebase\"\n     @@ t/t3426-rebase-submodule.sh: git_rebase_interactive () {\n    - \tls -1pR * >>actual &&\n      \ttest_cmp expect actual &&\n      \tset_fake_editor &&\n    --\techo \"fake-editor.sh\" >.git/info/exclude &&\n    + \techo \"fake-editor.sh\" >.git/info/exclude &&\n     -\tgit rebase -i \"$1\"\n    -+\techo \"fake-editor.sh\" >.git/info/exclude\n    ++\t$2 git rebase -i \"$1\"\n      }\n      \n    --test_submodule_switch_func \"git_rebase_interactive\"\n    -+test_submodule_switch_func \"rebase -i \\$arg\" \"git_rebase_interactive\"\n    - \n    - test_expect_success 'rebase interactive ignores modified submodules' '\n    - \ttest_when_finished \"rm -rf super sub\" &&\n    + test_submodule_switch_func \"git_rebase_interactive\"\n     \n      ## t/t3513-revert-submodule.sh ##\n    -@@ t/t3513-revert-submodule.sh: test_description='revert can handle submodules'\n    - # first so we can restore the work tree test setup after doing the checkout\n    - # and revert.  We test here that the restored work tree content is identical\n    - # to that at the beginning. The last revert is then tested by the framework.\n    --git_revert () {\n    -+git_revert_before () {\n    +@@ t/t3513-revert-submodule.sh: git_revert () {\n      \tgit status -su >expect &&\n      \tls -1pR * >>expect &&\n    --\ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n    + \ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n     -\tgit checkout \"$1\" &&\n    -+\ttar cf \"$TRASH_DIRECTORY/tmp.tar\" *\n    ++\t$2 git checkout \"$1\"\n     +}\n     +\n     +git_revert_after () {\n    @@ t/t3513-revert-submodule.sh: git_revert () {\n      \n      KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n     -test_submodule_switch_func \"git_revert\"\n    -+test_submodule_switch_func \"checkout \\$arg\" \"git_revert_before\" \"git_revert_after\"\n    ++test_submodule_switch_func \"git_revert\" \"git_revert_after\"\n      \n      test_done\n     \n      ## t/t3906-stash-submodule.sh ##\n     @@ t/t3906-stash-submodule.sh: test_description='stash can handle submodules'\n    - . ./test-lib.sh\n    - . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n    - \n    --git_stash () {\n    -+git_stash_before () {\n    + git_stash () {\n      \tgit status -su >expect &&\n    --\tls -1pR * >>expect &&\n    + \tls -1pR * >>expect &&\n     -\tgit read-tree -u -m \"$1\" &&\n    -+\tls -1pR * >>expect\n    ++\t$2 git read-tree -u -m \"$1\"\n     +}\n     +\n     +git_stash_after () {\n    @@ t/t3906-stash-submodule.sh: git_stash () {\n      KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1\n      KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n     -test_submodule_switch_func \"git_stash\"\n    -+test_submodule_switch_func \"read-tree -u -m \\$arg\" \"git_stash_before\" \"git_stash_after\"\n    ++test_submodule_switch_func \"git_stash\" \"git_stash_after\"\n      \n      setup_basic () {\n      \ttest_when_finished \"rm -rf main sub\" &&\n     \n      ## t/t4137-apply-submodule.sh ##\n     @@ t/t4137-apply-submodule.sh: test_description='git apply handling submodules'\n    - . ./test-lib.sh\n      . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n      \n    --apply_index () {\n    + apply_index () {\n     -\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --index -\n    -+create_diff () {\n    -+\tgit diff --ignore-submodules=dirty \"..$1\" >diff\n    ++\tgit diff --ignore-submodules=dirty \"..$1\" >diff &&\n    ++\t$2 git apply --index diff\n      }\n      \n    --test_submodule_switch_func \"apply_index\"\n    -+test_submodule_switch_func \"apply --index diff\" \"create_diff\"\n    + test_submodule_switch_func \"apply_index\"\n      \n    --apply_3way () {\n    + apply_3way () {\n     -\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --3way -\n    --}\n    --\n    --test_submodule_switch_func \"apply_3way\"\n    -+test_submodule_switch_func \"apply --3way diff\" \"create_diff\"\n    ++\tgit diff --ignore-submodules=dirty \"..$1\" >diff\n    ++\t$2 git apply --3way diff\n    + }\n      \n    - test_done\n    + test_submodule_switch_func \"apply_3way\"\n     \n      ## t/t4255-am-submodule.sh ##\n     @@ t/t4255-am-submodule.sh: test_description='git am handling submodules'\n    - . ./test-lib.sh\n      . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n      \n    --am () {\n    + am () {\n     -\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am -\n    -+create_patch () {\n    -+\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" >patch\n    ++\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" >patch &&\n    ++\t$2 git am patch\n      }\n      \n    --test_submodule_switch_func \"am\"\n    --\n    --am_3way () {\n    + test_submodule_switch_func \"am\"\n    + \n    + am_3way () {\n     -\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am --3way -\n    --}\n    -+test_submodule_switch_func \"am patch\" \"create_patch\"\n    ++\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" >patch &&\n    ++\t$2 git am --3way patch\n    + }\n      \n      KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n    --test_submodule_switch_func \"am_3way\"\n    -+test_submodule_switch_func \"am --3way patch\" \"create_patch\"\n    - \n    - test_expect_success 'setup diff.submodule' '\n    - \ttest_commit one &&\n     \n      ## t/t5572-pull-submodule.sh ##\n     @@ t/t5572-pull-submodule.sh: reset_branch_to_HEAD () {\n    - \tgit branch --set-upstream-to=\"origin/$1\" \"$1\"\n    + \n    + git_pull () {\n    + \treset_branch_to_HEAD \"$1\" &&\n    +-\tgit pull\n    ++\t$2 git pull\n      }\n      \n    --git_pull () {\n    --\treset_branch_to_HEAD \"$1\" &&\n    --\tgit pull\n    --}\n    --\n      # pulls without conflicts\n    --test_submodule_switch_func \"git_pull\"\n    -+test_submodule_switch_func \"pull\" \"reset_branch_to_HEAD\"\n    +@@ t/t5572-pull-submodule.sh: test_submodule_switch_func \"git_pull\"\n      \n    --git_pull_ff () {\n    --\treset_branch_to_HEAD \"$1\" &&\n    + git_pull_ff () {\n    + \treset_branch_to_HEAD \"$1\" &&\n     -\tgit pull --ff\n    --}\n    -+test_submodule_switch_func \"pull --ff\" \"reset_branch_to_HEAD\"\n    ++\t$2 git pull --ff\n    + }\n      \n    --test_submodule_switch_func \"git_pull_ff\"\n    --\n    --git_pull_ff_only () {\n    --\treset_branch_to_HEAD \"$1\" &&\n    + test_submodule_switch_func \"git_pull_ff\"\n    + \n    + git_pull_ff_only () {\n    + \treset_branch_to_HEAD \"$1\" &&\n     -\tgit pull --ff-only\n    --}\n    --\n    --test_submodule_switch_func \"git_pull_ff_only\"\n    --\n    --git_pull_noff () {\n    --\treset_branch_to_HEAD \"$1\" &&\n    ++\t$2 git pull --ff-only\n    + }\n    + \n    + test_submodule_switch_func \"git_pull_ff_only\"\n    + \n    + git_pull_noff () {\n    + \treset_branch_to_HEAD \"$1\" &&\n     -\tgit pull --no-ff\n    --}\n    -+test_submodule_switch_func \"pull --ff-only\" \"reset_branch_to_HEAD\"\n    ++\t$2 git pull --no-ff\n    + }\n      \n      KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n    - KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n    --test_submodule_switch_func \"git_pull_noff\"\n    -+test_submodule_switch_func \"pull --no-ff\" \"reset_branch_to_HEAD\"\n    - \n    - test_expect_success 'pull --recurse-submodule setup' '\n    - \ttest_create_repo child &&\n     \n      ## t/t6041-bisect-submodule.sh ##\n    -@@ t/t6041-bisect-submodule.sh: test_description='bisect can handle submodules'\n    - . ./test-lib.sh\n    - . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n    - \n    --git_bisect () {\n    -+git_bisect_before () {\n    - \tgit status -su >expect &&\n    +@@ t/t6041-bisect-submodule.sh: git_bisect () {\n      \tls -1pR * >>expect &&\n      \ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n    --\tGOOD=$(git rev-parse --verify HEAD) &&\n    + \tGOOD=$(git rev-parse --verify HEAD) &&\n     -\tgit checkout \"$1\" &&\n    -+\tGOOD=$(git rev-parse --verify HEAD)\n    ++\t$2 git checkout \"$1\"\n     +}\n     +\n     +git_bisect_after () {\n    @@ t/t6041-bisect-submodule.sh: git_bisect () {\n      }\n      \n     -test_submodule_switch_func \"git_bisect\"\n    -+test_submodule_switch_func \"checkout \\$arg\" \"git_bisect_before\" \"git_bisect_after\"\n    ++test_submodule_switch_func \"git_bisect\" \"git_bisect_after\"\n      \n      test_done\n-- \n2.27.0.132.g321788e831\n\n"},{"id":"400354","messageId":"16d0a3eb9ac8dcda701433a9e67cde5103949432.1592907663.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1592907663.git.liu.denton@gmail.com","subject":"[PATCH v5 2/4] lib-submodule-update: consolidate --recurse-submodules","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-06-23T10:28:03Z","receivedAt":"2020-06-23T10:28:25Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"Both test_submodule_switch_recursing_with_args() and\ntest_submodule_forced_switch_recursing_with_args() call the internal\nfunction test_submodule_recursing_with_args_common() with the final\nargument of `--recurse-submodules`. Consolidate this duplication by\nappending the argument in test_submodule_recursing_with_args_common().\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\n t/lib-submodule-update.sh | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 122554acd6..bb36287803 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -630,7 +630,7 @@ test_submodule_forced_switch () {\n # Internal function; use test_submodule_switch_recursing_with_args() or\n # test_submodule_forced_switch_recursing_with_args() instead.\n test_submodule_recursing_with_args_common () {\n-\tcommand=\"$1\"\n+\tcommand=\"$1 --recurse-submodules\"\n \n \t######################### Appearing submodule #########################\n \t# Switching to a commit letting a submodule appear checks it out ...\n@@ -809,7 +809,7 @@ test_submodule_recursing_with_args_common () {\n # test_submodule_switch_recursing_with_args \"$GIT_COMMAND\"\n test_submodule_switch_recursing_with_args () {\n \tcmd_args=\"$1\"\n-\tcommand=\"git $cmd_args --recurse-submodules\"\n+\tcommand=\"git $cmd_args\"\n \ttest_submodule_recursing_with_args_common \"$command\"\n \n \tRESULTDS=success\n@@ -927,7 +927,7 @@ test_submodule_switch_recursing_with_args () {\n # away local changes in the superproject is allowed.\n test_submodule_forced_switch_recursing_with_args () {\n \tcmd_args=\"$1\"\n-\tcommand=\"git $cmd_args --recurse-submodules\"\n+\tcommand=\"git $cmd_args\"\n \ttest_submodule_recursing_with_args_common \"$command\"\n \n \tRESULT=success\n-- \n2.27.0.132.g321788e831\n\n"},{"id":"400355","messageId":"250eee1dd35485bec33b80a6c97ecc3c3f276280.1592907663.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1592907663.git.liu.denton@gmail.com","subject":"[PATCH v5 4/4] lib-submodule-update: use callbacks in test_submodule_switch_common()","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-06-23T10:28:05Z","receivedAt":"2020-06-23T10:28:29Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"When we run a test helper function in test_submodule_switch_common(), we\nsometimes specify a whole helper function as the $command. When we do\nthis, in some test cases, we just mark the whole function with\n`test_must_fail`. However, it's possible that the helper function might\nfail earlier or later than expected due to an introduced bug. If this\nhappens, then the test case will still report as passing but it should\nreally be marked as failing since it didn't actually display the\nintended behaviour.\n\nInstead of invoking $command as one monolithic helper function, break it\nup into two parts:\n\n\t1. $command which is a function containing a git command.\n\t2. $after which is a callback function that runs just after\n\t   $command.\n\nIf the command requires a filename argument, it will be passed in as\nthe first arg.\n\nThe $after callback function will be passed the filename as the first\narg. This callback function is optional and, if missing, will be\nreplaced with `true`. Also, in the case where we have a `test_must_fail`\ntest, $after will not be executed, similar to how the helper functions\ncurrently behave when the git command fails and exits the &&-chain.\n\nFinally, as an added bonus, `test_must_fail` will now only run on git\ncommands.\n\nAn alternate design was considered where $OVERWRITING_FAIL is set from\ntest_submodule_switch_common() and exposed to the helper function. This\napproach was considered too difficult to understand due to the fact that\nusing a signalling magic environment variable might be too indirect.\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\n t/lib-submodule-update.sh   | 89 +++++++++++++++++++++++++++----------\n t/t3426-rebase-submodule.sh |  4 +-\n t/t3513-revert-submodule.sh |  7 ++-\n t/t3906-stash-submodule.sh  |  7 ++-\n t/t4137-apply-submodule.sh  |  6 ++-\n t/t4255-am-submodule.sh     |  6 ++-\n t/t5572-pull-submodule.sh   |  8 ++--\n t/t6041-bisect-submodule.sh |  7 ++-\n 8 files changed, 94 insertions(+), 40 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 7c3ba1be00..104090b489 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -290,6 +290,17 @@ test_submodule_content () {\n \t)\n }\n \n+test_command () {\n+\tcommand=\"$1\" after=\"$2\" arg=\"$3\" &&\n+\t$command \"$arg\" &&\n+\t$after \"$arg\"\n+}\n+\n+test_command_fail () {\n+\tcommand=\"$1\" arg=\"$2\" &&\n+\t$command \"$arg\" test_must_fail\n+}\n+\n # Test that the following transitions are correctly handled:\n # - Updated submodule\n # - New submodule\n@@ -306,11 +317,20 @@ test_submodule_content () {\n # Removing a submodule containing a .git directory must fail even when forced\n # to protect the history!\n #\n+# $1: The function which contains the git command. It will be passed two\n+# arguments. $1 will be the submodule being operated on. $2 will be\n+# \"test_must_fail\" if the git command is expected to fail, else the empty\n+# string.\n+#\n+# $2: The function that will run after $1. It will be passed the submodule\n+# being operated on as the only argument. This argument is optional. It will\n+# not be run when testing a case where the git command is expected to fail.\n \n # Internal function; use test_submodule_switch_func(), test_submodule_switch(),\n # or test_submodule_forced_switch() instead.\n test_submodule_switch_common () {\n-\tcommand=\"$1\"\n+\tcommand=\"$1\" after=\"${2:-true}\"\n+\n \t######################### Appearing submodule #########################\n \t# Switching to a commit letting a submodule appear creates empty dir ...\n \tif test \"$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES\" = 1\n@@ -326,7 +346,7 @@ test_submodule_switch_common () {\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_command \"$command\" \"$after\" add_sub1 &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n \t\t\tgit submodule update --init --recursive &&\n@@ -341,7 +361,7 @@ test_submodule_switch_common () {\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_command \"$command\" \"$after\" add_sub1 &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n \t\t\tgit submodule update --init --recursive &&\n@@ -356,7 +376,7 @@ test_submodule_switch_common () {\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_command \"$command\" \"$after\" replace_file_with_sub1 &&\n \t\t\ttest_superproject_content origin/replace_file_with_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n \t\t\tgit submodule update --init --recursive &&\n@@ -380,7 +400,7 @@ test_submodule_switch_common () {\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_command \"$command\" \"$after\" replace_directory_with_sub1 &&\n \t\t\ttest_superproject_content origin/replace_directory_with_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n \t\t\tgit submodule update --init --recursive &&\n@@ -402,7 +422,7 @@ test_submodule_switch_common () {\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_command \"$command\" \"$after\" remove_sub1 &&\n \t\t\ttest_superproject_content origin/remove_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -415,7 +435,7 @@ test_submodule_switch_common () {\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\t$command remove_sub1 &&\n+\t\t\ttest_command \"$command\" \"$after\" remove_sub1 &&\n \t\t\ttest_superproject_content origin/remove_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -443,7 +463,7 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\ttest_command_fail \"$command\" replace_sub1_with_directory &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -456,7 +476,7 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\ttest_command_fail \"$command\" replace_sub1_with_directory &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -470,7 +490,7 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\ttest_command_fail \"$command\" replace_sub1_with_file &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -484,7 +504,7 @@ test_submodule_switch_common () {\n \t\t\tcd submodule_update &&\n \t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n \t\t\treplace_gitfile_with_git_dir sub1 &&\n-\t\t\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\ttest_command_fail \"$command\" replace_sub1_with_file &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -508,7 +528,7 @@ test_submodule_switch_common () {\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_command \"$command\" \"$after\" modify_sub1 &&\n \t\t\ttest_superproject_content origin/modify_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n \t\t\tgit submodule update &&\n@@ -523,7 +543,7 @@ test_submodule_switch_common () {\n \t\t(\n \t\t\tcd submodule_update &&\n \t\t\tgit branch -t invalid_sub1 origin/invalid_sub1 &&\n-\t\t\t$command invalid_sub1 &&\n+\t\t\ttest_command \"$command\" \"$after\" invalid_sub1 &&\n \t\t\ttest_superproject_content origin/invalid_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n \t\t\ttest_must_fail git submodule update &&\n@@ -538,7 +558,7 @@ test_submodule_switch_common () {\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_command \"$command\" \"$after\" valid_sub1 &&\n \t\t\ttest_superproject_content origin/valid_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n \t\t\tgit submodule update --init --recursive &&\n@@ -559,17 +579,32 @@ test_submodule_switch_common () {\n # conditions, set the appropriate KNOWN_FAILURE_* variable used in the tests\n # below to 1.\n #\n-# Use as follows:\n+# $1: The function which contains the git command. It will be passed two\n+# arguments. $1 will be the submodule being operated on. $2 will be\n+# \"test_must_fail\" if the git command is expected to fail, else the empty\n+# string.\n+#\n+# $2: The function that will run after $1. It will be passed the submodule\n+# being operated on as the only argument. This argument is optional. It will\n+# not be run when testing a case where the git command is expected to fail.\n+#\n+# The following example uses `git some-command` as an example command to be\n+# tested. It updates the worktree and index to match a target, but not any\n+# submodule directories.\n #\n # my_func () {\n #   target=$1\n-#   # Do something here that updates the worktree and index to match target,\n-#   # but not any submodule directories.\n+#   $2 git some-command $target\n # }\n-# test_submodule_switch_func \"my_func\"\n+# my_func_after () {\n+#   target=$1\n+#   # Check the state after git some-command is run\n+# }\n+# test_submodule_switch_func \"my_func\" \"my_func_after\"\n test_submodule_switch_func () {\n \tcommand=\"$1\"\n-\ttest_submodule_switch_common \"$command\"\n+\tafter=\"$2\"\n+\ttest_submodule_switch_common \"$command\" \"$after\"\n \n \t# An empty directory does not prevent the creation of a submodule of\n \t# the same name, but a file does.\n@@ -580,23 +615,29 @@ test_submodule_switch_func () {\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_command_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 \n+git_test_func () {\n+\t$2 git $gitcmd \"$1\"\n+}\n+\n test_submodule_switch () {\n-\ttest_submodule_switch_func \"git $1\"\n+\tgitcmd=\"$1\"\n+\ttest_submodule_switch_func \"git_test_func\"\n }\n \n # Same as test_submodule_switch(), except that throwing away local changes in\n # the superproject is allowed.\n test_submodule_forced_switch () {\n-\tcommand=\"$1\"\n+\tgitcmd=\"$1\"\n+\tcommand=\"git_test_func\"\n \tKNOWN_FAILURE_FORCED_SWITCH_TESTS=1\n-\ttest_submodule_switch_common \"git $command\"\n+\ttest_submodule_switch_common \"$command\"\n \n \t# When forced, a file in the superproject does not prevent creating a\n \t# submodule of the same name.\n@@ -607,7 +648,7 @@ test_submodule_forced_switch () {\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_command \"$command\" true add_sub1 &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_dir_is_empty sub1\n \t\t)\ndiff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh\nindex 788605ccc0..dd5daa53d3 100755\n--- a/t/t3426-rebase-submodule.sh\n+++ b/t/t3426-rebase-submodule.sh\n@@ -17,7 +17,7 @@ git_rebase () {\n \tgit status -su >actual &&\n \tls -1pR * >>actual &&\n \ttest_cmp expect actual &&\n-\tgit rebase \"$1\"\n+\t$2 git rebase \"$1\"\n }\n \n test_submodule_switch_func \"git_rebase\"\n@@ -35,7 +35,7 @@ git_rebase_interactive () {\n \ttest_cmp expect actual &&\n \tset_fake_editor &&\n \techo \"fake-editor.sh\" >.git/info/exclude &&\n-\tgit rebase -i \"$1\"\n+\t$2 git rebase -i \"$1\"\n }\n \n test_submodule_switch_func \"git_rebase_interactive\"\ndiff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh\nindex 95a7f64471..7ac06731bd 100755\n--- a/t/t3513-revert-submodule.sh\n+++ b/t/t3513-revert-submodule.sh\n@@ -15,7 +15,10 @@ git_revert () {\n \tgit status -su >expect &&\n \tls -1pR * >>expect &&\n \ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n-\tgit checkout \"$1\" &&\n+\t$2 git checkout \"$1\"\n+}\n+\n+git_revert_after () {\n \tgit revert HEAD &&\n \trm -rf * &&\n \ttar xf \"$TRASH_DIRECTORY/tmp.tar\" &&\n@@ -26,6 +29,6 @@ git_revert () {\n }\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-test_submodule_switch_func \"git_revert\"\n+test_submodule_switch_func \"git_revert\" \"git_revert_after\"\n \n test_done\ndiff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh\nindex 6a7e801ca0..30bdc113cd 100755\n--- a/t/t3906-stash-submodule.sh\n+++ b/t/t3906-stash-submodule.sh\n@@ -8,7 +8,10 @@ test_description='stash can handle submodules'\n git_stash () {\n \tgit status -su >expect &&\n \tls -1pR * >>expect &&\n-\tgit read-tree -u -m \"$1\" &&\n+\t$2 git read-tree -u -m \"$1\"\n+}\n+\n+git_stash_after () {\n \tgit stash &&\n \tgit status -su >actual &&\n \tls -1pR * >>actual &&\n@@ -19,7 +22,7 @@ git_stash () {\n KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES=1\n KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1\n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-test_submodule_switch_func \"git_stash\"\n+test_submodule_switch_func \"git_stash\" \"git_stash_after\"\n \n setup_basic () {\n \ttest_when_finished \"rm -rf main sub\" &&\ndiff --git a/t/t4137-apply-submodule.sh b/t/t4137-apply-submodule.sh\nindex b645e303a0..5477d48ffd 100755\n--- a/t/t4137-apply-submodule.sh\n+++ b/t/t4137-apply-submodule.sh\n@@ -6,13 +6,15 @@ test_description='git apply handling submodules'\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n apply_index () {\n-\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --index -\n+\tgit diff --ignore-submodules=dirty \"..$1\" >diff &&\n+\t$2 git apply --index diff\n }\n \n test_submodule_switch_func \"apply_index\"\n \n apply_3way () {\n-\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --3way -\n+\tgit diff --ignore-submodules=dirty \"..$1\" >diff\n+\t$2 git apply --3way diff\n }\n \n test_submodule_switch_func \"apply_3way\"\ndiff --git a/t/t4255-am-submodule.sh b/t/t4255-am-submodule.sh\nindex 1b179d5f45..8403124ac0 100755\n--- a/t/t4255-am-submodule.sh\n+++ b/t/t4255-am-submodule.sh\n@@ -6,13 +6,15 @@ test_description='git am handling submodules'\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n am () {\n-\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am -\n+\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" >patch &&\n+\t$2 git am patch\n }\n \n test_submodule_switch_func \"am\"\n \n am_3way () {\n-\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am --3way -\n+\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" >patch &&\n+\t$2 git am --3way patch\n }\n \n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\ndiff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh\nindex f911bf631e..cfa40b9251 100755\n--- a/t/t5572-pull-submodule.sh\n+++ b/t/t5572-pull-submodule.sh\n@@ -13,7 +13,7 @@ reset_branch_to_HEAD () {\n \n git_pull () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull\n+\t$2 git pull\n }\n \n # pulls without conflicts\n@@ -21,21 +21,21 @@ test_submodule_switch_func \"git_pull\"\n \n git_pull_ff () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --ff\n+\t$2 git pull --ff\n }\n \n test_submodule_switch_func \"git_pull_ff\"\n \n git_pull_ff_only () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --ff-only\n+\t$2 git pull --ff-only\n }\n \n test_submodule_switch_func \"git_pull_ff_only\"\n \n git_pull_noff () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --no-ff\n+\t$2 git pull --no-ff\n }\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\ndiff --git a/t/t6041-bisect-submodule.sh b/t/t6041-bisect-submodule.sh\nindex 0e0cdf638d..e213876fcd 100755\n--- a/t/t6041-bisect-submodule.sh\n+++ b/t/t6041-bisect-submodule.sh\n@@ -10,7 +10,10 @@ git_bisect () {\n \tls -1pR * >>expect &&\n \ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n \tGOOD=$(git rev-parse --verify HEAD) &&\n-\tgit checkout \"$1\" &&\n+\t$2 git checkout \"$1\"\n+}\n+\n+git_bisect_after () {\n \techo \"foo\" >bar &&\n \tgit add bar &&\n \tgit commit -m \"bisect bad\" &&\n@@ -27,6 +30,6 @@ git_bisect () {\n \tgit bisect bad $BAD\n }\n \n-test_submodule_switch_func \"git_bisect\"\n+test_submodule_switch_func \"git_bisect\" \"git_bisect_after\"\n \n test_done\n-- \n2.27.0.132.g321788e831\n\n"},{"id":"400356","messageId":"09446be5b9e9d6291dae3531a93b588e0b7a1c3f.1592907663.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1592907663.git.liu.denton@gmail.com","subject":"[PATCH v5 3/4] lib-submodule-update: prepend \"git\" to $command","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-06-23T10:28:04Z","receivedAt":"2020-06-23T10:28:30Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"Since all invocations of test_submodule_forced_switch() are git\ncommands, automatically prepend \"git\" before invoking\ntest_submodule_switch_common().\n\nSimilarly, many invocations of test_submodule_switch() are also git\ncommands so automatically prepend \"git\" before invoking\ntest_submodule_switch_common() as well.\n\nFinally, for invocations of test_submodule_switch() that invoke a custom\nfunction, rename the old function to test_submodule_switch_func().\n\nThis is necessary because in a future commit, we will be adding some\nlogic that needs to distinguish between an invocation of a plain git\ncomamnd and an invocation of a test helper function.\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\n t/lib-submodule-update.sh        | 14 +++++++++-----\n t/t1013-read-tree-submodule.sh   |  4 ++--\n t/t2013-checkout-submodule.sh    |  4 ++--\n t/t3426-rebase-submodule.sh      |  4 ++--\n t/t3512-cherry-pick-submodule.sh |  2 +-\n t/t3513-revert-submodule.sh      |  2 +-\n t/t3906-stash-submodule.sh       |  2 +-\n t/t4137-apply-submodule.sh       |  4 ++--\n t/t4255-am-submodule.sh          |  4 ++--\n t/t5572-pull-submodule.sh        |  8 ++++----\n t/t6041-bisect-submodule.sh      |  2 +-\n t/t7112-reset-submodule.sh       |  6 +++---\n t/t7613-merge-submodule.sh       |  8 ++++----\n 13 files changed, 34 insertions(+), 30 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex bb36287803..7c3ba1be00 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -307,8 +307,8 @@ test_submodule_content () {\n # to protect the history!\n #\n \n-# Internal function; use test_submodule_switch() or\n-# test_submodule_forced_switch() instead.\n+# Internal function; use test_submodule_switch_func(), test_submodule_switch(),\n+# or test_submodule_forced_switch() instead.\n test_submodule_switch_common () {\n \tcommand=\"$1\"\n \t######################### Appearing submodule #########################\n@@ -566,8 +566,8 @@ test_submodule_switch_common () {\n #   # Do something here that updates the worktree and index to match target,\n #   # but not any submodule directories.\n # }\n-# test_submodule_switch \"my_func\"\n-test_submodule_switch () {\n+# test_submodule_switch_func \"my_func\"\n+test_submodule_switch_func () {\n \tcommand=\"$1\"\n \ttest_submodule_switch_common \"$command\"\n \n@@ -587,12 +587,16 @@ test_submodule_switch () {\n \t'\n }\n \n+test_submodule_switch () {\n+\ttest_submodule_switch_func \"git $1\"\n+}\n+\n # Same as test_submodule_switch(), except that throwing away local changes in\n # the superproject is allowed.\n test_submodule_forced_switch () {\n \tcommand=\"$1\"\n \tKNOWN_FAILURE_FORCED_SWITCH_TESTS=1\n-\ttest_submodule_switch_common \"$command\"\n+\ttest_submodule_switch_common \"git $command\"\n \n \t# When forced, a file in the superproject does not prevent creating a\n \t# submodule of the same name.\ndiff --git a/t/t1013-read-tree-submodule.sh b/t/t1013-read-tree-submodule.sh\nindex 91a6fafcb4..b6df7444c0 100755\n--- a/t/t1013-read-tree-submodule.sh\n+++ b/t/t1013-read-tree-submodule.sh\n@@ -12,8 +12,8 @@ test_submodule_switch_recursing_with_args \"read-tree -u -m\"\n \n test_submodule_forced_switch_recursing_with_args \"read-tree -u --reset\"\n \n-test_submodule_switch \"git read-tree -u -m\"\n+test_submodule_switch \"read-tree -u -m\"\n \n-test_submodule_forced_switch \"git read-tree -u --reset\"\n+test_submodule_forced_switch \"read-tree -u --reset\"\n \n test_done\ndiff --git a/t/t2013-checkout-submodule.sh b/t/t2013-checkout-submodule.sh\nindex 8f86b5f4b2..b2bdd1fcb4 100755\n--- a/t/t2013-checkout-submodule.sh\n+++ b/t/t2013-checkout-submodule.sh\n@@ -68,8 +68,8 @@ test_submodule_switch_recursing_with_args \"checkout\"\n \n test_submodule_forced_switch_recursing_with_args \"checkout -f\"\n \n-test_submodule_switch \"git checkout\"\n+test_submodule_switch \"checkout\"\n \n-test_submodule_forced_switch \"git checkout -f\"\n+test_submodule_forced_switch \"checkout -f\"\n \n test_done\ndiff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh\nindex a2bba04ba9..788605ccc0 100755\n--- a/t/t3426-rebase-submodule.sh\n+++ b/t/t3426-rebase-submodule.sh\n@@ -20,7 +20,7 @@ git_rebase () {\n \tgit rebase \"$1\"\n }\n \n-test_submodule_switch \"git_rebase\"\n+test_submodule_switch_func \"git_rebase\"\n \n git_rebase_interactive () {\n \tgit status -su >expect &&\n@@ -38,7 +38,7 @@ git_rebase_interactive () {\n \tgit rebase -i \"$1\"\n }\n \n-test_submodule_switch \"git_rebase_interactive\"\n+test_submodule_switch_func \"git_rebase_interactive\"\n \n test_expect_success 'rebase interactive ignores modified submodules' '\n \ttest_when_finished \"rm -rf super sub\" &&\ndiff --git a/t/t3512-cherry-pick-submodule.sh b/t/t3512-cherry-pick-submodule.sh\nindex bd78287841..6ece1d8573 100755\n--- a/t/t3512-cherry-pick-submodule.sh\n+++ b/t/t3512-cherry-pick-submodule.sh\n@@ -7,7 +7,7 @@ test_description='cherry-pick can handle submodules'\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-test_submodule_switch \"git cherry-pick\"\n+test_submodule_switch \"cherry-pick\"\n \n test_expect_success 'unrelated submodule/file conflict is ignored' '\n \ttest_create_repo sub &&\ndiff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh\nindex 5e39fcdb66..95a7f64471 100755\n--- a/t/t3513-revert-submodule.sh\n+++ b/t/t3513-revert-submodule.sh\n@@ -26,6 +26,6 @@ git_revert () {\n }\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-test_submodule_switch \"git_revert\"\n+test_submodule_switch_func \"git_revert\"\n \n test_done\ndiff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh\nindex b93d1d74da..6a7e801ca0 100755\n--- a/t/t3906-stash-submodule.sh\n+++ b/t/t3906-stash-submodule.sh\n@@ -19,7 +19,7 @@ git_stash () {\n KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES=1\n KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1\n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-test_submodule_switch \"git_stash\"\n+test_submodule_switch_func \"git_stash\"\n \n setup_basic () {\n \ttest_when_finished \"rm -rf main sub\" &&\ndiff --git a/t/t4137-apply-submodule.sh b/t/t4137-apply-submodule.sh\nindex a9bd40a6d0..b645e303a0 100755\n--- a/t/t4137-apply-submodule.sh\n+++ b/t/t4137-apply-submodule.sh\n@@ -9,12 +9,12 @@ apply_index () {\n \tgit diff --ignore-submodules=dirty \"..$1\" | git apply --index -\n }\n \n-test_submodule_switch \"apply_index\"\n+test_submodule_switch_func \"apply_index\"\n \n apply_3way () {\n \tgit diff --ignore-submodules=dirty \"..$1\" | git apply --3way -\n }\n \n-test_submodule_switch \"apply_3way\"\n+test_submodule_switch_func \"apply_3way\"\n \n test_done\ndiff --git a/t/t4255-am-submodule.sh b/t/t4255-am-submodule.sh\nindex 0ba8194403..1b179d5f45 100755\n--- a/t/t4255-am-submodule.sh\n+++ b/t/t4255-am-submodule.sh\n@@ -9,14 +9,14 @@ am () {\n \tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am -\n }\n \n-test_submodule_switch \"am\"\n+test_submodule_switch_func \"am\"\n \n am_3way () {\n \tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am --3way -\n }\n \n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-test_submodule_switch \"am_3way\"\n+test_submodule_switch_func \"am_3way\"\n \n test_expect_success 'setup diff.submodule' '\n \ttest_commit one &&\ndiff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh\nindex f916729a12..f911bf631e 100755\n--- a/t/t5572-pull-submodule.sh\n+++ b/t/t5572-pull-submodule.sh\n@@ -17,21 +17,21 @@ git_pull () {\n }\n \n # pulls without conflicts\n-test_submodule_switch \"git_pull\"\n+test_submodule_switch_func \"git_pull\"\n \n git_pull_ff () {\n \treset_branch_to_HEAD \"$1\" &&\n \tgit pull --ff\n }\n \n-test_submodule_switch \"git_pull_ff\"\n+test_submodule_switch_func \"git_pull_ff\"\n \n git_pull_ff_only () {\n \treset_branch_to_HEAD \"$1\" &&\n \tgit pull --ff-only\n }\n \n-test_submodule_switch \"git_pull_ff_only\"\n+test_submodule_switch_func \"git_pull_ff_only\"\n \n git_pull_noff () {\n \treset_branch_to_HEAD \"$1\" &&\n@@ -40,7 +40,7 @@ git_pull_noff () {\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-test_submodule_switch \"git_pull_noff\"\n+test_submodule_switch_func \"git_pull_noff\"\n \n test_expect_success 'pull --recurse-submodule setup' '\n \ttest_create_repo child &&\ndiff --git a/t/t6041-bisect-submodule.sh b/t/t6041-bisect-submodule.sh\nindex 62b8a2e7bb..0e0cdf638d 100755\n--- a/t/t6041-bisect-submodule.sh\n+++ b/t/t6041-bisect-submodule.sh\n@@ -27,6 +27,6 @@ git_bisect () {\n \tgit bisect bad $BAD\n }\n \n-test_submodule_switch \"git_bisect\"\n+test_submodule_switch_func \"git_bisect\"\n \n test_done\ndiff --git a/t/t7112-reset-submodule.sh b/t/t7112-reset-submodule.sh\nindex a1cb9ff858..8741b665c9 100755\n--- a/t/t7112-reset-submodule.sh\n+++ b/t/t7112-reset-submodule.sh\n@@ -13,10 +13,10 @@ test_submodule_switch_recursing_with_args \"reset --keep\"\n \n test_submodule_forced_switch_recursing_with_args \"reset --hard\"\n \n-test_submodule_switch \"git reset --keep\"\n+test_submodule_switch \"reset --keep\"\n \n-test_submodule_switch \"git reset --merge\"\n+test_submodule_switch \"reset --merge\"\n \n-test_submodule_forced_switch \"git reset --hard\"\n+test_submodule_forced_switch \"reset --hard\"\n \n test_done\ndiff --git a/t/t7613-merge-submodule.sh b/t/t7613-merge-submodule.sh\nindex d1e9fcc781..04bf4be7d7 100755\n--- a/t/t7613-merge-submodule.sh\n+++ b/t/t7613-merge-submodule.sh\n@@ -6,14 +6,14 @@ test_description='merge can handle submodules'\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n # merges without conflicts\n-test_submodule_switch \"git merge\"\n+test_submodule_switch \"merge\"\n \n-test_submodule_switch \"git merge --ff\"\n+test_submodule_switch \"merge --ff\"\n \n-test_submodule_switch \"git merge --ff-only\"\n+test_submodule_switch \"merge --ff-only\"\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-test_submodule_switch \"git merge --no-ff\"\n+test_submodule_switch \"merge --no-ff\"\n \n test_done\n-- \n2.27.0.132.g321788e831\n\n"},{"id":"400419","messageId":"20200623184011.GC1444619@coredump.intra.peff.net","threadId":"53350","inReplyTo":"cover.1592907663.git.liu.denton@gmail.com","subject":"Re: [PATCH v5 0/4] t: replace incorrect test_must_fail usage (part 5)","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2020-06-23T18:40:11Z","receivedAt":"2020-06-23T18:40:14Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Jun 23, 2020 at 06:28:01AM -0400, Denton Liu wrote:\n\n> I've taken your suggestions and rerolled the last patch. Notably, I\n> combined $before and $command into a single function and then passed in\n> `test_must_fail` as the second argument if it's expected to fail. I also\n> decided to use a helper function to reduce the duplication of the\n> calling logic but it's still a little verbose because I opted to make\n> use of argument passing over global variables where possible.\n> \n> One thing that I'm leaning towards is completely removing $after. We can\n> combine $after with $command like I did in the first few iterations of\n> this series and just write it as:\n> \n> \tgit_test_thing () {\n> \t\t# before...\n> \t\t$2 git do-the-thing \"$1\" &&\n> \t\tif test -n \"$2\"\n> \t\tthen\n> \t\t\treturn\n> \t\tfi &&\n> \t\t# after...\n> \t}\n> \n> but I'm also okay with leaving it as is.\n\nYeah, as soon as I saw \"combined $before and $command\", then I wondered\nwhy we needed to split anything (since clearly we're passing\nresponsibility to handle must_fail to the callback function).\n\nSo I think we should either have the full before/command/after split, or\nhave a single callback function which understands that it has to respect\n\"$2\" as a prefix).\n\nI'm OK with either. I do like both of them better than the magic\n$OVERWRITING_FAIL thing, but this series seems to be taking a lot more\nenergy than I think its outcome is worth. Let's resolve it somehow and\nwork on something more exciting. ;)\n\n> Also, one problem that's present is that for tests that use\n> test_submodule_switch() and test_submodule_forced_switch(), $command\n> will be listed as git_test_func, which might make debugging more\n> difficult. I think I'd prefer the version we currently have queued for\n> this reason (and why I did the whole song and dance of $OVERWRITING_FAIL\n> in the first place), but if you think that this is fine, I'm fine with\n> this approach as well.\n\nI agree it's not ideal, but I don't think it's too bad. There are lots\nof tests that have output you can't just cut-and-paste due to code\ngeneration, helper functions, etc.\n\n-Peff\n"},{"id":"400435","messageId":"7b9c19b3606f31b12a79591a41847dcb0a071751.1592942453.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1592907663.git.liu.denton@gmail.com","subject":"[PATCH v5.1] lib-submodule-update: pass 'test_must_fail' as an argument","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-06-23T20:35:14Z","receivedAt":"2020-06-23T20:35:31Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"When we run a test helper function in test_submodule_switch_common(), we\nsometimes specify a whole helper function as the $command. When we do\nthis, in some test cases, we just mark the whole function with\n`test_must_fail`. However, it's possible that the helper function might\nfail earlier or later than expected due to an introduced bug. If this\nhappens, then the test case will still report as passing but it should\nreally be marked as failing since it didn't actually display the\nintended behaviour.\n\nInstead of invoking `test_must_fail $command`, pass the string\n\"test_must_fail\" as the second argument in case where the git command is\nexpected to fail.\n\nWhen $command is a helper function, the parent function calling\ntest_submodule_switch_common() is test_submodule_switch_func(). For all\ntest_submodule_switch_func() invocations, increase the granularity of\nthe argument test helper function by prefixing the git invocation which is\nmeant to fail with the second argument like this:\n\n\t$2 git checkout \"$1\"\n\nIn the other cases, test_submodule_switch() and\ntest_submodule_forced_switch(), instead of passing in the git command\ndirectly, wrap it using the git_test_func() and pass the git arguments\nusing the global variable $gitcmd. Unfortunately, since closures aren't\na thing in shell scripts, the global variable is necessary. Another\nunfortunate result is that the \"git_test_func\" will used as the test\ncase name when $command is printed but it's worth it for the cleaner\ncode.\n\nFinally, as an added bonus, `test_must_fail` will now only run on git\ncommands.\n\nAn alternate design was considered where the global variable,\n$OVERWRITING_FAIL, is set from test_submodule_switch_common() and\nexposed to the helper function. This would allow $command to be set to a\nmore sensible value. However this approach was considered too difficult\nto understand due to the fact that using a signalling magical global\nvariable is too indirect and it's best to keep the magic confined to\nwithin one file.\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\n[I dropped the CC list because I've already sent out two copies of this\npatch but, for some reason, it isn't hitting the list. I don't want to\nspam anyone while I'm experimenting.]\n\nThis patch replaces v5 4/4. Hopefully, this'll be the last iteration...\n\n t/lib-submodule-update.sh   | 49 +++++++++++++++++++++++++++----------\n t/t3426-rebase-submodule.sh |  4 +--\n t/t3513-revert-submodule.sh |  6 ++++-\n t/t3906-stash-submodule.sh  |  6 ++++-\n t/t4137-apply-submodule.sh  |  6 +++--\n t/t4255-am-submodule.sh     |  6 +++--\n t/t5572-pull-submodule.sh   |  8 +++---\n t/t6041-bisect-submodule.sh |  6 ++++-\n 8 files changed, 65 insertions(+), 26 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 7c3ba1be00..53c5374ea1 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -303,8 +303,12 @@ test_submodule_content () {\n # update\" is run. And even then that command doesn't delete the work tree of\n # a removed submodule.\n #\n+# The first argument of the callback function will be the name of the submodule.\n+#\n # Removing a submodule containing a .git directory must fail even when forced\n-# to protect the history!\n+# to protect the history! If we are testing this case, the second argument of\n+# the callback function will be 'test_must_fail', else it will be the empty\n+# string.\n #\n \n # Internal function; use test_submodule_switch_func(), test_submodule_switch(),\n@@ -443,7 +447,7 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\t$command replace_sub1_with_directory test_must_fail &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -456,7 +460,7 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\t$command replace_sub1_with_directory test_must_fail &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -470,7 +474,7 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\t$command replace_sub1_with_file test_must_fail &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -484,7 +488,7 @@ test_submodule_switch_common () {\n \t\t\tcd submodule_update &&\n \t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n \t\t\treplace_gitfile_with_git_dir sub1 &&\n-\t\t\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\t$command replace_sub1_with_file test_must_fail &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -559,12 +563,25 @@ test_submodule_switch_common () {\n # conditions, set the appropriate KNOWN_FAILURE_* variable used in the tests\n # below to 1.\n #\n-# Use as follows:\n+# The first argument of the callback function will be the name of the submodule.\n+#\n+# Removing a submodule containing a .git directory must fail even when forced\n+# to protect the history! If we are testing this case, the second argument of\n+# the callback function will be 'test_must_fail', else it will be the empty\n+# string.\n+#\n+# The following example uses `git some-command` as an example command to be\n+# tested. It updates the worktree and index to match a target, but not any\n+# submodule directories.\n #\n # my_func () {\n-#   target=$1\n-#   # Do something here that updates the worktree and index to match target,\n-#   # but not any submodule directories.\n+#   ...prepare for `git some-command` to be run...\n+#   $2 git some-command \"$1\" &&\n+#   if test -n \"$2\"\n+#   then\n+#     return\n+#   fi &&\n+#   ...check the state after git some-command is run...\n # }\n # test_submodule_switch_func \"my_func\"\n test_submodule_switch_func () {\n@@ -580,23 +597,29 @@ test_submodule_switch_func () {\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\t$command add_sub1 test_must_fail &&\n \t\t\ttest_superproject_content origin/no_submodule &&\n \t\t\ttest_must_be_empty sub1\n \t\t)\n \t'\n }\n \n+git_test_func () {\n+\t$2 git $gitcmd \"$1\"\n+}\n+\n test_submodule_switch () {\n-\ttest_submodule_switch_func \"git $1\"\n+\tgitcmd=\"$1\"\n+\ttest_submodule_switch_func \"git_test_func\"\n }\n \n # Same as test_submodule_switch(), except that throwing away local changes in\n # the superproject is allowed.\n test_submodule_forced_switch () {\n-\tcommand=\"$1\"\n+\tgitcmd=\"$1\"\n+\tcommand=\"git_test_func\"\n \tKNOWN_FAILURE_FORCED_SWITCH_TESTS=1\n-\ttest_submodule_switch_common \"git $command\"\n+\ttest_submodule_switch_common \"$command\"\n \n \t# When forced, a file in the superproject does not prevent creating a\n \t# submodule of the same name.\ndiff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh\nindex 788605ccc0..dd5daa53d3 100755\n--- a/t/t3426-rebase-submodule.sh\n+++ b/t/t3426-rebase-submodule.sh\n@@ -17,7 +17,7 @@ git_rebase () {\n \tgit status -su >actual &&\n \tls -1pR * >>actual &&\n \ttest_cmp expect actual &&\n-\tgit rebase \"$1\"\n+\t$2 git rebase \"$1\"\n }\n \n test_submodule_switch_func \"git_rebase\"\n@@ -35,7 +35,7 @@ git_rebase_interactive () {\n \ttest_cmp expect actual &&\n \tset_fake_editor &&\n \techo \"fake-editor.sh\" >.git/info/exclude &&\n-\tgit rebase -i \"$1\"\n+\t$2 git rebase -i \"$1\"\n }\n \n test_submodule_switch_func \"git_rebase_interactive\"\ndiff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh\nindex 95a7f64471..f98e3301b9 100755\n--- a/t/t3513-revert-submodule.sh\n+++ b/t/t3513-revert-submodule.sh\n@@ -15,7 +15,11 @@ git_revert () {\n \tgit status -su >expect &&\n \tls -1pR * >>expect &&\n \ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n-\tgit checkout \"$1\" &&\n+\t$2 git checkout \"$1\" &&\n+\tif test -n \"$2\"\n+\tthen\n+\t\treturn\n+\tfi &&\n \tgit revert HEAD &&\n \trm -rf * &&\n \ttar xf \"$TRASH_DIRECTORY/tmp.tar\" &&\ndiff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh\nindex 6a7e801ca0..61db4a9886 100755\n--- a/t/t3906-stash-submodule.sh\n+++ b/t/t3906-stash-submodule.sh\n@@ -8,7 +8,11 @@ test_description='stash can handle submodules'\n git_stash () {\n \tgit status -su >expect &&\n \tls -1pR * >>expect &&\n-\tgit read-tree -u -m \"$1\" &&\n+\t$2 git read-tree -u -m \"$1\" &&\n+\tif test -n \"$2\"\n+\tthen\n+\t\treturn\n+\tfi &&\n \tgit stash &&\n \tgit status -su >actual &&\n \tls -1pR * >>actual &&\ndiff --git a/t/t4137-apply-submodule.sh b/t/t4137-apply-submodule.sh\nindex b645e303a0..5477d48ffd 100755\n--- a/t/t4137-apply-submodule.sh\n+++ b/t/t4137-apply-submodule.sh\n@@ -6,13 +6,15 @@ test_description='git apply handling submodules'\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n apply_index () {\n-\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --index -\n+\tgit diff --ignore-submodules=dirty \"..$1\" >diff &&\n+\t$2 git apply --index diff\n }\n \n test_submodule_switch_func \"apply_index\"\n \n apply_3way () {\n-\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --3way -\n+\tgit diff --ignore-submodules=dirty \"..$1\" >diff\n+\t$2 git apply --3way diff\n }\n \n test_submodule_switch_func \"apply_3way\"\ndiff --git a/t/t4255-am-submodule.sh b/t/t4255-am-submodule.sh\nindex 1b179d5f45..8403124ac0 100755\n--- a/t/t4255-am-submodule.sh\n+++ b/t/t4255-am-submodule.sh\n@@ -6,13 +6,15 @@ test_description='git am handling submodules'\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n am () {\n-\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am -\n+\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" >patch &&\n+\t$2 git am patch\n }\n \n test_submodule_switch_func \"am\"\n \n am_3way () {\n-\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am --3way -\n+\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" >patch &&\n+\t$2 git am --3way patch\n }\n \n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\ndiff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh\nindex f911bf631e..cfa40b9251 100755\n--- a/t/t5572-pull-submodule.sh\n+++ b/t/t5572-pull-submodule.sh\n@@ -13,7 +13,7 @@ reset_branch_to_HEAD () {\n \n git_pull () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull\n+\t$2 git pull\n }\n \n # pulls without conflicts\n@@ -21,21 +21,21 @@ test_submodule_switch_func \"git_pull\"\n \n git_pull_ff () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --ff\n+\t$2 git pull --ff\n }\n \n test_submodule_switch_func \"git_pull_ff\"\n \n git_pull_ff_only () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --ff-only\n+\t$2 git pull --ff-only\n }\n \n test_submodule_switch_func \"git_pull_ff_only\"\n \n git_pull_noff () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --no-ff\n+\t$2 git pull --no-ff\n }\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\ndiff --git a/t/t6041-bisect-submodule.sh b/t/t6041-bisect-submodule.sh\nindex 0e0cdf638d..619f181032 100755\n--- a/t/t6041-bisect-submodule.sh\n+++ b/t/t6041-bisect-submodule.sh\n@@ -10,7 +10,11 @@ git_bisect () {\n \tls -1pR * >>expect &&\n \ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n \tGOOD=$(git rev-parse --verify HEAD) &&\n-\tgit checkout \"$1\" &&\n+\t$2 git checkout \"$1\" &&\n+\tif test -n \"$2\"\n+\tthen\n+\t\treturn\n+\tfi &&\n \techo \"foo\" >bar &&\n \tgit add bar &&\n \tgit commit -m \"bisect bad\" &&\n-- \n2.27.0.307.g7979e895e7\n\n"},{"id":"400449","messageId":"7b9c19b3606f31b12a79591a41847dcb0a071751.1592942452.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"cover.1592907663.git.liu.denton@gmail.com","subject":"[PATCH v5.1] lib-submodule-update: pass 'test_must_fail' as an argument","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-06-23T20:21:20Z","receivedAt":"2020-06-23T21:23:02Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"When we run a test helper function in test_submodule_switch_common(), we\nsometimes specify a whole helper function as the $command. When we do\nthis, in some test cases, we just mark the whole function with\n`test_must_fail`. However, it's possible that the helper function might\nfail earlier or later than expected due to an introduced bug. If this\nhappens, then the test case will still report as passing but it should\nreally be marked as failing since it didn't actually display the\nintended behaviour.\n\nInstead of invoking `test_must_fail $command`, pass the string\n\"test_must_fail\" as the second argument in case where the git command is\nexpected to fail.\n\nWhen $command is a helper function, the parent function calling\ntest_submodule_switch_common() is test_submodule_switch_func(). For all\ntest_submodule_switch_func() invocations, increase the granularity of\nthe argument test helper function by prefixing the git invocation which is\nmeant to fail with the second argument like this:\n\n\t$2 git checkout \"$1\"\n\nIn the other cases, test_submodule_switch() and\ntest_submodule_forced_switch(), instead of passing in the git command\ndirectly, wrap it using the git_test_func() and pass the git arguments\nusing the global variable $gitcmd. Unfortunately, since closures aren't\na thing in shell scripts, the global variable is necessary. Another\nunfortunate result is that the \"git_test_func\" will used as the test\ncase name when $command is printed but it's worth it for the cleaner\ncode.\n\nFinally, as an added bonus, `test_must_fail` will now only run on git\ncommands.\n\nAn alternate design was considered where the global variable,\n$OVERWRITING_FAIL, is set from test_submodule_switch_common() and\nexposed to the helper function. This would allow $command to be set to a\nmore sensible value. However this approach was considered too difficult\nto understand due to the fact that using a signalling magical global\nvariable is too indirect and it's best to keep the magic confined to\nwithin one file.\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\nThis patch replaces v5 4/4. Hopefully, this'll be the last iteration...\n\n t/lib-submodule-update.sh   | 49 +++++++++++++++++++++++++++----------\n t/t3426-rebase-submodule.sh |  4 +--\n t/t3513-revert-submodule.sh |  6 ++++-\n t/t3906-stash-submodule.sh  |  6 ++++-\n t/t4137-apply-submodule.sh  |  6 +++--\n t/t4255-am-submodule.sh     |  6 +++--\n t/t5572-pull-submodule.sh   |  8 +++---\n t/t6041-bisect-submodule.sh |  6 ++++-\n 8 files changed, 65 insertions(+), 26 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 7c3ba1be00..53c5374ea1 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -303,8 +303,12 @@ test_submodule_content () {\n # update\" is run. And even then that command doesn't delete the work tree of\n # a removed submodule.\n #\n+# The first argument of the callback function will be the name of the submodule.\n+#\n # Removing a submodule containing a .git directory must fail even when forced\n-# to protect the history!\n+# to protect the history! If we are testing this case, the second argument of\n+# the callback function will be 'test_must_fail', else it will be the empty\n+# string.\n #\n \n # Internal function; use test_submodule_switch_func(), test_submodule_switch(),\n@@ -443,7 +447,7 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\t$command replace_sub1_with_directory test_must_fail &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -456,7 +460,7 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\t$command replace_sub1_with_directory test_must_fail &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -470,7 +474,7 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\t$command replace_sub1_with_file test_must_fail &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -484,7 +488,7 @@ test_submodule_switch_common () {\n \t\t\tcd submodule_update &&\n \t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n \t\t\treplace_gitfile_with_git_dir sub1 &&\n-\t\t\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\t$command replace_sub1_with_file test_must_fail &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -559,12 +563,25 @@ test_submodule_switch_common () {\n # conditions, set the appropriate KNOWN_FAILURE_* variable used in the tests\n # below to 1.\n #\n-# Use as follows:\n+# The first argument of the callback function will be the name of the submodule.\n+#\n+# Removing a submodule containing a .git directory must fail even when forced\n+# to protect the history! If we are testing this case, the second argument of\n+# the callback function will be 'test_must_fail', else it will be the empty\n+# string.\n+#\n+# The following example uses `git some-command` as an example command to be\n+# tested. It updates the worktree and index to match a target, but not any\n+# submodule directories.\n #\n # my_func () {\n-#   target=$1\n-#   # Do something here that updates the worktree and index to match target,\n-#   # but not any submodule directories.\n+#   ...prepare for `git some-command` to be run...\n+#   $2 git some-command \"$1\" &&\n+#   if test -n \"$2\"\n+#   then\n+#     return\n+#   fi &&\n+#   ...check the state after git some-command is run...\n # }\n # test_submodule_switch_func \"my_func\"\n test_submodule_switch_func () {\n@@ -580,23 +597,29 @@ test_submodule_switch_func () {\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\t$command add_sub1 test_must_fail &&\n \t\t\ttest_superproject_content origin/no_submodule &&\n \t\t\ttest_must_be_empty sub1\n \t\t)\n \t'\n }\n \n+git_test_func () {\n+\t$2 git $gitcmd \"$1\"\n+}\n+\n test_submodule_switch () {\n-\ttest_submodule_switch_func \"git $1\"\n+\tgitcmd=\"$1\"\n+\ttest_submodule_switch_func \"git_test_func\"\n }\n \n # Same as test_submodule_switch(), except that throwing away local changes in\n # the superproject is allowed.\n test_submodule_forced_switch () {\n-\tcommand=\"$1\"\n+\tgitcmd=\"$1\"\n+\tcommand=\"git_test_func\"\n \tKNOWN_FAILURE_FORCED_SWITCH_TESTS=1\n-\ttest_submodule_switch_common \"git $command\"\n+\ttest_submodule_switch_common \"$command\"\n \n \t# When forced, a file in the superproject does not prevent creating a\n \t# submodule of the same name.\ndiff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh\nindex 788605ccc0..dd5daa53d3 100755\n--- a/t/t3426-rebase-submodule.sh\n+++ b/t/t3426-rebase-submodule.sh\n@@ -17,7 +17,7 @@ git_rebase () {\n \tgit status -su >actual &&\n \tls -1pR * >>actual &&\n \ttest_cmp expect actual &&\n-\tgit rebase \"$1\"\n+\t$2 git rebase \"$1\"\n }\n \n test_submodule_switch_func \"git_rebase\"\n@@ -35,7 +35,7 @@ git_rebase_interactive () {\n \ttest_cmp expect actual &&\n \tset_fake_editor &&\n \techo \"fake-editor.sh\" >.git/info/exclude &&\n-\tgit rebase -i \"$1\"\n+\t$2 git rebase -i \"$1\"\n }\n \n test_submodule_switch_func \"git_rebase_interactive\"\ndiff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh\nindex 95a7f64471..f98e3301b9 100755\n--- a/t/t3513-revert-submodule.sh\n+++ b/t/t3513-revert-submodule.sh\n@@ -15,7 +15,11 @@ git_revert () {\n \tgit status -su >expect &&\n \tls -1pR * >>expect &&\n \ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n-\tgit checkout \"$1\" &&\n+\t$2 git checkout \"$1\" &&\n+\tif test -n \"$2\"\n+\tthen\n+\t\treturn\n+\tfi &&\n \tgit revert HEAD &&\n \trm -rf * &&\n \ttar xf \"$TRASH_DIRECTORY/tmp.tar\" &&\ndiff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh\nindex 6a7e801ca0..61db4a9886 100755\n--- a/t/t3906-stash-submodule.sh\n+++ b/t/t3906-stash-submodule.sh\n@@ -8,7 +8,11 @@ test_description='stash can handle submodules'\n git_stash () {\n \tgit status -su >expect &&\n \tls -1pR * >>expect &&\n-\tgit read-tree -u -m \"$1\" &&\n+\t$2 git read-tree -u -m \"$1\" &&\n+\tif test -n \"$2\"\n+\tthen\n+\t\treturn\n+\tfi &&\n \tgit stash &&\n \tgit status -su >actual &&\n \tls -1pR * >>actual &&\ndiff --git a/t/t4137-apply-submodule.sh b/t/t4137-apply-submodule.sh\nindex b645e303a0..5477d48ffd 100755\n--- a/t/t4137-apply-submodule.sh\n+++ b/t/t4137-apply-submodule.sh\n@@ -6,13 +6,15 @@ test_description='git apply handling submodules'\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n apply_index () {\n-\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --index -\n+\tgit diff --ignore-submodules=dirty \"..$1\" >diff &&\n+\t$2 git apply --index diff\n }\n \n test_submodule_switch_func \"apply_index\"\n \n apply_3way () {\n-\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --3way -\n+\tgit diff --ignore-submodules=dirty \"..$1\" >diff\n+\t$2 git apply --3way diff\n }\n \n test_submodule_switch_func \"apply_3way\"\ndiff --git a/t/t4255-am-submodule.sh b/t/t4255-am-submodule.sh\nindex 1b179d5f45..8403124ac0 100755\n--- a/t/t4255-am-submodule.sh\n+++ b/t/t4255-am-submodule.sh\n@@ -6,13 +6,15 @@ test_description='git am handling submodules'\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n am () {\n-\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am -\n+\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" >patch &&\n+\t$2 git am patch\n }\n \n test_submodule_switch_func \"am\"\n \n am_3way () {\n-\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am --3way -\n+\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" >patch &&\n+\t$2 git am --3way patch\n }\n \n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\ndiff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh\nindex f911bf631e..cfa40b9251 100755\n--- a/t/t5572-pull-submodule.sh\n+++ b/t/t5572-pull-submodule.sh\n@@ -13,7 +13,7 @@ reset_branch_to_HEAD () {\n \n git_pull () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull\n+\t$2 git pull\n }\n \n # pulls without conflicts\n@@ -21,21 +21,21 @@ test_submodule_switch_func \"git_pull\"\n \n git_pull_ff () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --ff\n+\t$2 git pull --ff\n }\n \n test_submodule_switch_func \"git_pull_ff\"\n \n git_pull_ff_only () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --ff-only\n+\t$2 git pull --ff-only\n }\n \n test_submodule_switch_func \"git_pull_ff_only\"\n \n git_pull_noff () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --no-ff\n+\t$2 git pull --no-ff\n }\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\ndiff --git a/t/t6041-bisect-submodule.sh b/t/t6041-bisect-submodule.sh\nindex 0e0cdf638d..619f181032 100755\n--- a/t/t6041-bisect-submodule.sh\n+++ b/t/t6041-bisect-submodule.sh\n@@ -10,7 +10,11 @@ git_bisect () {\n \tls -1pR * >>expect &&\n \ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n \tGOOD=$(git rev-parse --verify HEAD) &&\n-\tgit checkout \"$1\" &&\n+\t$2 git checkout \"$1\" &&\n+\tif test -n \"$2\"\n+\tthen\n+\t\treturn\n+\tfi &&\n \techo \"foo\" >bar &&\n \tgit add bar &&\n \tgit commit -m \"bisect bad\" &&\n-- \n2.27.0.307.g7979e895e7\n\n"},{"id":"400472","messageId":"xmqq4kr1bao8.fsf@gitster.c.googlers.com","threadId":"53350","inReplyTo":"7b9c19b3606f31b12a79591a41847dcb0a071751.1592942452.git.liu.denton@gmail.com","subject":"Re: [PATCH v5.1] lib-submodule-update: pass 'test_must_fail' as an argument","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-06-23T23:54:31Z","receivedAt":"2020-06-23T23:54:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Denton Liu <liu.denton@gmail.com> writes:\n\n> When $command is a helper function, the parent function calling\n> test_submodule_switch_common() is test_submodule_switch_func(). For all\n> test_submodule_switch_func() invocations, increase the granularity of\n> the argument test helper function by prefixing the git invocation which is\n> meant to fail with the second argument like this:\n>\n> \t$2 git checkout \"$1\"\n>\n> ...\n> Finally, as an added bonus, `test_must_fail` will now only run on git\n> commands.\n\n> This patch replaces v5 4/4. Hopefully, this'll be the last iteration...\n\nSo three copies of v5.1 are identical replacement for 4/4, they seem.\n\n> -\t\t\ttest_must_fail $command replace_sub1_with_directory &&\n> +\t\t\t$command replace_sub1_with_directory test_must_fail &&\n\n> +# The following example uses `git some-command` as an example command to be\n> +# tested. It updates the worktree and index to match a target, but not any\n> +# submodule directories.\n>  #\n>  # my_func () {\n> +#   ...prepare for `git some-command` to be run...\n> +#   $2 git some-command \"$1\" &&\n> +#   if test -n \"$2\"\n> +#   then\n> +#     return\n> +#   fi &&\n\nSo, in practice $2 MUST BE either test_must_fail OR an empty\nstring.  Feeding the my_func anything other than these two values is\na BUG.  I wonder if we can somehow make sure to reduce mental burden\nby readers.  Perhaps\n\n> +git_test_func () {\n\n\tmay_only_be_test_must_fail \"$2\"\n\n> +\t$2 git $gitcmd \"$1\"\n> +}\n\nwhere\n\n\tmay_only_be_test_must_fail () {\n\t\ttest -z \"$1\" || test \"$1\" = test_must_fail || die\n\t}\n\nor something.  The idea is to make sure that this extra helper can\nbe named in such a way that it can serve as a documention to help\nreaders of \"git_test_func ()\" and others about \"$2\".\n\n> diff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh\n> index 788605ccc0..dd5daa53d3 100755\n> --- a/t/t3426-rebase-submodule.sh\n> +++ b/t/t3426-rebase-submodule.sh\n> @@ -17,7 +17,7 @@ git_rebase () {\n>  \tgit status -su >actual &&\n>  \tls -1pR * >>actual &&\n>  \ttest_cmp expect actual &&\n> -\tgit rebase \"$1\"\n> +\t$2 git rebase \"$1\"\n\nLikewise here.\n\nEven without such a change this round reads much better than the\nprevious ones.\n\n> An alternate design was considered where the global variable,\n> $OVERWRITING_FAIL, is set from test_submodule_switch_common() and\n> exposed to the helper function.  This would allow $command to be\n> set to a more sensible value. However ...\n\nBy the way, I do not think this paragraph adds much value to the\nmessage.  It wasn't clear how OVERWRITING_FAIL wanted to achieve its\ngoal back in its own commit, and without any actual code but with\nonly the four lines to go by, there is no chance that you can\nconvince anybody how $command could have been \"more sensible value\".\n\nThanks.\n\n"},{"id":"400475","messageId":"20200624001654.GA18358@danh.dev","threadId":"53350","inReplyTo":"7b9c19b3606f31b12a79591a41847dcb0a071751.1592942452.git.liu.denton@gmail.com","subject":"Re: [PATCH v5.1] lib-submodule-update: pass 'test_must_fail' as an argument","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2020-06-24T00:16:54Z","receivedAt":"2020-06-24T00:16:59Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"On 2020-06-23 16:21:20-0400, Denton Liu <liu.denton@gmail.com> wrote:\n> diff --git a/t/t4137-apply-submodule.sh b/t/t4137-apply-submodule.sh\n> index b645e303a0..5477d48ffd 100755\n> --- a/t/t4137-apply-submodule.sh\n> +++ b/t/t4137-apply-submodule.sh\n> @@ -6,13 +6,15 @@ test_description='git apply handling submodules'\n>  . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n>  \n>  apply_index () {\n> -\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --index -\n> +\tgit diff --ignore-submodules=dirty \"..$1\" >diff &&\n> +\t$2 git apply --index diff\n>  }\n>  \n>  test_submodule_switch_func \"apply_index\"\n>  \n>  apply_3way () {\n> -\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --3way -\n> +\tgit diff --ignore-submodules=dirty \"..$1\" >diff\n> +\t$2 git apply --3way diff\n\nIt seems like you forgot to chain commands with '&&' here.\n\n>  }\n>  \n>  test_submodule_switch_func \"apply_3way\"\n\n-- \nDanh\n"},{"id":"400491","messageId":"9ea9d3ff08266e9f1062632c4b1ff1e5f23733bd.1592981264.git.liu.denton@gmail.com","threadId":"53350","inReplyTo":"7b9c19b3606f31b12a79591a41847dcb0a071751.1592942452.git.liu.denton@gmail.com","subject":"[PATCH v5.2] lib-submodule-update: pass 'test_must_fail' as an argument","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2020-06-24T08:50:18Z","receivedAt":"2020-06-24T08:50:53Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"When we run a test helper function in test_submodule_switch_common(), we\nsometimes specify a whole helper function as the $command. When we do\nthis, in some test cases, we just mark the whole function with\n`test_must_fail`. However, it's possible that the helper function might\nfail earlier or later than expected due to an introduced bug. If this\nhappens, then the test case will still report as passing but it should\nreally be marked as failing since it didn't actually display the\nintended behaviour.\n\nInstead of invoking `test_must_fail $command`, pass the string\n\"test_must_fail\" as the second argument in case where the git command is\nexpected to fail.\n\nWhen $command is a helper function, the parent function calling\ntest_submodule_switch_common() is test_submodule_switch_func(). For all\ntest_submodule_switch_func() invocations, increase the granularity of\nthe argument test helper function by prefixing the git invocation which is\nmeant to fail with the second argument like this:\n\n\t$2 git checkout \"$1\"\n\nIn the other cases, test_submodule_switch() and\ntest_submodule_forced_switch(), instead of passing in the git command\ndirectly, wrap it using the git_test_func() and pass the git arguments\nusing the global variable $gitcmd. Unfortunately, since closures aren't\na thing in shell scripts, the global variable is necessary. Another\nunfortunate result is that the \"git_test_func\" will used as the test\ncase name when $command is printed but it's worth it for the cleaner\ncode.\n\nFinally, as an added bonus, `test_must_fail` will now only run on git\ncommands.\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\nChanges since v5.1:\n\n* Fix broken &&-chain\n\n* Add may_only_be_test_must_fail() checks\n\n* Remove $OVERWRITING_FAIL from the commit message\n\n t/lib-submodule-update.sh   | 55 ++++++++++++++++++++++++++++---------\n t/t3426-rebase-submodule.sh |  6 ++--\n t/t3513-revert-submodule.sh |  7 ++++-\n t/t3906-stash-submodule.sh  |  7 ++++-\n t/t4137-apply-submodule.sh  |  8 ++++--\n t/t4255-am-submodule.sh     |  8 ++++--\n t/t5572-pull-submodule.sh   | 12 +++++---\n t/t6041-bisect-submodule.sh |  7 ++++-\n 8 files changed, 84 insertions(+), 26 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 7c3ba1be00..8e9f310bcb 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -303,8 +303,12 @@ test_submodule_content () {\n # update\" is run. And even then that command doesn't delete the work tree of\n # a removed submodule.\n #\n+# The first argument of the callback function will be the name of the submodule.\n+#\n # Removing a submodule containing a .git directory must fail even when forced\n-# to protect the history!\n+# to protect the history! If we are testing this case, the second argument of\n+# the callback function will be 'test_must_fail', else it will be the empty\n+# string.\n #\n \n # Internal function; use test_submodule_switch_func(), test_submodule_switch(),\n@@ -443,7 +447,7 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\t$command replace_sub1_with_directory test_must_fail &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -456,7 +460,7 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\t$command replace_sub1_with_directory test_must_fail &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -470,7 +474,7 @@ test_submodule_switch_common () {\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\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\t$command replace_sub1_with_file test_must_fail &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n \t\t)\n@@ -484,7 +488,7 @@ test_submodule_switch_common () {\n \t\t\tcd submodule_update &&\n \t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n \t\t\treplace_gitfile_with_git_dir sub1 &&\n-\t\t\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\t$command replace_sub1_with_file test_must_fail &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_git_directory_is_unchanged sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -559,12 +563,25 @@ test_submodule_switch_common () {\n # conditions, set the appropriate KNOWN_FAILURE_* variable used in the tests\n # below to 1.\n #\n-# Use as follows:\n+# The first argument of the callback function will be the name of the submodule.\n+#\n+# Removing a submodule containing a .git directory must fail even when forced\n+# to protect the history! If we are testing this case, the second argument of\n+# the callback function will be 'test_must_fail', else it will be the empty\n+# string.\n+#\n+# The following example uses `git some-command` as an example command to be\n+# tested. It updates the worktree and index to match a target, but not any\n+# submodule directories.\n #\n # my_func () {\n-#   target=$1\n-#   # Do something here that updates the worktree and index to match target,\n-#   # but not any submodule directories.\n+#   ...prepare for `git some-command` to be run...\n+#   $2 git some-command \"$1\" &&\n+#   if test -n \"$2\"\n+#   then\n+#     return\n+#   fi &&\n+#   ...check the state after git some-command is run...\n # }\n # test_submodule_switch_func \"my_func\"\n test_submodule_switch_func () {\n@@ -580,23 +597,35 @@ test_submodule_switch_func () {\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\t$command add_sub1 test_must_fail &&\n \t\t\ttest_superproject_content origin/no_submodule &&\n \t\t\ttest_must_be_empty sub1\n \t\t)\n \t'\n }\n \n+# Ensures that the that the arg either contains \"test_must_fail\" or is empty.\n+may_only_be_test_must_fail () {\n+\ttest -z \"$1\" || test \"$1\" = test_must_fail || die\n+}\n+\n+git_test_func () {\n+\tmay_only_be_test_must_fail \"$2\" &&\n+\t$2 git $gitcmd \"$1\"\n+}\n+\n test_submodule_switch () {\n-\ttest_submodule_switch_func \"git $1\"\n+\tgitcmd=\"$1\"\n+\ttest_submodule_switch_func \"git_test_func\"\n }\n \n # Same as test_submodule_switch(), except that throwing away local changes in\n # the superproject is allowed.\n test_submodule_forced_switch () {\n-\tcommand=\"$1\"\n+\tgitcmd=\"$1\"\n+\tcommand=\"git_test_func\"\n \tKNOWN_FAILURE_FORCED_SWITCH_TESTS=1\n-\ttest_submodule_switch_common \"git $command\"\n+\ttest_submodule_switch_common \"$command\"\n \n \t# When forced, a file in the superproject does not prevent creating a\n \t# submodule of the same name.\ndiff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh\nindex 788605ccc0..0ad3a07bf4 100755\n--- a/t/t3426-rebase-submodule.sh\n+++ b/t/t3426-rebase-submodule.sh\n@@ -17,7 +17,8 @@ git_rebase () {\n \tgit status -su >actual &&\n \tls -1pR * >>actual &&\n \ttest_cmp expect actual &&\n-\tgit rebase \"$1\"\n+\tmay_only_be_test_must_fail \"$2\" &&\n+\t$2 git rebase \"$1\"\n }\n \n test_submodule_switch_func \"git_rebase\"\n@@ -35,7 +36,8 @@ git_rebase_interactive () {\n \ttest_cmp expect actual &&\n \tset_fake_editor &&\n \techo \"fake-editor.sh\" >.git/info/exclude &&\n-\tgit rebase -i \"$1\"\n+\tmay_only_be_test_must_fail \"$2\" &&\n+\t$2 git rebase -i \"$1\"\n }\n \n test_submodule_switch_func \"git_rebase_interactive\"\ndiff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh\nindex 95a7f64471..a759f12cbb 100755\n--- a/t/t3513-revert-submodule.sh\n+++ b/t/t3513-revert-submodule.sh\n@@ -15,7 +15,12 @@ git_revert () {\n \tgit status -su >expect &&\n \tls -1pR * >>expect &&\n \ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n-\tgit checkout \"$1\" &&\n+\tmay_only_be_test_must_fail \"$2\" &&\n+\t$2 git checkout \"$1\" &&\n+\tif test -n \"$2\"\n+\tthen\n+\t\treturn\n+\tfi &&\n \tgit revert HEAD &&\n \trm -rf * &&\n \ttar xf \"$TRASH_DIRECTORY/tmp.tar\" &&\ndiff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh\nindex 6a7e801ca0..a52e53dd2d 100755\n--- a/t/t3906-stash-submodule.sh\n+++ b/t/t3906-stash-submodule.sh\n@@ -8,7 +8,12 @@ test_description='stash can handle submodules'\n git_stash () {\n \tgit status -su >expect &&\n \tls -1pR * >>expect &&\n-\tgit read-tree -u -m \"$1\" &&\n+\tmay_only_be_test_must_fail \"$2\" &&\n+\t$2 git read-tree -u -m \"$1\" &&\n+\tif test -n \"$2\"\n+\tthen\n+\t\treturn\n+\tfi &&\n \tgit stash &&\n \tgit status -su >actual &&\n \tls -1pR * >>actual &&\ndiff --git a/t/t4137-apply-submodule.sh b/t/t4137-apply-submodule.sh\nindex b645e303a0..07d5262537 100755\n--- a/t/t4137-apply-submodule.sh\n+++ b/t/t4137-apply-submodule.sh\n@@ -6,13 +6,17 @@ test_description='git apply handling submodules'\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n apply_index () {\n-\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --index -\n+\tgit diff --ignore-submodules=dirty \"..$1\" >diff &&\n+\tmay_only_be_test_must_fail \"$2\" &&\n+\t$2 git apply --index diff\n }\n \n test_submodule_switch_func \"apply_index\"\n \n apply_3way () {\n-\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --3way -\n+\tgit diff --ignore-submodules=dirty \"..$1\" >diff &&\n+\tmay_only_be_test_must_fail \"$2\" &&\n+\t$2 git apply --3way diff\n }\n \n test_submodule_switch_func \"apply_3way\"\ndiff --git a/t/t4255-am-submodule.sh b/t/t4255-am-submodule.sh\nindex 1b179d5f45..a7ba08f728 100755\n--- a/t/t4255-am-submodule.sh\n+++ b/t/t4255-am-submodule.sh\n@@ -6,13 +6,17 @@ test_description='git am handling submodules'\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n am () {\n-\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am -\n+\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" >patch &&\n+\tmay_only_be_test_must_fail \"$2\" &&\n+\t$2 git am patch\n }\n \n test_submodule_switch_func \"am\"\n \n am_3way () {\n-\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am --3way -\n+\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" >patch &&\n+\tmay_only_be_test_must_fail \"$2\" &&\n+\t$2 git am --3way patch\n }\n \n KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\ndiff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh\nindex f911bf631e..1d75e3b12b 100755\n--- a/t/t5572-pull-submodule.sh\n+++ b/t/t5572-pull-submodule.sh\n@@ -13,7 +13,8 @@ reset_branch_to_HEAD () {\n \n git_pull () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull\n+\tmay_only_be_test_must_fail \"$2\" &&\n+\t$2 git pull\n }\n \n # pulls without conflicts\n@@ -21,21 +22,24 @@ test_submodule_switch_func \"git_pull\"\n \n git_pull_ff () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --ff\n+\tmay_only_be_test_must_fail \"$2\" &&\n+\t$2 git pull --ff\n }\n \n test_submodule_switch_func \"git_pull_ff\"\n \n git_pull_ff_only () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --ff-only\n+\tmay_only_be_test_must_fail \"$2\" &&\n+\t$2 git pull --ff-only\n }\n \n test_submodule_switch_func \"git_pull_ff_only\"\n \n git_pull_noff () {\n \treset_branch_to_HEAD \"$1\" &&\n-\tgit pull --no-ff\n+\tmay_only_be_test_must_fail \"$2\" &&\n+\t$2 git pull --no-ff\n }\n \n KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\ndiff --git a/t/t6041-bisect-submodule.sh b/t/t6041-bisect-submodule.sh\nindex 0e0cdf638d..df1eff0fb8 100755\n--- a/t/t6041-bisect-submodule.sh\n+++ b/t/t6041-bisect-submodule.sh\n@@ -10,7 +10,12 @@ git_bisect () {\n \tls -1pR * >>expect &&\n \ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n \tGOOD=$(git rev-parse --verify HEAD) &&\n-\tgit checkout \"$1\" &&\n+\tmay_only_be_test_must_fail \"$2\" &&\n+\t$2 git checkout \"$1\" &&\n+\tif test -n \"$2\"\n+\tthen\n+\t\treturn\n+\tfi &&\n \techo \"foo\" >bar &&\n \tgit add bar &&\n \tgit commit -m \"bisect bad\" &&\n-- \n2.27.0.307.g7979e895e7\n\n"},{"id":"400536","messageId":"xmqqd05o8ndw.fsf@gitster.c.googlers.com","threadId":"53350","inReplyTo":"9ea9d3ff08266e9f1062632c4b1ff1e5f23733bd.1592981264.git.liu.denton@gmail.com","subject":"Re: [PATCH v5.2] lib-submodule-update: pass 'test_must_fail' as an argument","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-06-24T16:00:27Z","receivedAt":"2020-06-24T16:00:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Denton Liu <liu.denton@gmail.com> writes:\n\n> +# Ensures that the that the arg either contains \"test_must_fail\" or is empty.\n> +may_only_be_test_must_fail () {\n> +\ttest -z \"$1\" || test \"$1\" = test_must_fail || die\n\nNo error message?  I guess it is OK as this is to only catch a bug\nin the test script, not a bug in Git being tested.\n\n> @@ -17,7 +17,8 @@ git_rebase () {\n>  \tgit status -su >actual &&\n>  \tls -1pR * >>actual &&\n>  \ttest_cmp expect actual &&\n> -\tgit rebase \"$1\"\n> +\tmay_only_be_test_must_fail \"$2\" &&\n> +\t$2 git rebase \"$1\"\n>  }\n\nI would have expected the sanity check for incoming arguments would\nbe done at the very beginning, but I guess it is OK (the same\ncomment applies to all the others).\n\n> @@ -15,7 +15,12 @@ git_revert () {\n>  \tgit status -su >expect &&\n>  \tls -1pR * >>expect &&\n>  \ttar cf \"$TRASH_DIRECTORY/tmp.tar\" * &&\n> -\tgit checkout \"$1\" &&\n> +\tmay_only_be_test_must_fail \"$2\" &&\n> +\t$2 git checkout \"$1\" &&\n> +\tif test -n \"$2\"\n> +\tthen\n> +\t\treturn\n> +\tfi &&\n\nThe addition to \"git_rebase\" does not need this \"if must-fail was\ngiven, return early\" because it was at the end of the helper, but\nhere we have some post procedure that relies on the checkout to\nbe successful, so after correctly failing the checkout we return.\n\nIt is somewhat tricky, but OK.  The same for the next one.\n\n> diff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh\n> index 6a7e801ca0..a52e53dd2d 100755\n> --- a/t/t3906-stash-submodule.sh\n> +++ b/t/t3906-stash-submodule.sh\n> @@ -8,7 +8,12 @@ test_description='stash can handle submodules'\n>  git_stash () {\n>  \tgit status -su >expect &&\n>  \tls -1pR * >>expect &&\n> -\tgit read-tree -u -m \"$1\" &&\n> +\tmay_only_be_test_must_fail \"$2\" &&\n> +\t$2 git read-tree -u -m \"$1\" &&\n> +\tif test -n \"$2\"\n> +\tthen\n> +\t\treturn\n> +\tfi &&\n>  \tgit stash &&\n>  \tgit status -su >actual &&\n>  \tls -1pR * >>actual &&\n\nLooking good.  Will replace.\n\nThanks.\n"}]}