{"thread":{"id":"58200","subject":"[PATCH 0/6] tests: fix ignored & hidden exit codes","startedAt":"2022-07-21T06:51:53Z","lastAt":"2023-02-06T23:34:16Z","messageCount":83,"participants":["Ævar Arnfjörð Bjarmason","Eric Sunshine","René Scharfe","Junio C Hamano","Torsten Bögershausen","Phillip Wood"],"isPatch":true,"patchVersion":1,"patchTotal":6},"messages":[{"id":"459576","messageId":"cover-0.6-00000000000-20220721T064349Z-avarab@gmail.com","threadId":"58200","inReplyTo":null,"subject":"[PATCH 0/6] tests: fix ignored & hidden exit codes","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-21T06:51:37Z","receivedAt":"2022-07-21T06:51:53Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"A small set of fixes to correct git on the LHS of a pipe, and in $()\nwithin a \"test\" expression, or where its exit code is otherwise\nhidden.\n\nThis also includes a (reworded) version of a case where we exit'd out\nof test-lib.sh itself, which Junio requested by spun off in:\nhttps://lore.kernel.org/git/xmqqmtd33e1h.fsf@gitster.g/\n\nAs noted in [1] there's no need to rebase the other series on top of\nthis, it benefits from 6/6 here, but the two can proceed\nindependently.\n\nThis is still just the tip of the iceberg in terms of hidden exit\ncodes in the test suite, as can be seen with e.g.:\n\n\tgit grep 'test.*\\$\\((git|test-tool)' -- 't/*.sh'\n\nBut these are all cases I've run into actual issues with, almost all\nwhen testing with SANITIZE=leak. In most cases just with one of the\nhunks in a given commit, but then I converted the rest of the file to\nfix a similar bad pattern.\n\nThat doesn't mean that these are more important than e.g. the output\nof the \"grep\" above, but we've got to start somewhere...\n\nThe range-diff below is to the tip of [2], to show how 6/6 was\nreworded.\n\n1. https://lore.kernel.org/git/cover-v2-00.14-00000000000-20220720T211221Z-avarab@gmail.com/\n2. https://lore.kernel.org/git/cover-00.10-00000000000-20220719T205710Z-avarab@gmail.com/\n\nÆvar Arnfjörð Bjarmason (6):\n  diff tests: fix ignored exit codes in t4023\n  t/lib-patch-mode.sh: fix ignored \"git\" exit codes\n  auto-crlf tests: check \"git checkout\" exit code\n  test-lib-functions: add and use test_cmp_cmd\n  merge tests: don't ignore \"rev-parse\" exit code in helper\n  log tests: don't use \"exit 1\" outside a sub-shell\n\n t/lib-patch-mode.sh               | 13 ++++++---\n t/t0027-auto-crlf.sh              | 14 +++++++---\n t/t0060-path-utils.sh             | 45 +++++++++++++++++--------------\n t/t4023-diff-rename-typechange.sh | 12 ++++-----\n t/t4205-log-pretty-formats.sh     |  2 +-\n t/t7600-merge.sh                  |  9 +++----\n t/test-lib-functions.sh           | 18 +++++++++++++\n 7 files changed, 74 insertions(+), 39 deletions(-)\n\nRange-diff:\n-:  ----------- > 1:  f8a382841d5 diff tests: fix ignored exit codes in t4023\n-:  ----------- > 2:  85c6ab40e91 t/lib-patch-mode.sh: fix ignored \"git\" exit codes\n-:  ----------- > 3:  cfc1abbf7e3 auto-crlf tests: check \"git checkout\" exit code\n-:  ----------- > 4:  df1b674b8a7 test-lib-functions: add and use test_cmp_cmd\n-:  ----------- > 5:  563666f9426 merge tests: don't ignore \"rev-parse\" exit code in helper\n1:  9cedf0cb0e2 ! 6:  259b4618fcb log tests: don't use \"exit 1\" outside a sub-shell\n    @@ Commit message\n         Using \"exit 1\" outside a sub-shell will cause the test framework\n         itself to exit on failure, which isn't what we want to do here.\n     \n    -    This issue was spotted with the new\n    -    \"GIT_TEST_PASSING_SANITIZE_LEAK=check\" mode, i.e. that \"git show\"\n    -    command leaks memory, and we'd thus \"exit 1\". Another implementation\n    -    of \"GIT_TEST_PASSING_SANITIZE_LEAK=check\" or \"--invert-exit-code\"\n    -    might have intercepted the \"exit 1\", and thus hidden the underlying\n    -    issue here, but we correctly distinguish the two.\n    +    This issue was spotted with the in-flight\n    +    \"GIT_TEST_PASSING_SANITIZE_LEAK=check\" test mode[1]. This \"git show\"\n    +    invocation currently leaks memory, and we'd thus \"exit 1\". This change\n    +    was initially part of that topic[2] to demonstrate the correctness of\n    +    the \"check\" implementation.\n    +\n    +    1. https://lore.kernel.org/git/patch-07.10-0961df2ab6c-20220719T205710Z-avarab@gmail.com/\n    +    2. https://lore.kernel.org/git/patch-10.10-9cedf0cb0e2-20220719T205710Z-avarab@gmail.com/\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n-- \n2.37.1.1095.g64a1e8362fd\n\n"},{"id":"459577","messageId":"patch-1.6-f8a382841d5-20220721T064349Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-0.6-00000000000-20220721T064349Z-avarab@gmail.com","subject":"[PATCH 1/6] diff tests: fix ignored exit codes in t4023","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-21T06:51:38Z","receivedAt":"2022-07-21T06:51:56Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change a \"git diff-tree\" command to be &&-chained so that we won't\nignore its exit code, see the ea05fd5fbf7 (Merge branch\n'ab/keep-git-exit-codes-in-tests', 2022-03-16) topic for prior art.\n\nThis fixes code added in b45563a229f (rename: Break filepairs with\ndifferent types., 2007-11-30). Due to hiding the exit code we hid a\nmemory leak under SANITIZE=leak.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t4023-diff-rename-typechange.sh | 12 ++++++------\n 1 file changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/t/t4023-diff-rename-typechange.sh b/t/t4023-diff-rename-typechange.sh\nindex 7cb99092938..25c31b0cb1b 100755\n--- a/t/t4023-diff-rename-typechange.sh\n+++ b/t/t4023-diff-rename-typechange.sh\n@@ -52,8 +52,8 @@ test_expect_success setup '\n '\n \n test_expect_success 'cross renames to be detected for regular files' '\n-\n-\tgit diff-tree five six -r --name-status -B -M | sort >actual &&\n+\tgit diff-tree five six -r --name-status -B -M >out &&\n+\tsort <out >actual &&\n \t{\n \t\techo \"R100\tfoo\tbar\" &&\n \t\techo \"R100\tbar\tfoo\"\n@@ -63,8 +63,8 @@ test_expect_success 'cross renames to be detected for regular files' '\n '\n \n test_expect_success 'cross renames to be detected for typechange' '\n-\n-\tgit diff-tree one two -r --name-status -B -M | sort >actual &&\n+\tgit diff-tree one two -r --name-status -B -M >out &&\n+\tsort <out >actual &&\n \t{\n \t\techo \"R100\tfoo\tbar\" &&\n \t\techo \"R100\tbar\tfoo\"\n@@ -74,8 +74,8 @@ test_expect_success 'cross renames to be detected for typechange' '\n '\n \n test_expect_success 'moves and renames' '\n-\n-\tgit diff-tree three four -r --name-status -B -M | sort >actual &&\n+\tgit diff-tree three four -r --name-status -B -M >out &&\n+\tsort <out >actual &&\n \t{\n \t\t# see -B -M (#6) in t4008\n \t\techo \"C100\tfoo\tbar\" &&\n-- \n2.37.1.1095.g64a1e8362fd\n\n"},{"id":"459578","messageId":"patch-2.6-85c6ab40e91-20220721T064349Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-0.6-00000000000-20220721T064349Z-avarab@gmail.com","subject":"[PATCH 2/6] t/lib-patch-mode.sh: fix ignored \"git\" exit codes","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-21T06:51:39Z","receivedAt":"2022-07-21T06:51:57Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Fix code added in b319ef70a94 (Add a small patch-mode testing library,\n2009-08-13) to use &&-chaining and test_cmp instead of interpolating\n\"git\" commands in a \"test\" statement.\n\nThis fixes cases where we'd have e.g. missed memory leaks under\nSANITIZE=leak, this code doesn't leak now as far as I can tell, but I\ndiscovered it while looking at leaks in related code.\n\nThe \"cat _head >expect\" here is redundant, we could simply give\n\"_head\" to \"test_cmp\", but let's be consistent in using the \"expect\"\nand \"actual\" names for clarity.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/lib-patch-mode.sh | 13 ++++++++++---\n 1 file changed, 10 insertions(+), 3 deletions(-)\n\ndiff --git a/t/lib-patch-mode.sh b/t/lib-patch-mode.sh\nindex cfd76bf987b..887554933c2 100644\n--- a/t/lib-patch-mode.sh\n+++ b/t/lib-patch-mode.sh\n@@ -29,8 +29,13 @@ set_and_save_state () {\n \n # verify_state <path> <expected-worktree-content> <expected-index-content>\n verify_state () {\n-\ttest \"$(cat \"$1\")\" = \"$2\" &&\n-\ttest \"$(git show :\"$1\")\" = \"$3\"\n+\techo \"$2\" >expect &&\n+\tcat \"$1\" >actual &&\n+\ttest_cmp expect actual &&\n+\n+\techo \"$3\" >expect\n+\tgit show :\"$1\" >actual &&\n+\ttest_cmp expect actual\n }\n \n # verify_saved_state <path>\n@@ -46,5 +51,7 @@ save_head () {\n }\n \n verify_saved_head () {\n-\ttest \"$(cat _head)\" = \"$(git rev-parse HEAD)\"\n+\tcat _head >expect &&\n+\tgit rev-parse HEAD >actual &&\n+\ttest_cmp expect actual\n }\n-- \n2.37.1.1095.g64a1e8362fd\n\n"},{"id":"459579","messageId":"patch-3.6-cfc1abbf7e3-20220721T064349Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-0.6-00000000000-20220721T064349Z-avarab@gmail.com","subject":"[PATCH 3/6] auto-crlf tests: check \"git checkout\" exit code","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-21T06:51:40Z","receivedAt":"2022-07-21T06:51:59Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Don't hide the exit code from the \"git checkout\" we run to checkout\nour attributes file.\n\nThis fixes cases where we'd have e.g. missed memory leaks under\nSANITIZE=leak, this code doesn't leak (the relevant \"git checkout\"\nleak has been fixed), but in a past version of git we'd continue past\nthis failure under SANITIZE=leak when these invocations had errored\nout, even under \"--immediate\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t0027-auto-crlf.sh | 14 ++++++++++----\n 1 file changed, 10 insertions(+), 4 deletions(-)\n\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex 7f80f463930..03b955b774f 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -293,11 +293,17 @@ checkout_files () {\n \tpfx=eol_${ceol}_crlf_${crlf}_attr_${attr}_ &&\n \tfor f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul\n \tdo\n-\t\trm crlf_false_attr__$f.txt &&\n-\t\tif test -z \"$ceol\"; then\n-\t\t\tgit checkout -- crlf_false_attr__$f.txt\n+\t\tif test -z \"$ceol\"\n+\t\tthen\n+\t\t\ttest_expect_success \"setup $f checkout\" '\n+\t\t\t\trm crlf_false_attr__$f.txt &&\n+\t\t\t\tgit checkout -- crlf_false_attr__$f.txt\n+\t\t\t'\n \t\telse\n-\t\t\tgit -c core.eol=$ceol checkout -- crlf_false_attr__$f.txt\n+\t\t\ttest_expect_success \"setup $f checkout with core.eol=$ceol\" '\n+\t\t\t\trm crlf_false_attr__$f.txt &&\n+\t\t\t\tgit -c core.eol=$ceol checkout -- crlf_false_attr__$f.txt\n+\t\t\t'\n \t\tfi\n \tdone\n \n-- \n2.37.1.1095.g64a1e8362fd\n\n"},{"id":"459580","messageId":"patch-4.6-df1b674b8a7-20220721T064349Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-0.6-00000000000-20220721T064349Z-avarab@gmail.com","subject":"[PATCH 4/6] test-lib-functions: add and use test_cmp_cmd","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-21T06:51:41Z","receivedAt":"2022-07-21T06:52:02Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add a \"test_cmp_cmd\" helper for the common pattern discussed in the\ndocumentation being added here to \"t/test-lib-functions.sh\".\n\nThis implementation leaves the door open for extending this helper\npast its obvious limitations, such as:\n\n\ttest_cmp_cmd \"some\" \"lines\" -- <some-cmd>\n\ttest_cmp_cmd --stdin <some-cmd> <expect\n\ttest_cmp_cmd --ignore-stderr \"output\" <some-cmd>\n\nBy using this in t0060-path.sh we'll catch cases where \"git\" or\n\"test-tool\" errors (such as segfaults or abort()) were previously\nhidden, and we'd either pass the test, or fail in some subsequent\nassertion.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t0060-path-utils.sh   | 45 +++++++++++++++++++++++------------------\n t/test-lib-functions.sh | 18 +++++++++++++++++\n 2 files changed, 43 insertions(+), 20 deletions(-)\n\ndiff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh\nindex 1f2007e62b7..6f278417e83 100755\n--- a/t/t0060-path-utils.sh\n+++ b/t/t0060-path-utils.sh\n@@ -10,8 +10,11 @@ TEST_PASSES_SANITIZE_LEAK=true\n \n norm_path() {\n \texpected=$(test-tool path-utils print_path \"$2\")\n-\ttest_expect_success $3 \"normalize path: $1 => $2\" \\\n-\t\"test \\\"\\$(test-tool path-utils normalize_path_copy '$1')\\\" = '$expected'\"\n+\ttest_expect_success $3 \"normalize path: $1 => $2\" \"\n+\t\techo '$expected' >expect &&\n+\t\ttest-tool path-utils normalize_path_copy '$1' >actual &&\n+\t\ttest_cmp expect actual\n+\t\"\n }\n \n relative_path() {\n@@ -166,8 +169,10 @@ ancestor D:/Users/me C:/ -1 MINGW\n ancestor //server/share/my-directory //server/share/ 14 MINGW\n \n test_expect_success 'strip_path_suffix' '\n-\ttest c:/msysgit = $(test-tool path-utils strip_path_suffix \\\n-\t\tc:/msysgit/libexec//git-core libexec/git-core)\n+\techo c:/msysgit >expect &&\n+\ttest-tool path-utils strip_path_suffix \\\n+\t\tc:/msysgit/libexec//git-core libexec/git-core >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'absolute path rejects the empty string' '\n@@ -189,34 +194,34 @@ test_expect_success 'real path rejects the empty string' '\n \n test_expect_success POSIX 'real path works on absolute paths 1' '\n \tnopath=\"hopefully-absent-path\" &&\n-\ttest \"/\" = \"$(test-tool path-utils real_path \"/\")\" &&\n-\ttest \"/$nopath\" = \"$(test-tool path-utils real_path \"/$nopath\")\"\n+\ttest_cmp_cmd / test-tool path-utils real_path \"/\" &&\n+\ttest_cmp_cmd \"/$nopath\" test-tool path-utils real_path \"/$nopath\"\n '\n \n test_expect_success 'real path works on absolute paths 2' '\n \tnopath=\"hopefully-absent-path\" &&\n \t# Find an existing top-level directory for the remaining tests:\n \td=$(pwd -P | sed -e \"s|^\\([^/]*/[^/]*\\)/.*|\\1|\") &&\n-\ttest \"$d\" = \"$(test-tool path-utils real_path \"$d\")\" &&\n-\ttest \"$d/$nopath\" = \"$(test-tool path-utils real_path \"$d/$nopath\")\"\n+\ttest_cmp_cmd \"$d\" test-tool path-utils real_path \"$d\" &&\n+\ttest_cmp_cmd \"$d/$nopath\" test-tool path-utils real_path \"$d/$nopath\"\n '\n \n test_expect_success POSIX 'real path removes extra leading slashes' '\n \tnopath=\"hopefully-absent-path\" &&\n-\ttest \"/\" = \"$(test-tool path-utils real_path \"///\")\" &&\n-\ttest \"/$nopath\" = \"$(test-tool path-utils real_path \"///$nopath\")\" &&\n+\ttest_cmp_cmd \"/\" test-tool path-utils real_path \"///\" &&\n+\ttest_cmp_cmd \"/$nopath\" test-tool path-utils real_path \"///$nopath\" &&\n \t# Find an existing top-level directory for the remaining tests:\n \td=$(pwd -P | sed -e \"s|^\\([^/]*/[^/]*\\)/.*|\\1|\") &&\n-\ttest \"$d\" = \"$(test-tool path-utils real_path \"//$d\")\" &&\n-\ttest \"$d/$nopath\" = \"$(test-tool path-utils real_path \"//$d/$nopath\")\"\n+\ttest_cmp_cmd \"$d\" test-tool path-utils real_path \"//$d\" &&\n+\ttest_cmp_cmd \"$d/$nopath\" test-tool path-utils real_path \"//$d/$nopath\"\n '\n \n test_expect_success 'real path removes other extra slashes' '\n \tnopath=\"hopefully-absent-path\" &&\n \t# Find an existing top-level directory for the remaining tests:\n \td=$(pwd -P | sed -e \"s|^\\([^/]*/[^/]*\\)/.*|\\1|\") &&\n-\ttest \"$d\" = \"$(test-tool path-utils real_path \"$d///\")\" &&\n-\ttest \"$d/$nopath\" = \"$(test-tool path-utils real_path \"$d///$nopath\")\"\n+\ttest_cmp_cmd \"$d\" test-tool path-utils real_path \"$d///\" &&\n+\ttest_cmp_cmd \"$d/$nopath\" test-tool path-utils real_path \"$d///$nopath\"\n '\n \n test_expect_success SYMLINKS 'real path works on symlinks' '\n@@ -227,19 +232,19 @@ test_expect_success SYMLINKS 'real path works on symlinks' '\n \tmkdir third &&\n \tdir=\"$(cd .git && pwd -P)\" &&\n \tdir2=third/../second/other/.git &&\n-\ttest \"$dir\" = \"$(test-tool path-utils real_path $dir2)\" &&\n+\ttest_cmp_cmd \"$dir\" test-tool path-utils real_path $dir2 &&\n \tfile=\"$dir\"/index &&\n-\ttest \"$file\" = \"$(test-tool path-utils real_path $dir2/index)\" &&\n+\ttest_cmp_cmd \"$file\" test-tool path-utils real_path $dir2/index &&\n \tbasename=blub &&\n-\ttest \"$dir/$basename\" = \"$(cd .git && test-tool path-utils real_path \"$basename\")\" &&\n+\ttest_cmp_cmd \"$dir/$basename\" test-tool -C .git path-utils real_path \"$basename\" &&\n \tln -s ../first/file .git/syml &&\n \tsym=\"$(cd first && pwd -P)\"/file &&\n-\ttest \"$sym\" = \"$(test-tool path-utils real_path \"$dir2/syml\")\"\n+\ttest_cmp_cmd \"$sym\" test-tool path-utils real_path \"$dir2/syml\"\n '\n \n test_expect_success SYMLINKS 'prefix_path works with absolute paths to work tree symlinks' '\n \tln -s target symlink &&\n-\ttest \"$(test-tool path-utils prefix_path prefix \"$(pwd)/symlink\")\" = \"symlink\"\n+\ttest_cmp_cmd \"symlink\" test-tool path-utils prefix_path prefix \"$(pwd)/symlink\"\n '\n \n test_expect_success 'prefix_path works with only absolute path to work tree' '\n@@ -255,7 +260,7 @@ test_expect_success 'prefix_path rejects absolute path to dir with same beginnin\n test_expect_success SYMLINKS 'prefix_path works with absolute path to a symlink to work tree having  same beginning as work tree' '\n \tgit init repo &&\n \tln -s repo repolink &&\n-\ttest \"a\" = \"$(cd repo && test-tool path-utils prefix_path prefix \"$(pwd)/../repolink/a\")\"\n+\ttest_cmp_cmd \"a\" test-tool -C repo path-utils prefix_path prefix \"$(cd repo && pwd)/../repolink/a\"\n '\n \n relative_path /foo/a/b/c/\t/foo/a/b/\tc/\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex 6da7273f1d5..63e46442eb6 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -1366,6 +1366,24 @@ test_cmp_rev () {\n \tfi\n }\n \n+# test_cmp_cmd is a convenience helper for doing the more verbose:\n+#\n+#\techo something >expect &&\n+#\t<some-command-and-args> >actual &&\n+#\ttest_cmp expect actual\n+#\n+# As:\n+#\n+#\ttest_cmp_cmd something <some-command-and-args>\n+test_cmp_cmd () {\n+\tlocal expect=\"$1\" &&\n+\tshift &&\n+\tprintf \"%s\\n\" \"$expect\" >expect &&\n+\t\"$@\" >actual 2>err &&\n+\ttest_must_be_empty err\n+\ttest_cmp expect actual\n+}\n+\n # Compare paths respecting core.ignoreCase\n test_cmp_fspath () {\n \tif test \"x$1\" = \"x$2\"\n-- \n2.37.1.1095.g64a1e8362fd\n\n"},{"id":"459581","messageId":"patch-5.6-563666f9426-20220721T064349Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-0.6-00000000000-20220721T064349Z-avarab@gmail.com","subject":"[PATCH 5/6] merge tests: don't ignore \"rev-parse\" exit code in helper","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-21T06:51:42Z","receivedAt":"2022-07-21T06:52:12Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the verify_mergeheads() helper the check the exit code of \"git\nrev-parse\". The \"$rest\" variable added in 274a5c06d52 (merge: record\ntag objects without peeling in MERGE_HEAD, 2011-11-07) wasn't being\nused.\n\nSuch a thing is needed to support the .git/MERGE_HEAD format in\ngeneral, but in this case we have no such addition to the line. So\nlet's compare with \"test_cmp\" instead, we can always add back this\n\"$rest\" parsing if it's needed in the future.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t7600-merge.sh | 9 ++++-----\n 1 file changed, 4 insertions(+), 5 deletions(-)\n\ndiff --git a/t/t7600-merge.sh b/t/t7600-merge.sh\nindex f0f6fda150b..3682d6f9d4e 100755\n--- a/t/t7600-merge.sh\n+++ b/t/t7600-merge.sh\n@@ -102,12 +102,11 @@ verify_parents () {\n }\n \n verify_mergeheads () {\n-\ttest_write_lines \"$@\" >mergehead.expected &&\n-\twhile read sha1 rest\n+\tfor rev in \"$@\"\n \tdo\n-\t\tgit rev-parse $sha1\n-\tdone <.git/MERGE_HEAD >mergehead.actual &&\n-\ttest_cmp mergehead.expected mergehead.actual\n+\t\tgit rev-parse $rev || return 1\n+\tdone >mergehead.expected &&\n+\ttest_cmp mergehead.expected .git/MERGE_HEAD\n }\n \n verify_no_mergehead () {\n-- \n2.37.1.1095.g64a1e8362fd\n\n"},{"id":"459582","messageId":"patch-6.6-259b4618fcb-20220721T064349Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-0.6-00000000000-20220721T064349Z-avarab@gmail.com","subject":"[PATCH 6/6] log tests: don't use \"exit 1\" outside a sub-shell","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-21T06:51:43Z","receivedAt":"2022-07-21T06:52:13Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change an \"exit 1\" added in ac52d9410e5 (t4205: cover `git log\n--reflog -z` blindspot, 2019-11-19) to use \"return 1\" instead, which\ncuriously was done in an adjacent test case added in the same commit.\n\nUsing \"exit 1\" outside a sub-shell will cause the test framework\nitself to exit on failure, which isn't what we want to do here.\n\nThis issue was spotted with the in-flight\n\"GIT_TEST_PASSING_SANITIZE_LEAK=check\" test mode[1]. This \"git show\"\ninvocation currently leaks memory, and we'd thus \"exit 1\". This change\nwas initially part of that topic[2] to demonstrate the correctness of\nthe \"check\" implementation.\n\n1. https://lore.kernel.org/git/patch-07.10-0961df2ab6c-20220719T205710Z-avarab@gmail.com/\n2. https://lore.kernel.org/git/patch-10.10-9cedf0cb0e2-20220719T205710Z-avarab@gmail.com/\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t4205-log-pretty-formats.sh | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh\nindex e448ef2928a..0404491d6ee 100755\n--- a/t/t4205-log-pretty-formats.sh\n+++ b/t/t4205-log-pretty-formats.sh\n@@ -156,7 +156,7 @@ test_expect_success 'NUL termination with --reflog --pretty=oneline' '\n \tfor r in $revs\n \tdo\n \t\tgit show -s --pretty=oneline \"$r\" >raw &&\n-\t\tcat raw | lf_to_nul || exit 1\n+\t\tcat raw | lf_to_nul || return 1\n \tdone >expect &&\n \t# the trailing NUL is already produced so we do not need to\n \t# output another one\n-- \n2.37.1.1095.g64a1e8362fd\n\n"},{"id":"468372","messageId":"cover-v2-0.8-00000000000-20221202T000227Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-0.6-00000000000-20220721T064349Z-avarab@gmail.com","subject":"[PATCH v2 0/8] tests: fix ignored & hidden exit codes","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-02T00:06:26Z","receivedAt":"2022-12-02T00:07:24Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"A small set of fixes to correct git on the LHS of a pipe, and in $()\nwithin a \"test\" expression, or where its exit code is otherwise\nhidden.\n\nThe 1/8 here was originally submitted as part of another series, and\nwhat prompted this re-submission at this time is that the exact same\nfix was independently discovered in [2].\n\nThis is still just the tip of the iceberg in terms of these issues in\nthe test suite, but hopefully this will get some attention this time\naround.\n\n1. https://lore.kernel.org/git/xmqqmtd33e1h.fsf@gitster.g/\n2. https://lore.kernel.org/git/c5b4d091-23c1-5a75-a255-99ec83973d8d@web.de/\n\nÆvar Arnfjörð Bjarmason (8):\n  log tests: don't use \"exit 1\" outside a sub-shell\n  auto-crlf tests: check \"git checkout\" exit code\n  diff tests: fix ignored exit codes in t4023\n  test-lib-functions: add and use test_cmp_cmd\n  t/lib-patch-mode.sh: fix ignored \"git\" exit codes\n  merge tests: don't ignore \"rev-parse\" exit code in helper\n  tests: use \"test_cmp_cmd\" instead of \"test\" in sub-shells\n  tests: use \"test_cmp_cmd\" in misc tests\n\n t/lib-httpd.sh                     |  3 +-\n t/lib-patch-mode.sh                |  9 +++--\n t/lib-submodule-update.sh          | 22 +++++-------\n t/t0001-init.sh                    |  4 +--\n t/t0002-gitfile.sh                 |  2 +-\n t/t0027-auto-crlf.sh               | 14 +++++---\n t/t0060-path-utils.sh              | 57 ++++++++++++++++--------------\n t/t0100-previous.sh                |  4 +--\n t/t1401-symbolic-ref.sh            |  3 +-\n t/t1504-ceiling-dirs.sh            |  6 ++--\n t/t2005-checkout-index-symlinks.sh |  2 +-\n t/t3200-branch.sh                  |  9 ++---\n t/t3701-add-interactive.sh         |  9 +++--\n t/t4023-diff-rename-typechange.sh  | 12 +++----\n t/t4205-log-pretty-formats.sh      |  2 +-\n t/t5522-pull-symlink.sh            |  2 +-\n t/t5605-clone-local.sh             |  9 +++--\n t/t7402-submodule-rebase.sh        | 10 +++---\n t/t7504-commit-msg-hook.sh         |  2 +-\n t/t7516-commit-races.sh            |  3 +-\n t/t7600-merge.sh                   |  9 +++--\n t/t7810-grep.sh                    |  2 +-\n t/test-lib-functions.sh            | 18 ++++++++++\n 23 files changed, 119 insertions(+), 94 deletions(-)\n\nRange-diff against v1:\n6:  259b4618fcb = 1:  7c9f8d2830f log tests: don't use \"exit 1\" outside a sub-shell\n3:  cfc1abbf7e3 = 2:  345a667d5bb auto-crlf tests: check \"git checkout\" exit code\n1:  f8a382841d5 = 3:  c5feef1c808 diff tests: fix ignored exit codes in t4023\n4:  df1b674b8a7 ! 4:  c36060934a6 test-lib-functions: add and use test_cmp_cmd\n    @@ Commit message\n                 test_cmp_cmd --stdin <some-cmd> <expect\n                 test_cmp_cmd --ignore-stderr \"output\" <some-cmd>\n     \n    -    By using this in t0060-path.sh we'll catch cases where \"git\" or\n    -    \"test-tool\" errors (such as segfaults or abort()) were previously\n    -    hidden, and we'd either pass the test, or fail in some subsequent\n    -    assertion.\n    +    By using this in we'll catch cases where \"git\" or \"test-tool\"\n    +    errors (such as segfaults or abort()) were previously hidden, and we'd\n    +    either pass the test, or fail in some subsequent assertion.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n    + ## t/lib-submodule-update.sh ##\n    +@@ t/lib-submodule-update.sh: test_git_directory_exists () {\n    + \tif test -f sub1/.git\n    + \tthen\n    + \t\t# does core.worktree point at the right place?\n    +-\t\ttest \"$(git -C .git/modules/$1 config core.worktree)\" = \"../../../$1\"\n    ++\t\ttest_cmp_cmd \"../../../$1\" git -C \".git/modules/$1\" config core.worktree\n    + \tfi\n    + }\n    + \n    +\n    + ## t/t0001-init.sh ##\n    +@@ t/t0001-init.sh: test_expect_success 'invalid default branch name' '\n    + test_expect_success 'branch -m with the initial branch' '\n    + \tgit init rename-initial &&\n    + \tgit -C rename-initial branch -m renamed &&\n    +-\ttest renamed = $(git -C rename-initial symbolic-ref --short HEAD) &&\n    ++\ttest_cmp_cmd renamed git -C rename-initial symbolic-ref --short HEAD &&\n    + \tgit -C rename-initial branch -m renamed again &&\n    +-\ttest again = $(git -C rename-initial symbolic-ref --short HEAD)\n    ++\ttest_cmp_cmd again git -C rename-initial symbolic-ref --short HEAD\n    + '\n    + \n    + test_done\n    +\n    + ## t/t0002-gitfile.sh ##\n    +@@ t/t0002-gitfile.sh: test_expect_success 'bad setup: invalid .git file path' '\n    + \n    + test_expect_success 'final setup + check rev-parse --git-dir' '\n    + \techo \"gitdir: $REAL\" >.git &&\n    +-\ttest \"$REAL\" = \"$(git rev-parse --git-dir)\"\n    ++\ttest_cmp_cmd \"$REAL\" git rev-parse --git-dir\n    + '\n    + \n    + test_expect_success 'check hash-object' '\n    +\n      ## t/t0060-path-utils.sh ##\n     @@ t/t0060-path-utils.sh: TEST_PASSES_SANITIZE_LEAK=true\n      \n    @@ t/t0060-path-utils.sh: TEST_PASSES_SANITIZE_LEAK=true\n     -\ttest_expect_success $3 \"normalize path: $1 => $2\" \\\n     -\t\"test \\\"\\$(test-tool path-utils normalize_path_copy '$1')\\\" = '$expected'\"\n     +\ttest_expect_success $3 \"normalize path: $1 => $2\" \"\n    -+\t\techo '$expected' >expect &&\n    -+\t\ttest-tool path-utils normalize_path_copy '$1' >actual &&\n    -+\t\ttest_cmp expect actual\n    ++\t\ttest_cmp_cmd '$expected' test-tool path-utils normalize_path_copy '$1'\n     +\t\"\n      }\n      \n      relative_path() {\n    + \texpected=$(test-tool path-utils print_path \"$3\")\n    +-\ttest_expect_success $4 \"relative path: $1 $2 => $3\" \\\n    +-\t\"test \\\"\\$(test-tool path-utils relative_path '$1' '$2')\\\" = '$expected'\"\n    ++\ttest_expect_success $4 \"relative path: $1 $2 => $3\" \"\n    ++\t\ttest_cmp_cmd '$expected' test-tool path-utils relative_path '$1' '$2'\n    ++\t\"\n    + }\n    + \n    + test_submodule_relative_url() {\n    + \ttest_expect_success \"test_submodule_relative_url: $1 $2 $3 => $4\" \"\n    +-\t\tactual=\\$(test-tool submodule resolve-relative-url '$1' '$2' '$3') &&\n    +-\t\ttest \\\"\\$actual\\\" = '$4'\n    ++\t\ttest_cmp_cmd '$4' test-tool submodule resolve-relative-url '$1' '$2' '$3'\n    + \t\"\n    + }\n    + \n    +@@ t/t0060-path-utils.sh: ancestor() {\n    + \t\texpected=$(($expected-$rootslash+$rootoff))\n    + \t\t;;\n    + \tesac\n    +-\ttest_expect_success $4 \"longest ancestor: $1 $2 => $expected\" \\\n    +-\t\"actual=\\$(test-tool path-utils longest_ancestor_length '$1' '$2') &&\n    +-\t test \\\"\\$actual\\\" = '$expected'\"\n    ++\ttest_expect_success $4 \"longest ancestor: $1 $2 => $expected\" \"\n    ++\t\ttest_cmp_cmd '$expected' test-tool path-utils longest_ancestor_length '$1' '$2'\n    ++\t\"\n    + }\n    + \n    + # Some absolute path tests should be skipped on Windows due to path mangling\n     @@ t/t0060-path-utils.sh: ancestor D:/Users/me C:/ -1 MINGW\n      ancestor //server/share/my-directory //server/share/ 14 MINGW\n      \n    @@ t/t0060-path-utils.sh: test_expect_success 'prefix_path rejects absolute path to\n      \n      relative_path /foo/a/b/c/\t/foo/a/b/\tc/\n     \n    + ## t/t0100-previous.sh ##\n    +@@ t/t0100-previous.sh: test_expect_success 'branch -d @{-1}' '\n    + \ttest_commit A &&\n    + \tgit checkout -b junk &&\n    + \tgit checkout - &&\n    +-\ttest \"$(git symbolic-ref HEAD)\" = refs/heads/main &&\n    ++\ttest_cmp_cmd refs/heads/main git symbolic-ref HEAD &&\n    + \tgit branch -d @{-1} &&\n    + \ttest_must_fail git rev-parse --verify refs/heads/junk\n    + '\n    +@@ t/t0100-previous.sh: test_expect_success 'branch -d @{-12} when there is not enough switches yet' '\n    + \tgit reflog expire --expire=now &&\n    + \tgit checkout -b junk2 &&\n    + \tgit checkout - &&\n    +-\ttest \"$(git symbolic-ref HEAD)\" = refs/heads/main &&\n    ++\ttest_cmp_cmd refs/heads/main git symbolic-ref HEAD &&\n    + \ttest_must_fail git branch -d @{-12} &&\n    + \tgit rev-parse --verify refs/heads/main\n    + '\n    +\n    + ## t/t1504-ceiling-dirs.sh ##\n    +@@ t/t1504-ceiling-dirs.sh: TEST_PASSES_SANITIZE_LEAK=true\n    + . ./test-lib.sh\n    + \n    + test_prefix() {\n    +-\ttest_expect_success \"$1\" \\\n    +-\t\"test '$2' = \\\"\\$(git rev-parse --show-prefix)\\\"\"\n    ++\tlocal expect=\"$2\" &&\n    ++\ttest_expect_success \"$1: git rev-parse --show-prefix is '$2'\" '\n    ++\t\ttest_cmp_cmd \"$expect\" git rev-parse --show-prefix\n    ++\t'\n    + }\n    + \n    + test_fail() {\n    +\n      ## t/test-lib-functions.sh ##\n     @@ t/test-lib-functions.sh: test_cmp_rev () {\n      \tfi\n2:  85c6ab40e91 ! 5:  f826a336c3d t/lib-patch-mode.sh: fix ignored \"git\" exit codes\n    @@ Commit message\n         t/lib-patch-mode.sh: fix ignored \"git\" exit codes\n     \n         Fix code added in b319ef70a94 (Add a small patch-mode testing library,\n    -    2009-08-13) to use &&-chaining and test_cmp instead of interpolating\n    -    \"git\" commands in a \"test\" statement.\n    +    2009-08-13) to use &&-chaining and the newly added \"test_cmp_cmd\"\n    +    instead of interpolating \"git\" commands in a \"test\" statement.\n     \n         This fixes cases where we'd have e.g. missed memory leaks under\n         SANITIZE=leak, this code doesn't leak now as far as I can tell, but I\n    @@ t/lib-patch-mode.sh: set_and_save_state () {\n     +\tcat \"$1\" >actual &&\n     +\ttest_cmp expect actual &&\n     +\n    -+\techo \"$3\" >expect\n    -+\tgit show :\"$1\" >actual &&\n    -+\ttest_cmp expect actual\n    ++\ttest_cmp_cmd \"$3\" git show :\"$1\"\n      }\n      \n      # verify_saved_state <path>\n    @@ t/lib-patch-mode.sh: save_head () {\n      \n      verify_saved_head () {\n     -\ttest \"$(cat _head)\" = \"$(git rev-parse HEAD)\"\n    -+\tcat _head >expect &&\n    -+\tgit rev-parse HEAD >actual &&\n    -+\ttest_cmp expect actual\n    ++\ttest_cmp_cmd \"$(cat _head)\" git rev-parse HEAD\n      }\n5:  563666f9426 = 6:  5715ff7f0f7 merge tests: don't ignore \"rev-parse\" exit code in helper\n-:  ----------- > 7:  d090478aa84 tests: use \"test_cmp_cmd\" instead of \"test\" in sub-shells\n-:  ----------- > 8:  979a7f003f8 tests: use \"test_cmp_cmd\" in misc tests\n-- \n2.39.0.rc1.980.g92d3d4579ad\n\n"},{"id":"468373","messageId":"patch-v2-1.8-7c9f8d2830f-20221202T000227Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v2-0.8-00000000000-20221202T000227Z-avarab@gmail.com","subject":"[PATCH v2 1/8] log tests: don't use \"exit 1\" outside a sub-shell","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-02T00:06:27Z","receivedAt":"2022-12-02T00:07:26Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change an \"exit 1\" added in ac52d9410e5 (t4205: cover `git log\n--reflog -z` blindspot, 2019-11-19) to use \"return 1\" instead, which\ncuriously was done in an adjacent test case added in the same commit.\n\nUsing \"exit 1\" outside a sub-shell will cause the test framework\nitself to exit on failure, which isn't what we want to do here.\n\nThis issue was spotted with the in-flight\n\"GIT_TEST_PASSING_SANITIZE_LEAK=check\" test mode[1]. This \"git show\"\ninvocation currently leaks memory, and we'd thus \"exit 1\". This change\nwas initially part of that topic[2] to demonstrate the correctness of\nthe \"check\" implementation.\n\n1. https://lore.kernel.org/git/patch-07.10-0961df2ab6c-20220719T205710Z-avarab@gmail.com/\n2. https://lore.kernel.org/git/patch-10.10-9cedf0cb0e2-20220719T205710Z-avarab@gmail.com/\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t4205-log-pretty-formats.sh | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh\nindex e448ef2928a..0404491d6ee 100755\n--- a/t/t4205-log-pretty-formats.sh\n+++ b/t/t4205-log-pretty-formats.sh\n@@ -156,7 +156,7 @@ test_expect_success 'NUL termination with --reflog --pretty=oneline' '\n \tfor r in $revs\n \tdo\n \t\tgit show -s --pretty=oneline \"$r\" >raw &&\n-\t\tcat raw | lf_to_nul || exit 1\n+\t\tcat raw | lf_to_nul || return 1\n \tdone >expect &&\n \t# the trailing NUL is already produced so we do not need to\n \t# output another one\n-- \n2.39.0.rc1.980.g92d3d4579ad\n\n"},{"id":"468375","messageId":"patch-v2-2.8-345a667d5bb-20221202T000227Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v2-0.8-00000000000-20221202T000227Z-avarab@gmail.com","subject":"[PATCH v2 2/8] auto-crlf tests: check \"git checkout\" exit code","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-02T00:06:28Z","receivedAt":"2022-12-02T00:07:29Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Don't hide the exit code from the \"git checkout\" we run to checkout\nour attributes file.\n\nThis fixes cases where we'd have e.g. missed memory leaks under\nSANITIZE=leak, this code doesn't leak (the relevant \"git checkout\"\nleak has been fixed), but in a past version of git we'd continue past\nthis failure under SANITIZE=leak when these invocations had errored\nout, even under \"--immediate\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t0027-auto-crlf.sh | 14 ++++++++++----\n 1 file changed, 10 insertions(+), 4 deletions(-)\n\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex a94ac1eae37..574344a99db 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -294,11 +294,17 @@ checkout_files () {\n \tpfx=eol_${ceol}_crlf_${crlf}_attr_${attr}_ &&\n \tfor f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul\n \tdo\n-\t\trm crlf_false_attr__$f.txt &&\n-\t\tif test -z \"$ceol\"; then\n-\t\t\tgit checkout -- crlf_false_attr__$f.txt\n+\t\tif test -z \"$ceol\"\n+\t\tthen\n+\t\t\ttest_expect_success \"setup $f checkout\" '\n+\t\t\t\trm crlf_false_attr__$f.txt &&\n+\t\t\t\tgit checkout -- crlf_false_attr__$f.txt\n+\t\t\t'\n \t\telse\n-\t\t\tgit -c core.eol=$ceol checkout -- crlf_false_attr__$f.txt\n+\t\t\ttest_expect_success \"setup $f checkout with core.eol=$ceol\" '\n+\t\t\t\trm crlf_false_attr__$f.txt &&\n+\t\t\t\tgit -c core.eol=$ceol checkout -- crlf_false_attr__$f.txt\n+\t\t\t'\n \t\tfi\n \tdone\n \n-- \n2.39.0.rc1.980.g92d3d4579ad\n\n"},{"id":"468374","messageId":"patch-v2-3.8-c5feef1c808-20221202T000227Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v2-0.8-00000000000-20221202T000227Z-avarab@gmail.com","subject":"[PATCH v2 3/8] diff tests: fix ignored exit codes in t4023","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-02T00:06:29Z","receivedAt":"2022-12-02T00:07:30Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change a \"git diff-tree\" command to be &&-chained so that we won't\nignore its exit code, see the ea05fd5fbf7 (Merge branch\n'ab/keep-git-exit-codes-in-tests', 2022-03-16) topic for prior art.\n\nThis fixes code added in b45563a229f (rename: Break filepairs with\ndifferent types., 2007-11-30). Due to hiding the exit code we hid a\nmemory leak under SANITIZE=leak.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t4023-diff-rename-typechange.sh | 12 ++++++------\n 1 file changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/t/t4023-diff-rename-typechange.sh b/t/t4023-diff-rename-typechange.sh\nindex 7cb99092938..25c31b0cb1b 100755\n--- a/t/t4023-diff-rename-typechange.sh\n+++ b/t/t4023-diff-rename-typechange.sh\n@@ -52,8 +52,8 @@ test_expect_success setup '\n '\n \n test_expect_success 'cross renames to be detected for regular files' '\n-\n-\tgit diff-tree five six -r --name-status -B -M | sort >actual &&\n+\tgit diff-tree five six -r --name-status -B -M >out &&\n+\tsort <out >actual &&\n \t{\n \t\techo \"R100\tfoo\tbar\" &&\n \t\techo \"R100\tbar\tfoo\"\n@@ -63,8 +63,8 @@ test_expect_success 'cross renames to be detected for regular files' '\n '\n \n test_expect_success 'cross renames to be detected for typechange' '\n-\n-\tgit diff-tree one two -r --name-status -B -M | sort >actual &&\n+\tgit diff-tree one two -r --name-status -B -M >out &&\n+\tsort <out >actual &&\n \t{\n \t\techo \"R100\tfoo\tbar\" &&\n \t\techo \"R100\tbar\tfoo\"\n@@ -74,8 +74,8 @@ test_expect_success 'cross renames to be detected for typechange' '\n '\n \n test_expect_success 'moves and renames' '\n-\n-\tgit diff-tree three four -r --name-status -B -M | sort >actual &&\n+\tgit diff-tree three four -r --name-status -B -M >out &&\n+\tsort <out >actual &&\n \t{\n \t\t# see -B -M (#6) in t4008\n \t\techo \"C100\tfoo\tbar\" &&\n-- \n2.39.0.rc1.980.g92d3d4579ad\n\n"},{"id":"468376","messageId":"patch-v2-5.8-f826a336c3d-20221202T000227Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v2-0.8-00000000000-20221202T000227Z-avarab@gmail.com","subject":"[PATCH v2 5/8] t/lib-patch-mode.sh: fix ignored \"git\" exit codes","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-02T00:06:31Z","receivedAt":"2022-12-02T00:07:38Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Fix code added in b319ef70a94 (Add a small patch-mode testing library,\n2009-08-13) to use &&-chaining and the newly added \"test_cmp_cmd\"\ninstead of interpolating \"git\" commands in a \"test\" statement.\n\nThis fixes cases where we'd have e.g. missed memory leaks under\nSANITIZE=leak, this code doesn't leak now as far as I can tell, but I\ndiscovered it while looking at leaks in related code.\n\nThe \"cat _head >expect\" here is redundant, we could simply give\n\"_head\" to \"test_cmp\", but let's be consistent in using the \"expect\"\nand \"actual\" names for clarity.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/lib-patch-mode.sh | 9 ++++++---\n 1 file changed, 6 insertions(+), 3 deletions(-)\n\ndiff --git a/t/lib-patch-mode.sh b/t/lib-patch-mode.sh\nindex cfd76bf987b..ae51f33a010 100644\n--- a/t/lib-patch-mode.sh\n+++ b/t/lib-patch-mode.sh\n@@ -29,8 +29,11 @@ set_and_save_state () {\n \n # verify_state <path> <expected-worktree-content> <expected-index-content>\n verify_state () {\n-\ttest \"$(cat \"$1\")\" = \"$2\" &&\n-\ttest \"$(git show :\"$1\")\" = \"$3\"\n+\techo \"$2\" >expect &&\n+\tcat \"$1\" >actual &&\n+\ttest_cmp expect actual &&\n+\n+\ttest_cmp_cmd \"$3\" git show :\"$1\"\n }\n \n # verify_saved_state <path>\n@@ -46,5 +49,5 @@ save_head () {\n }\n \n verify_saved_head () {\n-\ttest \"$(cat _head)\" = \"$(git rev-parse HEAD)\"\n+\ttest_cmp_cmd \"$(cat _head)\" git rev-parse HEAD\n }\n-- \n2.39.0.rc1.980.g92d3d4579ad\n\n"},{"id":"468377","messageId":"patch-v2-4.8-c36060934a6-20221202T000227Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v2-0.8-00000000000-20221202T000227Z-avarab@gmail.com","subject":"[PATCH v2 4/8] test-lib-functions: add and use test_cmp_cmd","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-02T00:06:30Z","receivedAt":"2022-12-02T00:07:40Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add a \"test_cmp_cmd\" helper for the common pattern discussed in the\ndocumentation being added here to \"t/test-lib-functions.sh\".\n\nThis implementation leaves the door open for extending this helper\npast its obvious limitations, such as:\n\n\ttest_cmp_cmd \"some\" \"lines\" -- <some-cmd>\n\ttest_cmp_cmd --stdin <some-cmd> <expect\n\ttest_cmp_cmd --ignore-stderr \"output\" <some-cmd>\n\nBy using this in we'll catch cases where \"git\" or \"test-tool\"\nerrors (such as segfaults or abort()) were previously hidden, and we'd\neither pass the test, or fail in some subsequent assertion.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/lib-submodule-update.sh |  2 +-\n t/t0001-init.sh           |  4 +--\n t/t0002-gitfile.sh        |  2 +-\n t/t0060-path-utils.sh     | 57 ++++++++++++++++++++-------------------\n t/t0100-previous.sh       |  4 +--\n t/t1504-ceiling-dirs.sh   |  6 +++--\n t/test-lib-functions.sh   | 18 +++++++++++++\n 7 files changed, 58 insertions(+), 35 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 2d31fcfda1f..d5d98714b4e 100644\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -189,7 +189,7 @@ test_git_directory_exists () {\n \tif test -f sub1/.git\n \tthen\n \t\t# does core.worktree point at the right place?\n-\t\ttest \"$(git -C .git/modules/$1 config core.worktree)\" = \"../../../$1\"\n+\t\ttest_cmp_cmd \"../../../$1\" git -C \".git/modules/$1\" config core.worktree\n \tfi\n }\n \ndiff --git a/t/t0001-init.sh b/t/t0001-init.sh\nindex d479303efa0..a3b902bcd8f 100755\n--- a/t/t0001-init.sh\n+++ b/t/t0001-init.sh\n@@ -598,9 +598,9 @@ test_expect_success 'invalid default branch name' '\n test_expect_success 'branch -m with the initial branch' '\n \tgit init rename-initial &&\n \tgit -C rename-initial branch -m renamed &&\n-\ttest renamed = $(git -C rename-initial symbolic-ref --short HEAD) &&\n+\ttest_cmp_cmd renamed git -C rename-initial symbolic-ref --short HEAD &&\n \tgit -C rename-initial branch -m renamed again &&\n-\ttest again = $(git -C rename-initial symbolic-ref --short HEAD)\n+\ttest_cmp_cmd again git -C rename-initial symbolic-ref --short HEAD\n '\n \n test_done\ndiff --git a/t/t0002-gitfile.sh b/t/t0002-gitfile.sh\nindex 26eaca095a2..aca847512c4 100755\n--- a/t/t0002-gitfile.sh\n+++ b/t/t0002-gitfile.sh\n@@ -33,7 +33,7 @@ test_expect_success 'bad setup: invalid .git file path' '\n \n test_expect_success 'final setup + check rev-parse --git-dir' '\n \techo \"gitdir: $REAL\" >.git &&\n-\ttest \"$REAL\" = \"$(git rev-parse --git-dir)\"\n+\ttest_cmp_cmd \"$REAL\" git rev-parse --git-dir\n '\n \n test_expect_success 'check hash-object' '\ndiff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh\nindex 68e29c904a6..c90d2e4d2b1 100755\n--- a/t/t0060-path-utils.sh\n+++ b/t/t0060-path-utils.sh\n@@ -10,20 +10,21 @@ TEST_PASSES_SANITIZE_LEAK=true\n \n norm_path() {\n \texpected=$(test-tool path-utils print_path \"$2\")\n-\ttest_expect_success $3 \"normalize path: $1 => $2\" \\\n-\t\"test \\\"\\$(test-tool path-utils normalize_path_copy '$1')\\\" = '$expected'\"\n+\ttest_expect_success $3 \"normalize path: $1 => $2\" \"\n+\t\ttest_cmp_cmd '$expected' test-tool path-utils normalize_path_copy '$1'\n+\t\"\n }\n \n relative_path() {\n \texpected=$(test-tool path-utils print_path \"$3\")\n-\ttest_expect_success $4 \"relative path: $1 $2 => $3\" \\\n-\t\"test \\\"\\$(test-tool path-utils relative_path '$1' '$2')\\\" = '$expected'\"\n+\ttest_expect_success $4 \"relative path: $1 $2 => $3\" \"\n+\t\ttest_cmp_cmd '$expected' test-tool path-utils relative_path '$1' '$2'\n+\t\"\n }\n \n test_submodule_relative_url() {\n \ttest_expect_success \"test_submodule_relative_url: $1 $2 $3 => $4\" \"\n-\t\tactual=\\$(test-tool submodule resolve-relative-url '$1' '$2' '$3') &&\n-\t\ttest \\\"\\$actual\\\" = '$4'\n+\t\ttest_cmp_cmd '$4' test-tool submodule resolve-relative-url '$1' '$2' '$3'\n \t\"\n }\n \n@@ -64,9 +65,9 @@ ancestor() {\n \t\texpected=$(($expected-$rootslash+$rootoff))\n \t\t;;\n \tesac\n-\ttest_expect_success $4 \"longest ancestor: $1 $2 => $expected\" \\\n-\t\"actual=\\$(test-tool path-utils longest_ancestor_length '$1' '$2') &&\n-\t test \\\"\\$actual\\\" = '$expected'\"\n+\ttest_expect_success $4 \"longest ancestor: $1 $2 => $expected\" \"\n+\t\ttest_cmp_cmd '$expected' test-tool path-utils longest_ancestor_length '$1' '$2'\n+\t\"\n }\n \n # Some absolute path tests should be skipped on Windows due to path mangling\n@@ -166,8 +167,10 @@ ancestor D:/Users/me C:/ -1 MINGW\n ancestor //server/share/my-directory //server/share/ 14 MINGW\n \n test_expect_success 'strip_path_suffix' '\n-\ttest c:/msysgit = $(test-tool path-utils strip_path_suffix \\\n-\t\tc:/msysgit/libexec//git-core libexec/git-core)\n+\techo c:/msysgit >expect &&\n+\ttest-tool path-utils strip_path_suffix \\\n+\t\tc:/msysgit/libexec//git-core libexec/git-core >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'absolute path rejects the empty string' '\n@@ -189,34 +192,34 @@ test_expect_success 'real path rejects the empty string' '\n \n test_expect_success POSIX 'real path works on absolute paths 1' '\n \tnopath=\"hopefully-absent-path\" &&\n-\ttest \"/\" = \"$(test-tool path-utils real_path \"/\")\" &&\n-\ttest \"/$nopath\" = \"$(test-tool path-utils real_path \"/$nopath\")\"\n+\ttest_cmp_cmd / test-tool path-utils real_path \"/\" &&\n+\ttest_cmp_cmd \"/$nopath\" test-tool path-utils real_path \"/$nopath\"\n '\n \n test_expect_success 'real path works on absolute paths 2' '\n \tnopath=\"hopefully-absent-path\" &&\n \t# Find an existing top-level directory for the remaining tests:\n \td=$(pwd -P | sed -e \"s|^\\([^/]*/[^/]*\\)/.*|\\1|\") &&\n-\ttest \"$d\" = \"$(test-tool path-utils real_path \"$d\")\" &&\n-\ttest \"$d/$nopath\" = \"$(test-tool path-utils real_path \"$d/$nopath\")\"\n+\ttest_cmp_cmd \"$d\" test-tool path-utils real_path \"$d\" &&\n+\ttest_cmp_cmd \"$d/$nopath\" test-tool path-utils real_path \"$d/$nopath\"\n '\n \n test_expect_success POSIX 'real path removes extra leading slashes' '\n \tnopath=\"hopefully-absent-path\" &&\n-\ttest \"/\" = \"$(test-tool path-utils real_path \"///\")\" &&\n-\ttest \"/$nopath\" = \"$(test-tool path-utils real_path \"///$nopath\")\" &&\n+\ttest_cmp_cmd \"/\" test-tool path-utils real_path \"///\" &&\n+\ttest_cmp_cmd \"/$nopath\" test-tool path-utils real_path \"///$nopath\" &&\n \t# Find an existing top-level directory for the remaining tests:\n \td=$(pwd -P | sed -e \"s|^\\([^/]*/[^/]*\\)/.*|\\1|\") &&\n-\ttest \"$d\" = \"$(test-tool path-utils real_path \"//$d\")\" &&\n-\ttest \"$d/$nopath\" = \"$(test-tool path-utils real_path \"//$d/$nopath\")\"\n+\ttest_cmp_cmd \"$d\" test-tool path-utils real_path \"//$d\" &&\n+\ttest_cmp_cmd \"$d/$nopath\" test-tool path-utils real_path \"//$d/$nopath\"\n '\n \n test_expect_success 'real path removes other extra slashes' '\n \tnopath=\"hopefully-absent-path\" &&\n \t# Find an existing top-level directory for the remaining tests:\n \td=$(pwd -P | sed -e \"s|^\\([^/]*/[^/]*\\)/.*|\\1|\") &&\n-\ttest \"$d\" = \"$(test-tool path-utils real_path \"$d///\")\" &&\n-\ttest \"$d/$nopath\" = \"$(test-tool path-utils real_path \"$d///$nopath\")\"\n+\ttest_cmp_cmd \"$d\" test-tool path-utils real_path \"$d///\" &&\n+\ttest_cmp_cmd \"$d/$nopath\" test-tool path-utils real_path \"$d///$nopath\"\n '\n \n test_expect_success SYMLINKS 'real path works on symlinks' '\n@@ -227,19 +230,19 @@ test_expect_success SYMLINKS 'real path works on symlinks' '\n \tmkdir third &&\n \tdir=\"$(cd .git && pwd -P)\" &&\n \tdir2=third/../second/other/.git &&\n-\ttest \"$dir\" = \"$(test-tool path-utils real_path $dir2)\" &&\n+\ttest_cmp_cmd \"$dir\" test-tool path-utils real_path $dir2 &&\n \tfile=\"$dir\"/index &&\n-\ttest \"$file\" = \"$(test-tool path-utils real_path $dir2/index)\" &&\n+\ttest_cmp_cmd \"$file\" test-tool path-utils real_path $dir2/index &&\n \tbasename=blub &&\n-\ttest \"$dir/$basename\" = \"$(cd .git && test-tool path-utils real_path \"$basename\")\" &&\n+\ttest_cmp_cmd \"$dir/$basename\" test-tool -C .git path-utils real_path \"$basename\" &&\n \tln -s ../first/file .git/syml &&\n \tsym=\"$(cd first && pwd -P)\"/file &&\n-\ttest \"$sym\" = \"$(test-tool path-utils real_path \"$dir2/syml\")\"\n+\ttest_cmp_cmd \"$sym\" test-tool path-utils real_path \"$dir2/syml\"\n '\n \n test_expect_success SYMLINKS 'prefix_path works with absolute paths to work tree symlinks' '\n \tln -s target symlink &&\n-\ttest \"$(test-tool path-utils prefix_path prefix \"$(pwd)/symlink\")\" = \"symlink\"\n+\ttest_cmp_cmd \"symlink\" test-tool path-utils prefix_path prefix \"$(pwd)/symlink\"\n '\n \n test_expect_success 'prefix_path works with only absolute path to work tree' '\n@@ -255,7 +258,7 @@ test_expect_success 'prefix_path rejects absolute path to dir with same beginnin\n test_expect_success SYMLINKS 'prefix_path works with absolute path to a symlink to work tree having  same beginning as work tree' '\n \tgit init repo &&\n \tln -s repo repolink &&\n-\ttest \"a\" = \"$(cd repo && test-tool path-utils prefix_path prefix \"$(pwd)/../repolink/a\")\"\n+\ttest_cmp_cmd \"a\" test-tool -C repo path-utils prefix_path prefix \"$(cd repo && pwd)/../repolink/a\"\n '\n \n relative_path /foo/a/b/c/\t/foo/a/b/\tc/\ndiff --git a/t/t0100-previous.sh b/t/t0100-previous.sh\nindex a16cc3d2983..e315283cccd 100755\n--- a/t/t0100-previous.sh\n+++ b/t/t0100-previous.sh\n@@ -12,7 +12,7 @@ test_expect_success 'branch -d @{-1}' '\n \ttest_commit A &&\n \tgit checkout -b junk &&\n \tgit checkout - &&\n-\ttest \"$(git symbolic-ref HEAD)\" = refs/heads/main &&\n+\ttest_cmp_cmd refs/heads/main git symbolic-ref HEAD &&\n \tgit branch -d @{-1} &&\n \ttest_must_fail git rev-parse --verify refs/heads/junk\n '\n@@ -21,7 +21,7 @@ test_expect_success 'branch -d @{-12} when there is not enough switches yet' '\n \tgit reflog expire --expire=now &&\n \tgit checkout -b junk2 &&\n \tgit checkout - &&\n-\ttest \"$(git symbolic-ref HEAD)\" = refs/heads/main &&\n+\ttest_cmp_cmd refs/heads/main git symbolic-ref HEAD &&\n \ttest_must_fail git branch -d @{-12} &&\n \tgit rev-parse --verify refs/heads/main\n '\ndiff --git a/t/t1504-ceiling-dirs.sh b/t/t1504-ceiling-dirs.sh\nindex 0fafcf9dde3..2c73869235d 100755\n--- a/t/t1504-ceiling-dirs.sh\n+++ b/t/t1504-ceiling-dirs.sh\n@@ -6,8 +6,10 @@ TEST_PASSES_SANITIZE_LEAK=true\n . ./test-lib.sh\n \n test_prefix() {\n-\ttest_expect_success \"$1\" \\\n-\t\"test '$2' = \\\"\\$(git rev-parse --show-prefix)\\\"\"\n+\tlocal expect=\"$2\" &&\n+\ttest_expect_success \"$1: git rev-parse --show-prefix is '$2'\" '\n+\t\ttest_cmp_cmd \"$expect\" git rev-parse --show-prefix\n+\t'\n }\n \n test_fail() {\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex 796093a7b32..0e8e0f808e3 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -1274,6 +1274,24 @@ test_cmp_rev () {\n \tfi\n }\n \n+# test_cmp_cmd is a convenience helper for doing the more verbose:\n+#\n+#\techo something >expect &&\n+#\t<some-command-and-args> >actual &&\n+#\ttest_cmp expect actual\n+#\n+# As:\n+#\n+#\ttest_cmp_cmd something <some-command-and-args>\n+test_cmp_cmd () {\n+\tlocal expect=\"$1\" &&\n+\tshift &&\n+\tprintf \"%s\\n\" \"$expect\" >expect &&\n+\t\"$@\" >actual 2>err &&\n+\ttest_must_be_empty err\n+\ttest_cmp expect actual\n+}\n+\n # Compare paths respecting core.ignoreCase\n test_cmp_fspath () {\n \tif test \"x$1\" = \"x$2\"\n-- \n2.39.0.rc1.980.g92d3d4579ad\n\n"},{"id":"468378","messageId":"patch-v2-6.8-5715ff7f0f7-20221202T000227Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v2-0.8-00000000000-20221202T000227Z-avarab@gmail.com","subject":"[PATCH v2 6/8] merge tests: don't ignore \"rev-parse\" exit code in helper","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-02T00:06:32Z","receivedAt":"2022-12-02T00:07:46Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the verify_mergeheads() helper the check the exit code of \"git\nrev-parse\". The \"$rest\" variable added in 274a5c06d52 (merge: record\ntag objects without peeling in MERGE_HEAD, 2011-11-07) wasn't being\nused.\n\nSuch a thing is needed to support the .git/MERGE_HEAD format in\ngeneral, but in this case we have no such addition to the line. So\nlet's compare with \"test_cmp\" instead, we can always add back this\n\"$rest\" parsing if it's needed in the future.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t7600-merge.sh | 9 ++++-----\n 1 file changed, 4 insertions(+), 5 deletions(-)\n\ndiff --git a/t/t7600-merge.sh b/t/t7600-merge.sh\nindex 7c3f6ed9943..f5c4cbae9c8 100755\n--- a/t/t7600-merge.sh\n+++ b/t/t7600-merge.sh\n@@ -102,12 +102,11 @@ verify_parents () {\n }\n \n verify_mergeheads () {\n-\ttest_write_lines \"$@\" >mergehead.expected &&\n-\twhile read sha1 rest\n+\tfor rev in \"$@\"\n \tdo\n-\t\tgit rev-parse $sha1\n-\tdone <.git/MERGE_HEAD >mergehead.actual &&\n-\ttest_cmp mergehead.expected mergehead.actual\n+\t\tgit rev-parse $rev || return 1\n+\tdone >mergehead.expected &&\n+\ttest_cmp mergehead.expected .git/MERGE_HEAD\n }\n \n verify_no_mergehead () {\n-- \n2.39.0.rc1.980.g92d3d4579ad\n\n"},{"id":"468379","messageId":"patch-v2-7.8-d090478aa84-20221202T000227Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v2-0.8-00000000000-20221202T000227Z-avarab@gmail.com","subject":"[PATCH v2 7/8] tests: use \"test_cmp_cmd\" instead of \"test\" in sub-shells","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-02T00:06:33Z","receivedAt":"2022-12-02T00:07:47Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Convert a few cases where we were using \"test\" inside a sub-shell, and\nwere losing the exit code of \"git\".\n\nIn the case of \"t3200-branch.sh\" some adjacent code outside of a\nsub-shell that was losing the exit code is also being converted, as\nit's within the same hunk.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/lib-httpd.sh              |  3 +--\n t/lib-submodule-update.sh   | 20 +++++++-------------\n t/t3200-branch.sh           |  9 +++------\n t/t5605-clone-local.sh      |  9 ++++-----\n t/t7402-submodule-rebase.sh |  6 +++---\n 5 files changed, 18 insertions(+), 29 deletions(-)\n\ndiff --git a/t/lib-httpd.sh b/t/lib-httpd.sh\nindex 608949ea80b..082496d6535 100644\n--- a/t/lib-httpd.sh\n+++ b/t/lib-httpd.sh\n@@ -217,8 +217,7 @@ test_http_push_nonff () {\n \t\tgit commit -a -m path2 --amend &&\n \n \t\ttest_must_fail git push -v origin >output 2>&1 &&\n-\t\t(cd \"$REMOTE_REPO\" &&\n-\t\t test $HEAD = $(git rev-parse --verify HEAD))\n+\t\ttest_cmp_cmd \"$HEAD\" git -C \"$REMOTE_REPO\" rev-parse --verify HEAD\n \t'\n \n \ttest_expect_success 'non-fast-forward push show ref status' '\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex d5d98714b4e..207fab77bd3 100644\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -168,20 +168,14 @@ replace_gitfile_with_git_dir () {\n # Note that this only supports submodules at the root level of the\n # superproject, with the default name, i.e. same as its path.\n test_git_directory_is_unchanged () {\n-\t(\n-\t\tcd \".git/modules/$1\" &&\n-\t\t# does core.worktree point at the right place?\n-\t\ttest \"$(git config core.worktree)\" = \"../../../$1\" &&\n-\t\t# remove it temporarily before comparing, as\n-\t\t# \"$1/.git/config\" lacks it...\n-\t\tgit config --unset core.worktree\n-\t) &&\n+\t# does core.worktree point at the right place?\n+\ttest_cmp_cmd \"../../../$1\" git -C \".git/modules/$1\" config core.worktree\n+\t# remove it temporarily before comparing, as\n+\t# \"$1/.git/config\" lacks it...\n+\tgit -C \".git/modules/$1\" config --unset core.worktree &&\n \tdiff -r \".git/modules/$1\" \"$1/.git\" &&\n-\t(\n-\t\t# ... and then restore.\n-\t\tcd \".git/modules/$1\" &&\n-\t\tgit config core.worktree \"../../../$1\"\n-\t)\n+\t# ... and then restore.\n+\tgit -C \".git/modules/$1\" config core.worktree \"../../../$1\"\n }\n \n test_git_directory_exists () {\ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex 5a169b68d6a..c31036b49be 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -242,12 +242,9 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou\n test_expect_success 'git branch -M baz bam should succeed within a worktree in which baz is checked out' '\n \tgit checkout -b baz &&\n \tgit worktree add -f bazdir baz &&\n-\t(\n-\t\tcd bazdir &&\n-\t\tgit branch -M baz bam &&\n-\t\ttest $(git rev-parse --abbrev-ref HEAD) = bam\n-\t) &&\n-\ttest $(git rev-parse --abbrev-ref HEAD) = bam &&\n+\tgit -C \"$bazdir\" branch -M baz bam &&\n+\ttest_cmp_cmd \"bam\" git -C \"$bazdir\" rev-parse --abbrev-ref HEAD &&\n+\ttest_cmp_cmd \"bam\" git rev-parse --abbrev-ref HEAD &&\n \trm -r bazdir &&\n \tgit worktree prune\n '\ndiff --git a/t/t5605-clone-local.sh b/t/t5605-clone-local.sh\nindex 38b850c10ef..55bda2c0aa9 100755\n--- a/t/t5605-clone-local.sh\n+++ b/t/t5605-clone-local.sh\n@@ -15,8 +15,8 @@ test_expect_success 'preparing origin repository' '\n \t: >file && git add . && git commit -m1 &&\n \tgit clone --bare . a.git &&\n \tgit clone --bare . x &&\n-\ttest \"$(cd a.git && git config --bool core.bare)\" = true &&\n-\ttest \"$(cd x && git config --bool core.bare)\" = true &&\n+\ttest_cmp_cmd true git -C a.git config --bool core.bare &&\n+\ttest_cmp_cmd true git -C x config --bool core.bare &&\n \tgit bundle create b1.bundle --all &&\n \tgit bundle create b2.bundle main &&\n \tmkdir dir &&\n@@ -28,9 +28,8 @@ test_expect_success 'preparing origin repository' '\n \n test_expect_success 'local clone without .git suffix' '\n \tgit clone -l -s a b &&\n-\t(cd b &&\n-\ttest \"$(git config --bool core.bare)\" = false &&\n-\tgit fetch)\n+\ttest_cmp_cmd false git -C b config --bool core.bare &&\n+\tgit -C b fetch\n '\n \n test_expect_success 'local clone with .git suffix' '\ndiff --git a/t/t7402-submodule-rebase.sh b/t/t7402-submodule-rebase.sh\nindex ebeca12a711..277bb8ae520 100755\n--- a/t/t7402-submodule-rebase.sh\n+++ b/t/t7402-submodule-rebase.sh\n@@ -82,11 +82,11 @@ test_expect_success 'stash with a dirty submodule' '\n \tCURRENT=$(cd submodule && git rev-parse HEAD) &&\n \tgit stash &&\n \ttest new != $(cat file) &&\n-\ttest submodule = $(git diff --name-only) &&\n-\ttest $CURRENT = $(cd submodule && git rev-parse HEAD) &&\n+\ttest_cmp_cmd submodule git diff --name-only &&\n+\ttest_cmp_cmd \"$CURRENT\" git -C submodule rev-parse HEAD &&\n \tgit stash apply &&\n \ttest new = $(cat file) &&\n-\ttest $CURRENT = $(cd submodule && git rev-parse HEAD)\n+\ttest_cmp_cmd \"$CURRENT\" git -C submodule rev-parse HEAD\n \n '\n \n-- \n2.39.0.rc1.980.g92d3d4579ad\n\n"},{"id":"468380","messageId":"patch-v2-8.8-979a7f003f8-20221202T000227Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v2-0.8-00000000000-20221202T000227Z-avarab@gmail.com","subject":"[PATCH v2 8/8] tests: use \"test_cmp_cmd\" in misc tests","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-02T00:06:34Z","receivedAt":"2022-12-02T00:07:59Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change a few miscellaneous tests to use \"test_cmp_cmd\" to avoid losing\nthe exit code of \"git\".\n\nThere's many offenders left that match patterns like:\n\n\t/test .*\\$\\((test-tool|git)/\n\nWhat these all have in common is that they were the rare odd cases out\nin test files that were otherwise consistently checking the exit code.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t1401-symbolic-ref.sh            | 3 ++-\n t/t2005-checkout-index-symlinks.sh | 2 +-\n t/t3701-add-interactive.sh         | 9 ++++++---\n t/t5522-pull-symlink.sh            | 2 +-\n t/t7402-submodule-rebase.sh        | 4 ++--\n t/t7504-commit-msg-hook.sh         | 2 +-\n t/t7516-commit-races.sh            | 3 ++-\n t/t7810-grep.sh                    | 2 +-\n 8 files changed, 16 insertions(+), 11 deletions(-)\n\ndiff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh\nindex d708acdb819..5e36899d207 100755\n--- a/t/t1401-symbolic-ref.sh\n+++ b/t/t1401-symbolic-ref.sh\n@@ -33,7 +33,8 @@ test_expect_success 'symbolic-ref refuses non-ref for HEAD' '\n reset_to_sane\n \n test_expect_success 'symbolic-ref refuses bare sha1' '\n-\ttest_must_fail git symbolic-ref HEAD $(git rev-parse HEAD)\n+\trev=$(git rev-parse HEAD) &&\n+\ttest_must_fail git symbolic-ref HEAD \"$rev\"\n '\n \n reset_to_sane\ndiff --git a/t/t2005-checkout-index-symlinks.sh b/t/t2005-checkout-index-symlinks.sh\nindex 112682a45a1..aee80d39221 100755\n--- a/t/t2005-checkout-index-symlinks.sh\n+++ b/t/t2005-checkout-index-symlinks.sh\n@@ -24,6 +24,6 @@ test -f symlink'\n \n test_expect_success \\\n 'the file must be the blob we added during the setup' '\n-test \"$(git hash-object -t blob symlink)\" = $l'\n+test_cmp_cmd \"$l\" git hash-object -t blob symlink'\n \n test_done\ndiff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh\nindex 5841f280fb2..3e59ffd18a0 100755\n--- a/t/t3701-add-interactive.sh\n+++ b/t/t3701-add-interactive.sh\n@@ -296,9 +296,12 @@ test_expect_success FILEMODE 'stage mode and hunk' '\n \techo content >>file &&\n \tchmod +x file &&\n \tprintf \"y\\\\ny\\\\n\" | git add -p &&\n-\tgit diff --cached file | grep \"new mode\" &&\n-\tgit diff --cached file | grep \"+content\" &&\n-\ttest -z \"$(git diff file)\"\n+\tgit diff --cached file >out &&\n+\tgrep \"new mode\" <out &&\n+\tgit diff --cached file >out &&\n+\tgrep \"+content\" <out &&\n+\tgit diff file >out &&\n+\ttest_must_be_empty out\n '\n \n # end of tests disabled when filemode is not usable\ndiff --git a/t/t5522-pull-symlink.sh b/t/t5522-pull-symlink.sh\nindex bcff460d0a2..b36dd40e34e 100755\n--- a/t/t5522-pull-symlink.sh\n+++ b/t/t5522-pull-symlink.sh\n@@ -78,7 +78,7 @@ test_expect_success SYMLINKS 'pushing from symlinked subdir' '\n \t\tgit commit -m push ./file &&\n \t\tgit push\n \t) &&\n-\ttest push = $(git show HEAD:subdir/file)\n+\ttest_cmp_cmd push git show HEAD:subdir/file\n '\n \n test_done\ndiff --git a/t/t7402-submodule-rebase.sh b/t/t7402-submodule-rebase.sh\nindex 277bb8ae520..b27d8da69ee 100755\n--- a/t/t7402-submodule-rebase.sh\n+++ b/t/t7402-submodule-rebase.sh\n@@ -55,11 +55,11 @@ chmod a+x fake-editor.sh\n \n test_expect_success 'interactive rebase with a dirty submodule' '\n \n-\ttest submodule = $(git diff --name-only) &&\n+\ttest_cmp_cmd submodule git diff --name-only &&\n \tHEAD=$(git rev-parse HEAD) &&\n \tGIT_EDITOR=\"\\\"$(pwd)/fake-editor.sh\\\"\" EDITOR_TEXT=\"pick $HEAD\" \\\n \t\tgit rebase -i HEAD^ &&\n-\ttest submodule = $(git diff --name-only)\n+\ttest_cmp_cmd submodule git diff --name-only\n \n '\n \ndiff --git a/t/t7504-commit-msg-hook.sh b/t/t7504-commit-msg-hook.sh\nindex a39de8c1126..2b94237f9d1 100755\n--- a/t/t7504-commit-msg-hook.sh\n+++ b/t/t7504-commit-msg-hook.sh\n@@ -101,7 +101,7 @@ test_expect_success 'setup: commit-msg hook that always fails' '\n '\n \n commit_msg_is () {\n-\ttest \"$(git log --pretty=format:%s%b -1)\" = \"$1\"\n+\ttest_cmp_cmd \"$1\" git log --pretty=tformat:%s%b -1\n }\n \n test_expect_success 'with failing hook' '\ndiff --git a/t/t7516-commit-races.sh b/t/t7516-commit-races.sh\nindex f2ce14e9071..2d38a16480e 100755\n--- a/t/t7516-commit-races.sh\n+++ b/t/t7516-commit-races.sh\n@@ -10,7 +10,8 @@ test_expect_success 'race to create orphan commit' '\n \ttest_must_fail env EDITOR=./hare-editor git commit --allow-empty -m tortoise -e &&\n \tgit show -s --pretty=format:%s >subject &&\n \tgrep hare subject &&\n-\ttest -z \"$(git show -s --pretty=format:%P)\"\n+\tgit show -s --pretty=format:%P >out &&\n+\ttest_must_be_empty out\n '\n \n test_expect_success 'race to create non-orphan commit' '\ndiff --git a/t/t7810-grep.sh b/t/t7810-grep.sh\nindex 8eded6ab274..232b041b0cf 100755\n--- a/t/t7810-grep.sh\n+++ b/t/t7810-grep.sh\n@@ -1001,7 +1001,7 @@ test_expect_success 'log --committer does not search in timestamp' '\n test_expect_success 'grep with CE_VALID file' '\n \tgit update-index --assume-unchanged t/t &&\n \trm t/t &&\n-\ttest \"$(git grep test)\" = \"t/t:test\" &&\n+\ttest_cmp_cmd \"t/t:test\" git grep test &&\n \tgit update-index --no-assume-unchanged t/t &&\n \tgit checkout t/t\n '\n-- \n2.39.0.rc1.980.g92d3d4579ad\n\n"},{"id":"468385","messageId":"CAPig+cQK8BRU0u0g+jAkyJaqSamYBynJ6s00_6H2beb6gXaRDA@mail.gmail.com","threadId":"58200","inReplyTo":"patch-v2-1.8-7c9f8d2830f-20221202T000227Z-avarab@gmail.com","subject":"Re: [PATCH v2 1/8] log tests: don't use \"exit 1\" outside a sub-shell","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2022-12-02T01:02:14Z","receivedAt":"2022-12-02T01:02:30Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Dec 1, 2022 at 7:07 PM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n> Change an \"exit 1\" added in ac52d9410e5 (t4205: cover `git log\n> --reflog -z` blindspot, 2019-11-19) to use \"return 1\" instead, which\n> curiously was done in an adjacent test case added in the same commit.\n>\n> Using \"exit 1\" outside a sub-shell will cause the test framework\n> itself to exit on failure, which isn't what we want to do here.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n> diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh\n> @@ -156,7 +156,7 @@ test_expect_success 'NUL termination with --reflog --pretty=oneline' '\n>         for r in $revs\n>         do\n>                 git show -s --pretty=oneline \"$r\" >raw &&\n> -               cat raw | lf_to_nul || exit 1\n> +               cat raw | lf_to_nul || return 1\n>         done >expect &&\n\nUsing `return 1` here is \"obviously correct\" since this code is not\ninside a subshell. Furthermore, the exit code of the for-loop itself\nis not being lost down a pipe, so `return 1` is indeed an appropriate\nway to signal failure. Good.\n"},{"id":"468386","messageId":"02ead668-5b5d-877c-1e40-3656fd85945f@web.de","threadId":"58200","inReplyTo":"patch-v2-2.8-345a667d5bb-20221202T000227Z-avarab@gmail.com","subject":"Re: [PATCH v2 2/8] auto-crlf tests: check \"git checkout\" exit code","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2022-12-02T01:02:55Z","receivedAt":"2022-12-02T01:03:05Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 02.12.2022 um 01:06 schrieb Ævar Arnfjörð Bjarmason:\n> Don't hide the exit code from the \"git checkout\" we run to checkout\n> our attributes file.\n>\n> This fixes cases where we'd have e.g. missed memory leaks under\n> SANITIZE=leak, this code doesn't leak (the relevant \"git checkout\"\n> leak has been fixed), but in a past version of git we'd continue past\n> this failure under SANITIZE=leak when these invocations had errored\n> out, even under \"--immediate\".\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  t/t0027-auto-crlf.sh | 14 ++++++++++----\n>  1 file changed, 10 insertions(+), 4 deletions(-)\n>\n> diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\n> index a94ac1eae37..574344a99db 100755\n> --- a/t/t0027-auto-crlf.sh\n> +++ b/t/t0027-auto-crlf.sh\n> @@ -294,11 +294,17 @@ checkout_files () {\n>  \tpfx=eol_${ceol}_crlf_${crlf}_attr_${attr}_ &&\n>  \tfor f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul\n>  \tdo\n> -\t\trm crlf_false_attr__$f.txt &&\n> -\t\tif test -z \"$ceol\"; then\n> -\t\t\tgit checkout -- crlf_false_attr__$f.txt\n> +\t\tif test -z \"$ceol\"\n> +\t\tthen\n> +\t\t\ttest_expect_success \"setup $f checkout\" '\n> +\t\t\t\trm crlf_false_attr__$f.txt &&\n> +\t\t\t\tgit checkout -- crlf_false_attr__$f.txt\n> +\t\t\t'\n>  \t\telse\n> -\t\t\tgit -c core.eol=$ceol checkout -- crlf_false_attr__$f.txt\n> +\t\t\ttest_expect_success \"setup $f checkout with core.eol=$ceol\" '\n> +\t\t\t\trm crlf_false_attr__$f.txt &&\n> +\t\t\t\tgit -c core.eol=$ceol checkout -- crlf_false_attr__$f.txt\n> +\t\t\t'\n\nThat adds five test_expect_success calls.  Wouldn't one suffice, for the\nwhole for loop, and a \"|| return 1\"?\n\nOne line above the context there's a \"git config\" call that should also\nbe covered, right?\n\nSide note: The checkout commands only differ in their -c parameter.\nThey could be unified like this, which might simplify handling their\nreturn code:\n\n\tgit ${ceol:+-c core.eol=$ceol} checkout -- crlf_false_attr__$f.txt\n\n>  \t\tfi\n>  \tdone\n>\n"},{"id":"468387","messageId":"CAPig+cRwwyiQdbAhDYGH==8r+Q2HVuqbW2a8c6W_myyqKAs4eA@mail.gmail.com","threadId":"58200","inReplyTo":"02ead668-5b5d-877c-1e40-3656fd85945f@web.de","subject":"Re: [PATCH v2 2/8] auto-crlf tests: check \"git checkout\" exit code","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2022-12-02T01:10:47Z","receivedAt":"2022-12-02T01:11:01Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Dec 1, 2022 at 8:02 PM René Scharfe <l.s.r@web.de> wrote:\n> Am 02.12.2022 um 01:06 schrieb Ævar Arnfjörð Bjarmason:\n> > Don't hide the exit code from the \"git checkout\" we run to checkout\n> > our attributes file.\n> > @@ -294,11 +294,17 @@ checkout_files () {\n> >       pfx=eol_${ceol}_crlf_${crlf}_attr_${attr}_ &&\n> >       for f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul\n> >       do\n> > -             rm crlf_false_attr__$f.txt &&\n> > -             if test -z \"$ceol\"; then\n> > -                     git checkout -- crlf_false_attr__$f.txt\n> > +             if test -z \"$ceol\"\n> > +             then\n> > +                     test_expect_success \"setup $f checkout\" '\n> > +                             rm crlf_false_attr__$f.txt &&\n> > +                             git checkout -- crlf_false_attr__$f.txt\n> > +                     '\n> >               else\n> > -                     git -c core.eol=$ceol checkout -- crlf_false_attr__$f.txt\n> > +                     test_expect_success \"setup $f checkout with core.eol=$ceol\" '\n> > +                             rm crlf_false_attr__$f.txt &&\n> > +                             git -c core.eol=$ceol checkout -- crlf_false_attr__$f.txt\n> > +                     '\n>\n> That adds five test_expect_success calls.  Wouldn't one suffice, for the\n> whole for loop, and a \"|| return 1\"?\n\nSeems like a reasonable idea.\n\n> One line above the context there's a \"git config\" call that should also\n> be covered, right?\n\nAlso, the call to create_gitattributes() just above that line is in\nthe function's &&-chain, which implies that it too should be covered.\n"},{"id":"468388","messageId":"6f6350b7-a479-c05d-6100-cb2aad72a658@web.de","threadId":"58200","inReplyTo":"patch-v2-4.8-c36060934a6-20221202T000227Z-avarab@gmail.com","subject":"Re: [PATCH v2 4/8] test-lib-functions: add and use test_cmp_cmd","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2022-12-02T01:30:35Z","receivedAt":"2022-12-02T01:30:45Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 02.12.2022 um 01:06 schrieb Ævar Arnfjörð Bjarmason:\n> Add a \"test_cmp_cmd\" helper for the common pattern discussed in the\n> documentation being added here to \"t/test-lib-functions.sh\".\n>\n> This implementation leaves the door open for extending this helper\n> past its obvious limitations, such as:\n>\n> \ttest_cmp_cmd \"some\" \"lines\" -- <some-cmd>\n> \ttest_cmp_cmd --stdin <some-cmd> <expect\n> \ttest_cmp_cmd --ignore-stderr \"output\" <some-cmd>\n>\n> By using this in we'll catch cases where \"git\" or \"test-tool\"\n> errors (such as segfaults or abort()) were previously hidden, and we'd\n> either pass the test, or fail in some subsequent assertion.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n\n> diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\n> index 796093a7b32..0e8e0f808e3 100644\n> --- a/t/test-lib-functions.sh\n> +++ b/t/test-lib-functions.sh\n> @@ -1274,6 +1274,24 @@ test_cmp_rev () {\n>  \tfi\n>  }\n>\n> +# test_cmp_cmd is a convenience helper for doing the more verbose:\n> +#\n> +#\techo something >expect &&\n> +#\t<some-command-and-args> >actual &&\n> +#\ttest_cmp expect actual\n> +#\n> +# As:\n> +#\n> +#\ttest_cmp_cmd something <some-command-and-args>\n> +test_cmp_cmd () {\n> +\tlocal expect=\"$1\" &&\n> +\tshift &&\n> +\tprintf \"%s\\n\" \"$expect\" >expect &&\n> +\t\"$@\" >actual 2>err &&\n> +\ttest_must_be_empty err\n> +\ttest_cmp expect actual\n\nerr, expect and actual are common filenames used in tests.\nClobbering them might be surprising.  Perhaps at least add some\nprefix (e.g. name them test_cmp_cmd_expect etc.), like other\nfunctions in that script do, to avoid collisions?\n\n> +}\n> +\n>  # Compare paths respecting core.ignoreCase\n>  test_cmp_fspath () {\n>  \tif test \"x$1\" = \"x$2\"\n"},{"id":"468389","messageId":"4f6f065c-1fd9-7c1a-f547-c568e930562d@web.de","threadId":"58200","inReplyTo":"patch-v2-5.8-f826a336c3d-20221202T000227Z-avarab@gmail.com","subject":"Re: [PATCH v2 5/8] t/lib-patch-mode.sh: fix ignored \"git\" exit codes","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2022-12-02T01:31:12Z","receivedAt":"2022-12-02T01:31:21Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 02.12.2022 um 01:06 schrieb Ævar Arnfjörð Bjarmason:\n> Fix code added in b319ef70a94 (Add a small patch-mode testing library,\n> 2009-08-13) to use &&-chaining and the newly added \"test_cmp_cmd\"\n> instead of interpolating \"git\" commands in a \"test\" statement.\n>\n> This fixes cases where we'd have e.g. missed memory leaks under\n> SANITIZE=leak, this code doesn't leak now as far as I can tell, but I\n> discovered it while looking at leaks in related code.\n>\n> The \"cat _head >expect\" here is redundant, we could simply give\n> \"_head\" to \"test_cmp\", but let's be consistent in using the \"expect\"\n> and \"actual\" names for clarity.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  t/lib-patch-mode.sh | 9 ++++++---\n>  1 file changed, 6 insertions(+), 3 deletions(-)\n>\n> diff --git a/t/lib-patch-mode.sh b/t/lib-patch-mode.sh\n> index cfd76bf987b..ae51f33a010 100644\n> --- a/t/lib-patch-mode.sh\n> +++ b/t/lib-patch-mode.sh\n> @@ -29,8 +29,11 @@ set_and_save_state () {\n>\n>  # verify_state <path> <expected-worktree-content> <expected-index-content>\n>  verify_state () {\n> -\ttest \"$(cat \"$1\")\" = \"$2\" &&\n> -\ttest \"$(git show :\"$1\")\" = \"$3\"\n> +\techo \"$2\" >expect &&\n> +\tcat \"$1\" >actual &&\n> +\ttest_cmp expect actual &&\n\nHmm, I'd have expected this oneliner instead, matching the conversion of\nthe second command:\n\n\ttest_cmp_cmd \"$2\" cat \"$1\" &&\n\ncat is not a git command, though, so the extra checks of test_cmp_cmd\nare unnecessary.  But how about avoiding its useless use then?\n\n\techo \"$2\" >expect &&\n\ttest_cmp expect \"$1\" &&\n\n> +\n> +\ttest_cmp_cmd \"$3\" git show :\"$1\"\n>  }\n>\n>  # verify_saved_state <path>\n> @@ -46,5 +49,5 @@ save_head () {\n>  }\n>\n>  verify_saved_head () {\n> -\ttest \"$(cat _head)\" = \"$(git rev-parse HEAD)\"\n> +\ttest_cmp_cmd \"$(cat _head)\" git rev-parse HEAD\n>  }\n"},{"id":"468390","messageId":"CAPig+cTfx4QYBdtSomPRM+BpW+3ELqaQxD7okKhXzykVkyH9NA@mail.gmail.com","threadId":"58200","inReplyTo":"patch-v2-4.8-c36060934a6-20221202T000227Z-avarab@gmail.com","subject":"Re: [PATCH v2 4/8] test-lib-functions: add and use test_cmp_cmd","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2022-12-02T01:33:03Z","receivedAt":"2022-12-02T01:33:20Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Dec 1, 2022 at 7:07 PM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n> Add a \"test_cmp_cmd\" helper for the common pattern discussed in the\n> documentation being added here to \"t/test-lib-functions.sh\".\n\nI'm somewhat \"meh\" on this, at least as it's sold here. Perhaps if it\nwas sold as producing better diagnostic report for:\n\n    test \"$something\" = \"$(git blah)\"\n\nwhich covers many of the \"fixes\" in this patch then I'd be less jaded...\n\n> By using this in we'll catch cases where \"git\" or \"test-tool\"\n> errors (such as segfaults or abort()) were previously hidden, and we'd\n> either pass the test, or fail in some subsequent assertion.\n\n...which, I suppose, may be what this paragraph is saying, but it's\nnot immediately obvious.\n\nMinor subjective stuff aside...\n\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n> diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\n> +# test_cmp_cmd is a convenience helper for doing the more verbose:\n> +#\n> +#      echo something >expect &&\n> +#      <some-command-and-args> >actual &&\n> +#      test_cmp expect actual\n> +#\n> +# As:\n> +#\n> +#      test_cmp_cmd something <some-command-and-args>\n> +test_cmp_cmd () {\n> +       local expect=\"$1\" &&\n> +       shift &&\n> +       printf \"%s\\n\" \"$expect\" >expect &&\n> +       \"$@\" >actual 2>err &&\n> +       test_must_be_empty err\n> +       test_cmp expect actual\n> +}\n\nI do find it concerning that this clobbers 'actual', 'expect', and\n'err', which are common enough names. I'd suggest using names unique\nto this function (perhaps 'test_cmp_cmd.actual',\n'test_cmp_cmd.expect', etc.).\n\nI think you also need to document the fact that it expects stderr\noutput to be empty.\n"},{"id":"468391","messageId":"b32593a2-664b-6ef0-ed8f-194a25a9eb69@web.de","threadId":"58200","inReplyTo":"patch-v2-6.8-5715ff7f0f7-20221202T000227Z-avarab@gmail.com","subject":"Re: [PATCH v2 6/8] merge tests: don't ignore \"rev-parse\" exit code in helper","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2022-12-02T01:41:32Z","receivedAt":"2022-12-02T01:41:44Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 02.12.2022 um 01:06 schrieb Ævar Arnfjörð Bjarmason:\n> Change the verify_mergeheads() helper the check the exit code of \"git\n> rev-parse\". The \"$rest\" variable added in 274a5c06d52 (merge: record\n> tag objects without peeling in MERGE_HEAD, 2011-11-07) wasn't being\n> used.\n>\n> Such a thing is needed to support the .git/MERGE_HEAD format in\n> general, but in this case we have no such addition to the line. So\n> let's compare with \"test_cmp\" instead, we can always add back this\n> \"$rest\" parsing if it's needed in the future.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  t/t7600-merge.sh | 9 ++++-----\n>  1 file changed, 4 insertions(+), 5 deletions(-)\n>\n> diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh\n> index 7c3f6ed9943..f5c4cbae9c8 100755\n> --- a/t/t7600-merge.sh\n> +++ b/t/t7600-merge.sh\n> @@ -102,12 +102,11 @@ verify_parents () {\n>  }\n>\n>  verify_mergeheads () {\n> -\ttest_write_lines \"$@\" >mergehead.expected &&\n> -\twhile read sha1 rest\n> +\tfor rev in \"$@\"\n>  \tdo\n> -\t\tgit rev-parse $sha1\n> -\tdone <.git/MERGE_HEAD >mergehead.actual &&\n> -\ttest_cmp mergehead.expected mergehead.actual\n> +\t\tgit rev-parse $rev || return 1\n> +\tdone >mergehead.expected &&\n> +\ttest_cmp mergehead.expected .git/MERGE_HEAD\n\nWhy all these changes and not just add \"|| return 1\"?\n\n>  }\n>\n>  verify_no_mergehead () {\n"},{"id":"468393","messageId":"CAPig+cSgnhzFCUVTQCcTKJK+2qVOpdB2R-Vq1DjqspDJudom4w@mail.gmail.com","threadId":"58200","inReplyTo":"CAPig+cTfx4QYBdtSomPRM+BpW+3ELqaQxD7okKhXzykVkyH9NA@mail.gmail.com","subject":"Re: [PATCH v2 4/8] test-lib-functions: add and use test_cmp_cmd","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2022-12-02T01:45:42Z","receivedAt":"2022-12-02T01:46:02Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Dec 1, 2022 at 8:33 PM Eric Sunshine <sunshine@sunshineco.com> wrote:\n> On Thu, Dec 1, 2022 at 7:07 PM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n> > diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\n> > +# test_cmp_cmd is a convenience helper for doing the more verbose:\n> > +#\n> > +#      echo something >expect &&\n> > +#      <some-command-and-args> >actual &&\n> > +#      test_cmp expect actual\n> > +#\n> > +# As:\n> > +#\n> > +#      test_cmp_cmd something <some-command-and-args>\n> > +test_cmp_cmd () {\n> > +       local expect=\"$1\" &&\n> > +       shift &&\n> > +       printf \"%s\\n\" \"$expect\" >expect &&\n> > +       \"$@\" >actual 2>err &&\n> > +       test_must_be_empty err\n> > +       test_cmp expect actual\n> > +}\n>\n> I think you also need to document the fact that it expects stderr\n> output to be empty.\n\nThat said, the behavior of expecting stderr output to be empty seems\nlike a potentially bad default since it won't play well with commands\nwhich send their \"chatty\" output to stderr.\n\nAnother reason I'm \"meh\" about this function is that it seems too\nnarrowly focussed, insisting that the \"expect\" argument is expressed\nas a one-liner. (Yes, I know that that is not a hard limitation; a\ncaller can pass in a multiline string, but still...) Maybe I'd be less\njaded if it accepted \"expect\" on its stdin. But, even that doesn't\nseem to buy much. The vast majority of cases where you've converted:\n\n    test \"$dir\" = \"$(test-tool path-utils real_path $dir2)\" &&\n\nto:\n\n    test_cmp_cmd \"$dir\" test-tool path-utils real_path $dir2 &&\n\ncould just have easily become:\n\n    echo \"$dir\" >expect &&\n    test_cmp test-tool path-utils real_path $dir2 &&\n\nwhich isn't bad at all, even if it is one line longer, and it is\nidiomatic in this test suite.\n"},{"id":"468394","messageId":"xmqqwn7apodp.fsf@gitster.g","threadId":"58200","inReplyTo":"CAPig+cQK8BRU0u0g+jAkyJaqSamYBynJ6s00_6H2beb6gXaRDA@mail.gmail.com","subject":"Re: [PATCH v2 1/8] log tests: don't use \"exit 1\" outside a sub-shell","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-12-02T01:48:02Z","receivedAt":"2022-12-02T01:48:06Z","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>>                 git show -s --pretty=oneline \"$r\" >raw &&\n>> -               cat raw | lf_to_nul || exit 1\n>> +               cat raw | lf_to_nul || return 1\n>>         done >expect &&\n>\n> Using `return 1` here is \"obviously correct\" since this code is not\n> inside a subshell. Furthermore, the exit code of the for-loop itself\n> is not being lost down a pipe, so `return 1` is indeed an appropriate\n> way to signal failure. Good.\n\n\"return 1\" is obvious and safe correction.  I have to wonder if\ntest_expect_success can be taught to be smarter to intercept \"exit\"\nso we do not have to bo so careful, but that would be a much more\ninvolved change to the lower-level of test framework.\n\n"},{"id":"468395","messageId":"CAPig+cROyCWrweskbUoxjA9ziHPqUR++KgJ9ViTKwkPhz-J3QQ@mail.gmail.com","threadId":"58200","inReplyTo":"CAPig+cSgnhzFCUVTQCcTKJK+2qVOpdB2R-Vq1DjqspDJudom4w@mail.gmail.com","subject":"Re: [PATCH v2 4/8] test-lib-functions: add and use test_cmp_cmd","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2022-12-02T01:52:14Z","receivedAt":"2022-12-02T01:52:30Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Dec 1, 2022 at 8:45 PM Eric Sunshine <sunshine@sunshineco.com> wrote:\n> But, even that doesn't\n> seem to buy much. The vast majority of cases where you've converted:\n>\n>     test \"$dir\" = \"$(test-tool path-utils real_path $dir2)\" &&\n>\n> to:\n>\n>     test_cmp_cmd \"$dir\" test-tool path-utils real_path $dir2 &&\n>\n> could just have easily become:\n>\n>     echo \"$dir\" >expect &&\n>     test_cmp test-tool path-utils real_path $dir2 &&\n>\n> which isn't bad at all, even if it is one line longer, and it is\n> idiomatic in this test suite.\n\nI can't count. Of course, I meant:\n\n     echo \"$dir\" >expect &&\n     test-tool path-utils real_path $dir2 >actual &&\n     test_cmp expect actual &&\n\nwhich is two extra lines.\n"},{"id":"468396","messageId":"xmqqsfhypnq0.fsf@gitster.g","threadId":"58200","inReplyTo":"patch-v2-3.8-c5feef1c808-20221202T000227Z-avarab@gmail.com","subject":"Re: [PATCH v2 3/8] diff tests: fix ignored exit codes in t4023","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-12-02T02:02:15Z","receivedAt":"2022-12-02T02:02:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Change a \"git diff-tree\" command to be &&-chained so that we won't\n> ignore its exit code, see the ea05fd5fbf7 (Merge branch\n> 'ab/keep-git-exit-codes-in-tests', 2022-03-16) topic for prior art.\n>\n> This fixes code added in b45563a229f (rename: Break filepairs with\n> different types., 2007-11-30). Due to hiding the exit code we hid a\n> memory leak under SANITIZE=leak.\n\nThanks.\n\nThe changes all make sense and obviously correct.  The ancient style\nto have a blank line before the first statement in the test body is\nalso gone, which is a good thing.\n\n\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  t/t4023-diff-rename-typechange.sh | 12 ++++++------\n>  1 file changed, 6 insertions(+), 6 deletions(-)\n>\n> diff --git a/t/t4023-diff-rename-typechange.sh b/t/t4023-diff-rename-typechange.sh\n> index 7cb99092938..25c31b0cb1b 100755\n> --- a/t/t4023-diff-rename-typechange.sh\n> +++ b/t/t4023-diff-rename-typechange.sh\n> @@ -52,8 +52,8 @@ test_expect_success setup '\n>  '\n>  \n>  test_expect_success 'cross renames to be detected for regular files' '\n> -\n> -\tgit diff-tree five six -r --name-status -B -M | sort >actual &&\n> +\tgit diff-tree five six -r --name-status -B -M >out &&\n> +\tsort <out >actual &&\n>  \t{\n>  \t\techo \"R100\tfoo\tbar\" &&\n>  \t\techo \"R100\tbar\tfoo\"\n> @@ -63,8 +63,8 @@ test_expect_success 'cross renames to be detected for regular files' '\n>  '\n>  \n>  test_expect_success 'cross renames to be detected for typechange' '\n> -\n> -\tgit diff-tree one two -r --name-status -B -M | sort >actual &&\n> +\tgit diff-tree one two -r --name-status -B -M >out &&\n> +\tsort <out >actual &&\n>  \t{\n>  \t\techo \"R100\tfoo\tbar\" &&\n>  \t\techo \"R100\tbar\tfoo\"\n> @@ -74,8 +74,8 @@ test_expect_success 'cross renames to be detected for typechange' '\n>  '\n>  \n>  test_expect_success 'moves and renames' '\n> -\n> -\tgit diff-tree three four -r --name-status -B -M | sort >actual &&\n> +\tgit diff-tree three four -r --name-status -B -M >out &&\n> +\tsort <out >actual &&\n>  \t{\n>  \t\t# see -B -M (#6) in t4008\n>  \t\techo \"C100\tfoo\tbar\" &&\n"},{"id":"468397","messageId":"xmqqiliupmxh.fsf@gitster.g","threadId":"58200","inReplyTo":"patch-v2-8.8-979a7f003f8-20221202T000227Z-avarab@gmail.com","subject":"Re: [PATCH v2 8/8] tests: use \"test_cmp_cmd\" in misc tests","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-12-02T02:19:22Z","receivedAt":"2022-12-02T02:19:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Change a few miscellaneous tests to use \"test_cmp_cmd\" to avoid losing\n> the exit code of \"git\".\n\nThe step might have started out to do so, but many of them do not\nseem to anymore, perhaps because you allowed the scope of the step\nto drift and the focus to be lost while developing more?\n\n>  test_expect_success 'symbolic-ref refuses bare sha1' '\n> -\ttest_must_fail git symbolic-ref HEAD $(git rev-parse HEAD)\n> +\trev=$(git rev-parse HEAD) &&\n> +\ttest_must_fail git symbolic-ref HEAD \"$rev\"\n\nThis is not a test_cmp_cmd user.  The update is good.\n\n> diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh\n> index 5841f280fb2..3e59ffd18a0 100755\n> --- a/t/t3701-add-interactive.sh\n> +++ b/t/t3701-add-interactive.sh\n> @@ -296,9 +296,12 @@ test_expect_success FILEMODE 'stage mode and hunk' '\n>  \techo content >>file &&\n>  \tchmod +x file &&\n>  \tprintf \"y\\\\ny\\\\n\" | git add -p &&\n> -\tgit diff --cached file | grep \"new mode\" &&\n> -\tgit diff --cached file | grep \"+content\" &&\n> -\ttest -z \"$(git diff file)\"\n> +\tgit diff --cached file >out &&\n> +\tgrep \"new mode\" <out &&\n> +\tgit diff --cached file >out &&\n> +\tgrep \"+content\" <out &&\n\nNo need to run the same \"diff --cached file\" twice.  No need to\nredirect into \"grep\"; giving the file on the command line is more\nnatural.\n\n> +\tgit diff file >out &&\n> +\ttest_must_be_empty out\n>  '\n\nOther than that, the above is an improvement, but again, it is not a\ntest_cmp_cmd user.\n\n> diff --git a/t/t7516-commit-races.sh b/t/t7516-commit-races.sh\n> index f2ce14e9071..2d38a16480e 100755\n> --- a/t/t7516-commit-races.sh\n> +++ b/t/t7516-commit-races.sh\n> @@ -10,7 +10,8 @@ test_expect_success 'race to create orphan commit' '\n>  \ttest_must_fail env EDITOR=./hare-editor git commit --allow-empty -m tortoise -e &&\n>  \tgit show -s --pretty=format:%s >subject &&\n>  \tgrep hare subject &&\n> -\ttest -z \"$(git show -s --pretty=format:%P)\"\n> +\tgit show -s --pretty=format:%P >out &&\n> +\ttest_must_be_empty out\n>  '\n\nLikewise.\n\nI guess only half of the tests updated are test_cmp_cmd users, so\nthis step was about half as big when it was originally written?\n\n"},{"id":"468398","messageId":"xmqqbkompjw6.fsf@gitster.g","threadId":"58200","inReplyTo":"CAPig+cQK8BRU0u0g+jAkyJaqSamYBynJ6s00_6H2beb6gXaRDA@mail.gmail.com","subject":"Re: [PATCH v2 1/8] log tests: don't use \"exit 1\" outside a sub-shell","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-12-02T03:24:57Z","receivedAt":"2022-12-02T03:25:02Z","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>>         for r in $revs\n>>         do\n>>                 git show -s --pretty=oneline \"$r\" >raw &&\n>> -               cat raw | lf_to_nul || exit 1\n>> +               cat raw | lf_to_nul || return 1\n>>         done >expect &&\n>\n> Using `return 1` here is \"obviously correct\" since this code is not\n> inside a subshell.\n\nWhile it is safe and correct, I wonder if test_expect_success can be\nmade a bit smarter by somehow capturing what happens inside its\nbody.  We of course cannot just wrap everything inside a subshell,\nas we do want to allow the test body to affect the shell environment\nit is running in with its side effects.\n"},{"id":"468399","messageId":"xmqq5yeupj53.fsf@gitster.g","threadId":"58200","inReplyTo":"CAPig+cSgnhzFCUVTQCcTKJK+2qVOpdB2R-Vq1DjqspDJudom4w@mail.gmail.com","subject":"Re: [PATCH v2 4/8] test-lib-functions: add and use test_cmp_cmd","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-12-02T03:41:12Z","receivedAt":"2022-12-02T03:41:18Z","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> Another reason I'm \"meh\" about this function is that it seems too\n> narrowly focussed, insisting that the \"expect\" argument is expressed\n> as a one-liner. (Yes, I know that that is not a hard limitation; a\n> caller can pass in a multiline string, but still...) Maybe I'd be less\n> jaded if it accepted \"expect\" on its stdin. But, even that doesn't\n> seem to buy much. The vast majority of cases where you've converted:\n>\n>     test \"$dir\" = \"$(test-tool path-utils real_path $dir2)\" &&\n>\n> to:\n>\n>     test_cmp_cmd \"$dir\" test-tool path-utils real_path $dir2 &&\n>\n> could just have easily become:\n>\n>     echo \"$dir\" >expect &&\n>     test-tool path-utils real_path $dir2 >actual &&\n>     test_cmp expect actual\n>\n> which isn't bad at all, even if it is one line longer, and it is\n> idiomatic in this test suite.\n\n[jc: updated the rewritten example]\n\nAnd it is crystal clear that \"expect\" and \"actual\" are clobbered\nif written that way.\n"},{"id":"468400","messageId":"CAPig+cR2txMuv1E00TYuYJu=QU4psYi89VromYYKqHZb_7WQpQ@mail.gmail.com","threadId":"58200","inReplyTo":"20221202055905.2rqp26xu4nuknlxw@tb-raspi4","subject":"Re: [PATCH v2 2/8] auto-crlf tests: check \"git checkout\" exit code","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2022-12-02T06:03:49Z","receivedAt":"2022-12-02T06:04:04Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, Dec 2, 2022 at 12:59 AM Torsten Bögershausen <tboegi@web.de> wrote:\n> On Fri, Dec 02, 2022 at 02:02:55AM +0100, René Scharfe wrote:\n> > Side note: The checkout commands only differ in their -c parameter.\n> > They could be unified like this, which might simplify handling their\n> > return code:\n> >\n> >       git ${ceol:+-c core.eol=$ceol} checkout -- crlf_false_attr__$f.txt\n>\n> That is a nice one. (I learned about the ${:+} yesterday).\n> Is it supported by all the shells/os combinations ?\n\n${:+} is well supported. It's POSIX. It's used heavily in the Git test\nsuite already. So, it's safe to use.\n"},{"id":"468401","messageId":"20221202055905.2rqp26xu4nuknlxw@tb-raspi4","threadId":"58200","inReplyTo":"02ead668-5b5d-877c-1e40-3656fd85945f@web.de","subject":"Re: [PATCH v2 2/8] auto-crlf tests: check \"git checkout\" exit code","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2022-12-02T05:59:05Z","receivedAt":"2022-12-02T06:04:23Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"On Fri, Dec 02, 2022 at 02:02:55AM +0100, René Scharfe wrote:\n> Am 02.12.2022 um 01:06 schrieb Ævar Arnfjörð Bjarmason:\n> > Don't hide the exit code from the \"git checkout\" we run to checkout\n> > our attributes file.\n> >\n> > This fixes cases where we'd have e.g. missed memory leaks under\n> > SANITIZE=leak, this code doesn't leak (the relevant \"git checkout\"\n> > leak has been fixed), but in a past version of git we'd continue past\n> > this failure under SANITIZE=leak when these invocations had errored\n> > out, even under \"--immediate\".\n> >\n> > Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> > ---\n> >  t/t0027-auto-crlf.sh | 14 ++++++++++----\n> >  1 file changed, 10 insertions(+), 4 deletions(-)\n> >\n> > diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\n> > index a94ac1eae37..574344a99db 100755\n> > --- a/t/t0027-auto-crlf.sh\n> > +++ b/t/t0027-auto-crlf.sh\n> > @@ -294,11 +294,17 @@ checkout_files () {\n> >  \tpfx=eol_${ceol}_crlf_${crlf}_attr_${attr}_ &&\n> >  \tfor f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul\n> >  \tdo\n> > -\t\trm crlf_false_attr__$f.txt &&\n> > -\t\tif test -z \"$ceol\"; then\n> > -\t\t\tgit checkout -- crlf_false_attr__$f.txt\n> > +\t\tif test -z \"$ceol\"\n> > +\t\tthen\n> > +\t\t\ttest_expect_success \"setup $f checkout\" '\n> > +\t\t\t\trm crlf_false_attr__$f.txt &&\n> > +\t\t\t\tgit checkout -- crlf_false_attr__$f.txt\n> > +\t\t\t'\n> >  \t\telse\n> > -\t\t\tgit -c core.eol=$ceol checkout -- crlf_false_attr__$f.txt\n> > +\t\t\ttest_expect_success \"setup $f checkout with core.eol=$ceol\" '\n> > +\t\t\t\trm crlf_false_attr__$f.txt &&\n> > +\t\t\t\tgit -c core.eol=$ceol checkout -- crlf_false_attr__$f.txt\n> > +\t\t\t'\n>\n> That adds five test_expect_success calls.  Wouldn't one suffice, for the\n> whole for loop, and a \"|| return 1\"?\n>\n> One line above the context there's a \"git config\" call that should also\n> be covered, right?\n>\n> Side note: The checkout commands only differ in their -c parameter.\n> They could be unified like this, which might simplify handling their\n> return code:\n>\n> \tgit ${ceol:+-c core.eol=$ceol} checkout -- crlf_false_attr__$f.txt\n>\n> >  \t\tfi\n> >  \tdone\n> >\n\nThat is a nice one. (I learned about the ${:+} yesterday).\nIs it supported by all the shells/os combinations ?\nIf not, we can still extract the if:\n\n        if test -z \"$ceol\"; then\n          CEOL=\"-c core.eol=$ceol\"\n        else\n          CEOL=\"\"\n        fi\n        git $CEOL checkout -- crlf_false_attr__$f.txt &&\n\n\nThe original reasoning (for not looking at the return code) was that\nif the checkout fails, the test suite will fail further down anyway.\nBut checking for failures early is a good thing.\nThanks for cleaning up my mess.\n"},{"id":"468402","messageId":"221202.865yeugp7e.gmgdl@evledraar.gmail.com","threadId":"58200","inReplyTo":"xmqqwn7apodp.fsf@gitster.g","subject":"Re: [PATCH v2 1/8] log tests: don't use \"exit 1\" outside a sub-shell","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-02T02:45:55Z","receivedAt":"2022-12-02T08:55:11Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Fri, Dec 02 2022, Junio C Hamano wrote:\n\n> Eric Sunshine <sunshine@sunshineco.com> writes:\n>\n>>>                 git show -s --pretty=oneline \"$r\" >raw &&\n>>> -               cat raw | lf_to_nul || exit 1\n>>> +               cat raw | lf_to_nul || return 1\n>>>         done >expect &&\n>>\n>> Using `return 1` here is \"obviously correct\" since this code is not\n>> inside a subshell. Furthermore, the exit code of the for-loop itself\n>> is not being lost down a pipe, so `return 1` is indeed an appropriate\n>> way to signal failure. Good.\n>\n> \"return 1\" is obvious and safe correction.  I have to wonder if\n> test_expect_success can be taught to be smarter to intercept \"exit\"\n> so we do not have to bo so careful, but that would be a much more\n> involved change to the lower-level of test framework.\n\nI can't think of a way to do so that wouldn't involve running the test\nin a sub-shell, which I think would bring us to the state management\nproblems noted in [1] for Phillip's \"test_todo\" series, except in this\ncase we'd have those issues trying to pass state back from the\n\"test_expect_success\".\n\nIt's possible, but we'd need to change a lot of code that's expecting to\ntalk to itself via variables in the same shell to use IPC between\nshells, wouldn't we?\n\n1. https://lore.kernel.org/git/221006.86v8owr986.gmgdl@evledraar.gmail.com/\n"},{"id":"468403","messageId":"CAPig+cQvqPgo1UKbAAtyz8UVJZiwrG7j+kAokMEimv1E62pR0A@mail.gmail.com","threadId":"58200","inReplyTo":"221202.865yeugp7e.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH v2 1/8] log tests: don't use \"exit 1\" outside a sub-shell","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2022-12-02T09:03:54Z","receivedAt":"2022-12-02T09:04:42Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, Dec 2, 2022 at 3:55 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n> On Fri, Dec 02 2022, Junio C Hamano wrote:\n> > \"return 1\" is obvious and safe correction.  I have to wonder if\n> > test_expect_success can be taught to be smarter to intercept \"exit\"\n> > so we do not have to bo so careful, but that would be a much more\n> > involved change to the lower-level of test framework.\n>\n> I can't think of a way to do so that wouldn't involve running the test\n> in a sub-shell, which I think would bring us to the state management\n> problems noted in [1] for Phillip's \"test_todo\" series, except in this\n> case we'd have those issues trying to pass state back from the\n> \"test_expect_success\".\n>\n> It's possible, but we'd need to change a lot of code that's expecting to\n> talk to itself via variables in the same shell to use IPC between\n> shells, wouldn't we?\n\nIt might make more sense to turn this on its head and make it a\nlinting issue and simply throw a \"?!FOO?!\" as is done for other\nsuspect shell code. In fact, I already have local chainlint.pl patches\nwhich detect whether a subshell is active so that the linter can\ncomplain if it sees `cd` outside of a subshell. I would think that\nwarning about misuse of `exit 1` outside a subshell (and perhaps\n`return 1` inside a subshell) should be possible, though I haven't\nthought through all the possibilities.\n"},{"id":"468405","messageId":"221202.861qpiglto.gmgdl@evledraar.gmail.com","threadId":"58200","inReplyTo":"CAPig+cQvqPgo1UKbAAtyz8UVJZiwrG7j+kAokMEimv1E62pR0A@mail.gmail.com","subject":"Re: [PATCH v2 1/8] log tests: don't use \"exit 1\" outside a sub-shell","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-02T10:02:28Z","receivedAt":"2022-12-02T10:08:12Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Fri, Dec 02 2022, Eric Sunshine wrote:\n\n> On Fri, Dec 2, 2022 at 3:55 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n>> On Fri, Dec 02 2022, Junio C Hamano wrote:\n>> > \"return 1\" is obvious and safe correction.  I have to wonder if\n>> > test_expect_success can be taught to be smarter to intercept \"exit\"\n>> > so we do not have to bo so careful, but that would be a much more\n>> > involved change to the lower-level of test framework.\n>>\n>> I can't think of a way to do so that wouldn't involve running the test\n>> in a sub-shell, which I think would bring us to the state management\n>> problems noted in [1] for Phillip's \"test_todo\" series, except in this\n>> case we'd have those issues trying to pass state back from the\n>> \"test_expect_success\".\n>>\n>> It's possible, but we'd need to change a lot of code that's expecting to\n>> talk to itself via variables in the same shell to use IPC between\n>> shells, wouldn't we?\n>\n> It might make more sense to turn this on its head and make it a\n> linting issue and simply throw a \"?!FOO?!\" as is done for other\n> suspect shell code. In fact, I already have local chainlint.pl patches\n> which detect whether a subshell is active so that the linter can\n> complain if it sees `cd` outside of a subshell. I would think that\n> warning about misuse of `exit 1` outside a subshell (and perhaps\n> `return 1` inside a subshell) should be possible, though I haven't\n> thought through all the possibilities.\n\nThat would be great. As a reminder I think (maybe it's not what you have\nin mind exactly?) that we had a brief discussion on this topic starting\nat [1]. I.e. I was hoping chainlint.pl could be extended to detect\nexactly these sort of \"test...$(git\" patterns (among other things).\n\nThis topic doesn't get us there, but once we finally get rid of some of\nthose patterns it would be nice to have assertions to ensure they don't\ncome back.\n\n1. https://lore.kernel.org/git/221024.865yg9ecsx.gmgdl@evledraar.gmail.com/\n"},{"id":"468424","messageId":"patch-v3-1.8-64dfec31fb3-20221202T114733Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v3-0.8-00000000000-20221202T114733Z-avarab@gmail.com","subject":"[PATCH v3 1/8] merge tests: don't ignore \"rev-parse\" exit code in helper","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-02T11:52:34Z","receivedAt":"2022-12-02T11:53:52Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the verify_mergeheads() helper the check the exit code of \"git\nrev-parse\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t7600-merge.sh | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/t/t7600-merge.sh b/t/t7600-merge.sh\nindex 7c3f6ed9943..060e145957f 100755\n--- a/t/t7600-merge.sh\n+++ b/t/t7600-merge.sh\n@@ -105,7 +105,7 @@ verify_mergeheads () {\n \ttest_write_lines \"$@\" >mergehead.expected &&\n \twhile read sha1 rest\n \tdo\n-\t\tgit rev-parse $sha1\n+\t\tgit rev-parse $sha1 || return 1\n \tdone <.git/MERGE_HEAD >mergehead.actual &&\n \ttest_cmp mergehead.expected mergehead.actual\n }\n-- \n2.39.0.rc1.981.gf846af54b4b\n\n"},{"id":"468425","messageId":"cover-v3-0.8-00000000000-20221202T114733Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v2-0.8-00000000000-20221202T000227Z-avarab@gmail.com","subject":"[PATCH v3 0/8] tests: fix ignored & hidden exit codes","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-02T11:52:33Z","receivedAt":"2022-12-02T11:53:54Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Various fixes for \"git\" on the LHS of a pipe, but mostly when in\n\"test\" expressions like:\n\n\ttest str = \"$(git some-command)\" &&\n\nChanges since v2\n(https://lore.kernel.org/git/cover-v2-0.8-00000000000-20221202T000227Z-avarab@gmail.com/):\n\n * Ejected 1/8, as René's identical patch has been queued in \"seen\"\n * The \"test_cmp_cmd\" helper is gone, instead we just use the same\n   three echo/git/test_cmp lines every time.\n\n   I agree that introducing a new helper with some odd semantics was\n   probably not a good idea at this time.  It would be nice to do some\n   of these as one line, but that probably doesn't justify the helper.\n\n * Since we're not using the helper the latter part of this series is\n   now split up by the category of fix.\n * Rewrote the t0027-auto-crlf.sh commit to address the concerns\n   raised.\n * Avid removing redundant code from t7600-merge.sh, and just fix the\n   hidden exit code.\n * Small bits here and there, which I think should collectively\n   address all outstanding feedback on the v2. Thank all!\n\nÆvar Arnfjörð Bjarmason (8):\n  merge tests: don't ignore \"rev-parse\" exit code in helper\n  auto-crlf tests: don't lose exit code in loops and outside tests\n  diff tests: fix ignored exit codes in t4023\n  t/lib-patch-mode.sh: fix ignored exit codes\n  tests: use \"test_cmp\" instead of \"test\" in sub-shells\n  tests: don't lose 'test <str> = $(cmd ...)\"' exit code\n  tests: don't lose \"git\" exit codes in \"! ( git ... | grep )\"\n  tests: don't lose mist \"git\" exit codes\n\n t/lib-httpd.sh                     |   5 +-\n t/lib-patch-mode.sh                |  11 ++-\n t/lib-submodule-update.sh          |  26 ++++---\n t/t0001-init.sh                    |   9 ++-\n t/t0002-gitfile.sh                 |   4 +-\n t/t0027-auto-crlf.sh               |  60 +++++++++-------\n t/t0055-beyond-symlinks.sh         |  14 +++-\n t/t0060-path-utils.sh              | 107 +++++++++++++++++++++--------\n t/t0100-previous.sh                |   8 ++-\n t/t1401-symbolic-ref.sh            |   3 +-\n t/t1504-ceiling-dirs.sh            |   8 ++-\n t/t2005-checkout-index-symlinks.sh |   8 ++-\n t/t3200-branch.sh                  |  13 ++--\n t/t3700-add.sh                     |  18 +++--\n t/t3701-add-interactive.sh         |   8 ++-\n t/t4023-diff-rename-typechange.sh  |  12 ++--\n t/t5522-pull-symlink.sh            |   4 +-\n t/t5605-clone-local.sh             |  15 ++--\n t/t7402-submodule-rebase.sh        |  23 +++++--\n t/t7504-commit-msg-hook.sh         |   4 +-\n t/t7516-commit-races.sh            |   3 +-\n t/t7600-merge.sh                   |   2 +-\n t/t7810-grep.sh                    |   4 +-\n 23 files changed, 246 insertions(+), 123 deletions(-)\n\nRange-diff against v2:\n1:  7c9f8d2830f < -:  ----------- log tests: don't use \"exit 1\" outside a sub-shell\n6:  5715ff7f0f7 ! 1:  64dfec31fb3 merge tests: don't ignore \"rev-parse\" exit code in helper\n    @@ Commit message\n         merge tests: don't ignore \"rev-parse\" exit code in helper\n     \n         Change the verify_mergeheads() helper the check the exit code of \"git\n    -    rev-parse\". The \"$rest\" variable added in 274a5c06d52 (merge: record\n    -    tag objects without peeling in MERGE_HEAD, 2011-11-07) wasn't being\n    -    used.\n    -\n    -    Such a thing is needed to support the .git/MERGE_HEAD format in\n    -    general, but in this case we have no such addition to the line. So\n    -    let's compare with \"test_cmp\" instead, we can always add back this\n    -    \"$rest\" parsing if it's needed in the future.\n    +    rev-parse\".\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## t/t7600-merge.sh ##\n    -@@ t/t7600-merge.sh: verify_parents () {\n    - }\n    - \n    - verify_mergeheads () {\n    --\ttest_write_lines \"$@\" >mergehead.expected &&\n    --\twhile read sha1 rest\n    -+\tfor rev in \"$@\"\n    +@@ t/t7600-merge.sh: verify_mergeheads () {\n    + \ttest_write_lines \"$@\" >mergehead.expected &&\n    + \twhile read sha1 rest\n      \tdo\n     -\t\tgit rev-parse $sha1\n    --\tdone <.git/MERGE_HEAD >mergehead.actual &&\n    --\ttest_cmp mergehead.expected mergehead.actual\n    -+\t\tgit rev-parse $rev || return 1\n    -+\tdone >mergehead.expected &&\n    -+\ttest_cmp mergehead.expected .git/MERGE_HEAD\n    ++\t\tgit rev-parse $sha1 || return 1\n    + \tdone <.git/MERGE_HEAD >mergehead.actual &&\n    + \ttest_cmp mergehead.expected mergehead.actual\n      }\n    - \n    - verify_no_mergehead () {\n2:  345a667d5bb ! 2:  394d5e46494 auto-crlf tests: check \"git checkout\" exit code\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    auto-crlf tests: check \"git checkout\" exit code\n    +    auto-crlf tests: don't lose exit code in loops and outside tests\n     \n    -    Don't hide the exit code from the \"git checkout\" we run to checkout\n    -    our attributes file.\n    +    Change the functions which are called from within\n    +    \"test_expect_success\" to add the \"|| return 1\" idiom to their\n    +    for-loops, so we won't lose the exit code of \"cp\", \"git\" etc.\n     \n    -    This fixes cases where we'd have e.g. missed memory leaks under\n    +    Then for those setup functions that aren't called from a\n    +    \"test_expect_success\" we need to put the setup code in a\n    +    \"test_expect_success\" as well. It would not be enough to properly\n    +    &&-chain these, as the calling code is the top-level script itself. As\n    +    we don't run the tests with \"set -e\" we won't report failing commands\n    +    at the top-level.\n    +\n    +    The \"checkout\" part of this would miss memory leaks under\n         SANITIZE=leak, this code doesn't leak (the relevant \"git checkout\"\n         leak has been fixed), but in a past version of git we'd continue past\n         this failure under SANITIZE=leak when these invocations had errored\n         out, even under \"--immediate\".\n     \n    +    Helped-by: René Scharfe <l.s.r@web.de>\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## t/t0027-auto-crlf.sh ##\n    +@@ t/t0027-auto-crlf.sh: create_NNO_MIX_files () {\n    + \t\t\t\tcp CRLF        ${pfx}_CRLF.txt &&\n    + \t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt &&\n    + \t\t\t\tcp LF_mix_CR   ${pfx}_LF_mix_CR.txt &&\n    +-\t\t\t\tcp CRLF_nul    ${pfx}_CRLF_nul.txt\n    ++\t\t\t\tcp CRLF_nul    ${pfx}_CRLF_nul.txt ||\n    ++\t\t\t\treturn 1\n    + \t\t\tdone\n    + \t\tdone\n    + \tdone\n    +@@ t/t0027-auto-crlf.sh: commit_check_warn () {\n    + \tdo\n    + \t\tfname=${pfx}_$f.txt &&\n    + \t\tcp $f $fname &&\n    +-\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\"\n    ++\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\" ||\n    ++\t\treturn 1\n    + \tdone &&\n    + \tgit commit -m \"core.autocrlf $crlf\" &&\n    + \tcheck_warning \"$lfname\" ${pfx}_LF.err &&\n    +@@ t/t0027-auto-crlf.sh: commit_chk_wrnNNO () {\n    + \tlfmixcr=$1 ; shift\n    + \tcrlfnul=$1 ; shift\n    + \tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n    +-\t#Commit files on top of existing file\n    +-\tcreate_gitattributes \"$attr\" $aeol &&\n    +-\tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n    +-\tdo\n    +-\t\tfname=${pfx}_$f.txt &&\n    +-\t\tcp $f $fname &&\n    +-\t\tprintf Z >>\"$fname\" &&\n    +-\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\"\n    +-\tdone\n    ++\n    ++\ttest_expect_success 'setup commit NNO files' '\n    ++\t\t#Commit files on top of existing file\n    ++\t\tcreate_gitattributes \"$attr\" $aeol &&\n    ++\t\tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n    ++\t\tdo\n    ++\t\t\tfname=${pfx}_$f.txt &&\n    ++\t\t\tcp $f $fname &&\n    ++\t\t\tprintf Z >>\"$fname\" &&\n    ++\t\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\" ||\n    ++\t\t\treturn 1\n    ++\t\tdone\n    ++\t'\n    + \n    + \ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr LF\" '\n    + \t\tcheck_warning \"$lfwarn\" ${pfx}_LF.err\n    +@@ t/t0027-auto-crlf.sh: commit_MIX_chkwrn () {\n    + \tlfmixcr=$1 ; shift\n    + \tcrlfnul=$1 ; shift\n    + \tpfx=MIX_attr_${attr}_aeol_${aeol}_${crlf}\n    +-\t#Commit file with CLRF_mix_LF on top of existing file\n    +-\tcreate_gitattributes \"$attr\" $aeol &&\n    +-\tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n    +-\tdo\n    +-\t\tfname=${pfx}_$f.txt &&\n    +-\t\tcp CRLF_mix_LF $fname &&\n    +-\t\tprintf Z >>\"$fname\" &&\n    +-\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\"\n    +-\tdone\n    ++\n    ++\ttest_expect_success 'setup commit file with mixed EOL' '\n    ++\t\t#Commit file with CLRF_mix_LF on top of existing file\n    ++\t\tcreate_gitattributes \"$attr\" $aeol &&\n    ++\t\tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n    ++\t\tdo\n    ++\t\t\tfname=${pfx}_$f.txt &&\n    ++\t\t\tcp CRLF_mix_LF $fname &&\n    ++\t\t\tprintf Z >>\"$fname\" &&\n    ++\t\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\" ||\n    ++\t\t\treturn 1\n    ++\t\tdone\n    ++\t'\n    + \n    + \ttest_expect_success \"commit file with mixed EOL onto LF crlf=$crlf attr=$attr\" '\n    + \t\tcheck_warning \"$lfwarn\" ${pfx}_LF.err\n     @@ t/t0027-auto-crlf.sh: checkout_files () {\n      \tpfx=eol_${ceol}_crlf_${crlf}_attr_${attr}_ &&\n      \tfor f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul\n    @@ t/t0027-auto-crlf.sh: checkout_files () {\n     -\t\trm crlf_false_attr__$f.txt &&\n     -\t\tif test -z \"$ceol\"; then\n     -\t\t\tgit checkout -- crlf_false_attr__$f.txt\n    -+\t\tif test -z \"$ceol\"\n    -+\t\tthen\n    -+\t\t\ttest_expect_success \"setup $f checkout\" '\n    -+\t\t\t\trm crlf_false_attr__$f.txt &&\n    -+\t\t\t\tgit checkout -- crlf_false_attr__$f.txt\n    -+\t\t\t'\n    - \t\telse\n    +-\t\telse\n     -\t\t\tgit -c core.eol=$ceol checkout -- crlf_false_attr__$f.txt\n    -+\t\t\ttest_expect_success \"setup $f checkout with core.eol=$ceol\" '\n    -+\t\t\t\trm crlf_false_attr__$f.txt &&\n    -+\t\t\t\tgit -c core.eol=$ceol checkout -- crlf_false_attr__$f.txt\n    -+\t\t\t'\n    - \t\tfi\n    +-\t\tfi\n    ++\t\ttest_expect_success \"setup $f checkout ${ceol:+ with -c core.eol=$ceol}\"  '\n    ++\t\t\trm -f crlf_false_attr__$f.txt &&\n    ++\t\t\tgit ${ceol:+-c core.eol=$ceol} checkout -- crlf_false_attr__$f.txt\n    ++\t\t'\n      \tdone\n      \n    + \ttest_expect_success \"ls-files --eol attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol\" '\n3:  c5feef1c808 = 3:  4ec075689f6 diff tests: fix ignored exit codes in t4023\n5:  f826a336c3d ! 4:  c080899dd5f t/lib-patch-mode.sh: fix ignored \"git\" exit codes\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    t/lib-patch-mode.sh: fix ignored \"git\" exit codes\n    +    t/lib-patch-mode.sh: fix ignored exit codes\n     \n         Fix code added in b319ef70a94 (Add a small patch-mode testing library,\n    -    2009-08-13) to use &&-chaining and the newly added \"test_cmp_cmd\"\n    -    instead of interpolating \"git\" commands in a \"test\" statement.\n    +    2009-08-13) to use &&-chaining and the newly added \"test_cmp_cmd\".\n    +    This avoids losing both the exit code of a \"git\" and the \"cat\"\n    +    processes.\n     \n         This fixes cases where we'd have e.g. missed memory leaks under\n         SANITIZE=leak, this code doesn't leak now as far as I can tell, but I\n    @@ t/lib-patch-mode.sh: set_and_save_state () {\n     -\ttest \"$(cat \"$1\")\" = \"$2\" &&\n     -\ttest \"$(git show :\"$1\")\" = \"$3\"\n     +\techo \"$2\" >expect &&\n    -+\tcat \"$1\" >actual &&\n    -+\ttest_cmp expect actual &&\n    ++\ttest_cmp expect \"$1\" &&\n     +\n    -+\ttest_cmp_cmd \"$3\" git show :\"$1\"\n    ++\techo \"$3\" >expect &&\n    ++\tgit show :\"$1\" >actual &&\n    ++\ttest_cmp expect actual\n      }\n      \n      # verify_saved_state <path>\n    @@ t/lib-patch-mode.sh: save_head () {\n      \n      verify_saved_head () {\n     -\ttest \"$(cat _head)\" = \"$(git rev-parse HEAD)\"\n    -+\ttest_cmp_cmd \"$(cat _head)\" git rev-parse HEAD\n    ++\tgit rev-parse HEAD >actual &&\n    ++\ttest_cmp _head actual\n      }\n7:  d090478aa84 ! 5:  58ac6fe5604 tests: use \"test_cmp_cmd\" instead of \"test\" in sub-shells\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    tests: use \"test_cmp_cmd\" instead of \"test\" in sub-shells\n    +    tests: use \"test_cmp\" instead of \"test\" in sub-shells\n     \n         Convert a few cases where we were using \"test\" inside a sub-shell, and\n         were losing the exit code of \"git\".\n    @@ t/lib-httpd.sh: test_http_push_nonff () {\n      \t\ttest_must_fail git push -v origin >output 2>&1 &&\n     -\t\t(cd \"$REMOTE_REPO\" &&\n     -\t\t test $HEAD = $(git rev-parse --verify HEAD))\n    -+\t\ttest_cmp_cmd \"$HEAD\" git -C \"$REMOTE_REPO\" rev-parse --verify HEAD\n    ++\t\techo \"$HEAD\" >expect &&\n    ++\t\tgit -C \"$REMOTE_REPO\" rev-parse --verify HEAD >actual &&\n    ++\t\ttest_cmp expect actual\n      \t'\n      \n      \ttest_expect_success 'non-fast-forward push show ref status' '\n    @@ t/lib-submodule-update.sh: replace_gitfile_with_git_dir () {\n     -\t\tgit config --unset core.worktree\n     -\t) &&\n     +\t# does core.worktree point at the right place?\n    -+\ttest_cmp_cmd \"../../../$1\" git -C \".git/modules/$1\" config core.worktree\n    ++\techo \"../../../$1\" >expect &&\n    ++\tgit -C \".git/modules/$1\" config core.worktree >actual &&\n    ++\ttest_cmp expect actual &&\n     +\t# remove it temporarily before comparing, as\n     +\t# \"$1/.git/config\" lacks it...\n     +\tgit -C \".git/modules/$1\" config --unset core.worktree &&\n    @@ t/lib-submodule-update.sh: replace_gitfile_with_git_dir () {\n      \n      test_git_directory_exists () {\n     \n    + ## t/t0060-path-utils.sh ##\n    +@@ t/t0060-path-utils.sh: test_expect_success 'prefix_path rejects absolute path to dir with same beginnin\n    + test_expect_success SYMLINKS 'prefix_path works with absolute path to a symlink to work tree having  same beginning as work tree' '\n    + \tgit init repo &&\n    + \tln -s repo repolink &&\n    +-\ttest \"a\" = \"$(cd repo && test-tool path-utils prefix_path prefix \"$(pwd)/../repolink/a\")\"\n    ++\techo \"a\" >expect &&\n    ++\ttest-tool -C repo path-utils prefix_path prefix \"$(cd repo && pwd)/../repolink/a\" >actual &&\n    ++\ttest_cmp expect actual\n    + '\n    + \n    + relative_path /foo/a/b/c/\t/foo/a/b/\tc/\n    +\n      ## t/t3200-branch.sh ##\n     @@ t/t3200-branch.sh: test_expect_success 'git branch -M baz bam should succeed when baz is checked ou\n      test_expect_success 'git branch -M baz bam should succeed within a worktree in which baz is checked out' '\n    @@ t/t3200-branch.sh: test_expect_success 'git branch -M baz bam should succeed whe\n     -\t) &&\n     -\ttest $(git rev-parse --abbrev-ref HEAD) = bam &&\n     +\tgit -C \"$bazdir\" branch -M baz bam &&\n    -+\ttest_cmp_cmd \"bam\" git -C \"$bazdir\" rev-parse --abbrev-ref HEAD &&\n    -+\ttest_cmp_cmd \"bam\" git rev-parse --abbrev-ref HEAD &&\n    ++\techo \"bam\" >expect &&\n    ++\tgit -C \"$bazdir\" rev-parse --abbrev-ref HEAD >actual &&\n    ++\ttest_cmp expect actual &&\n    ++\techo \"bam\" >expect &&\n    ++\tgit rev-parse --abbrev-ref HEAD >actual &&\n    ++\ttest_cmp expect actual &&\n      \trm -r bazdir &&\n      \tgit worktree prune\n      '\n    @@ t/t5605-clone-local.sh: test_expect_success 'preparing origin repository' '\n      \tgit clone --bare . x &&\n     -\ttest \"$(cd a.git && git config --bool core.bare)\" = true &&\n     -\ttest \"$(cd x && git config --bool core.bare)\" = true &&\n    -+\ttest_cmp_cmd true git -C a.git config --bool core.bare &&\n    -+\ttest_cmp_cmd true git -C x config --bool core.bare &&\n    ++\techo true >expect &&\n    ++\tgit -C a.git config --bool core.bare >actual &&\n    ++\ttest_cmp expect actual &&\n    ++\techo true >expect &&\n    ++\tgit -C x config --bool core.bare >actual &&\n    ++\ttest_cmp expect actual &&\n      \tgit bundle create b1.bundle --all &&\n      \tgit bundle create b2.bundle main &&\n      \tmkdir dir &&\n    @@ t/t5605-clone-local.sh: test_expect_success 'preparing origin repository' '\n     -\t(cd b &&\n     -\ttest \"$(git config --bool core.bare)\" = false &&\n     -\tgit fetch)\n    -+\ttest_cmp_cmd false git -C b config --bool core.bare &&\n    ++\techo false >expect &&\n    ++\tgit -C b config --bool core.bare >actual &&\n    ++\ttest_cmp expect actual &&\n     +\tgit -C b fetch\n      '\n      \n    @@ t/t7402-submodule-rebase.sh: test_expect_success 'stash with a dirty submodule'\n      \ttest new != $(cat file) &&\n     -\ttest submodule = $(git diff --name-only) &&\n     -\ttest $CURRENT = $(cd submodule && git rev-parse HEAD) &&\n    -+\ttest_cmp_cmd submodule git diff --name-only &&\n    -+\ttest_cmp_cmd \"$CURRENT\" git -C submodule rev-parse HEAD &&\n    ++\techo submodule >expect &&\n    ++\tgit diff --name-only >actual &&\n    ++\ttest_cmp expect actual &&\n    ++\n    ++\techo \"$CURRENT\" >expect &&\n    ++\tgit -C submodule rev-parse HEAD >actual &&\n    ++\ttest_cmp expect actual &&\n    ++\n      \tgit stash apply &&\n      \ttest new = $(cat file) &&\n     -\ttest $CURRENT = $(cd submodule && git rev-parse HEAD)\n    -+\ttest_cmp_cmd \"$CURRENT\" git -C submodule rev-parse HEAD\n    ++\techo \"$CURRENT\" >expect &&\n    ++\tgit -C submodule rev-parse HEAD >actual &&\n    ++\ttest_cmp expect actual\n      \n      '\n      \n4:  c36060934a6 ! 6:  51f32b42ce6 test-lib-functions: add and use test_cmp_cmd\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    test-lib-functions: add and use test_cmp_cmd\n    +    tests: don't lose 'test <str> = $(cmd ...)\"' exit code\n     \n    -    Add a \"test_cmp_cmd\" helper for the common pattern discussed in the\n    -    documentation being added here to \"t/test-lib-functions.sh\".\n    +    Convert some cases in the test suite where we'd lose the exit code of\n    +    a command being interpolated as one of the arguments to the \"test\"\n    +    builtin function to use &&-chaining and \"test_cmp\" instead.\n     \n    -    This implementation leaves the door open for extending this helper\n    -    past its obvious limitations, such as:\n    +    This way we won't lose the exit code, and the failure output will be\n    +    more helpful.\n     \n    -            test_cmp_cmd \"some\" \"lines\" -- <some-cmd>\n    -            test_cmp_cmd --stdin <some-cmd> <expect\n    -            test_cmp_cmd --ignore-stderr \"output\" <some-cmd>\n    -\n    -    By using this in we'll catch cases where \"git\" or \"test-tool\"\n    -    errors (such as segfaults or abort()) were previously hidden, and we'd\n    -    either pass the test, or fail in some subsequent assertion.\n    +    In the case of \"t0060-path-utils.sh\" and\n    +    \"t2005-checkout-index-symlinks.sh\" convert the relevant code to using\n    +    the modern style of indentation and newline wrapping while having to\n    +    change it.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n    @@ t/lib-submodule-update.sh: test_git_directory_exists () {\n      \tthen\n      \t\t# does core.worktree point at the right place?\n     -\t\ttest \"$(git -C .git/modules/$1 config core.worktree)\" = \"../../../$1\"\n    -+\t\ttest_cmp_cmd \"../../../$1\" git -C \".git/modules/$1\" config core.worktree\n    ++\t\techo \"../../../$1\" >expect &&\n    ++\t\tgit -C \".git/modules/$1\" config core.worktree >actual &&\n    ++\t\ttest_cmp expect actual\n      \tfi\n      }\n      \n    @@ t/t0001-init.sh: test_expect_success 'invalid default branch name' '\n      \tgit init rename-initial &&\n      \tgit -C rename-initial branch -m renamed &&\n     -\ttest renamed = $(git -C rename-initial symbolic-ref --short HEAD) &&\n    -+\ttest_cmp_cmd renamed git -C rename-initial symbolic-ref --short HEAD &&\n    ++\techo renamed >expect &&\n    ++\tgit -C rename-initial symbolic-ref --short HEAD >actual &&\n    ++\ttest_cmp expect actual &&\n    ++\n      \tgit -C rename-initial branch -m renamed again &&\n     -\ttest again = $(git -C rename-initial symbolic-ref --short HEAD)\n    -+\ttest_cmp_cmd again git -C rename-initial symbolic-ref --short HEAD\n    ++\techo again >expect &&\n    ++\tgit -C rename-initial symbolic-ref --short HEAD >actual &&\n    ++\ttest_cmp expect actual\n      '\n      \n      test_done\n    @@ t/t0002-gitfile.sh: test_expect_success 'bad setup: invalid .git file path' '\n      test_expect_success 'final setup + check rev-parse --git-dir' '\n      \techo \"gitdir: $REAL\" >.git &&\n     -\ttest \"$REAL\" = \"$(git rev-parse --git-dir)\"\n    -+\ttest_cmp_cmd \"$REAL\" git rev-parse --git-dir\n    ++\techo \"$REAL\" >expect &&\n    ++\tgit rev-parse --git-dir >actual &&\n    ++\ttest_cmp expect actual\n      '\n      \n      test_expect_success 'check hash-object' '\n    @@ t/t0060-path-utils.sh: TEST_PASSES_SANITIZE_LEAK=true\n     -\ttest_expect_success $3 \"normalize path: $1 => $2\" \\\n     -\t\"test \\\"\\$(test-tool path-utils normalize_path_copy '$1')\\\" = '$expected'\"\n     +\ttest_expect_success $3 \"normalize path: $1 => $2\" \"\n    -+\t\ttest_cmp_cmd '$expected' test-tool path-utils normalize_path_copy '$1'\n    ++\t\techo '$expected' >expect &&\n    ++\t\ttest-tool path-utils normalize_path_copy '$1' >actual &&\n    ++\t\ttest_cmp expect actual\n     +\t\"\n      }\n      \n    @@ t/t0060-path-utils.sh: TEST_PASSES_SANITIZE_LEAK=true\n     -\ttest_expect_success $4 \"relative path: $1 $2 => $3\" \\\n     -\t\"test \\\"\\$(test-tool path-utils relative_path '$1' '$2')\\\" = '$expected'\"\n     +\ttest_expect_success $4 \"relative path: $1 $2 => $3\" \"\n    -+\t\ttest_cmp_cmd '$expected' test-tool path-utils relative_path '$1' '$2'\n    ++\t\techo '$expected' >expect &&\n    ++\t\ttest-tool path-utils relative_path '$1' '$2' >actual &&\n    ++\t\ttest_cmp expect actual\n     +\t\"\n      }\n      \n    @@ t/t0060-path-utils.sh: TEST_PASSES_SANITIZE_LEAK=true\n      \ttest_expect_success \"test_submodule_relative_url: $1 $2 $3 => $4\" \"\n     -\t\tactual=\\$(test-tool submodule resolve-relative-url '$1' '$2' '$3') &&\n     -\t\ttest \\\"\\$actual\\\" = '$4'\n    -+\t\ttest_cmp_cmd '$4' test-tool submodule resolve-relative-url '$1' '$2' '$3'\n    ++\t\techo '$4' >expect &&\n    ++\t\ttest-tool submodule resolve-relative-url '$1' '$2' '$3' >actual &&\n    ++\t\ttest_cmp expect actual\n      \t\"\n      }\n      \n    @@ t/t0060-path-utils.sh: ancestor() {\n     -\t\"actual=\\$(test-tool path-utils longest_ancestor_length '$1' '$2') &&\n     -\t test \\\"\\$actual\\\" = '$expected'\"\n     +\ttest_expect_success $4 \"longest ancestor: $1 $2 => $expected\" \"\n    -+\t\ttest_cmp_cmd '$expected' test-tool path-utils longest_ancestor_length '$1' '$2'\n    ++\t\techo '$expected' >expect &&\n    ++\t\ttest-tool path-utils longest_ancestor_length '$1' '$2' >actual &&\n    ++\t\ttest_cmp expect actual\n     +\t\"\n      }\n      \n    @@ t/t0060-path-utils.sh: ancestor D:/Users/me C:/ -1 MINGW\n      \n      test_expect_success 'absolute path rejects the empty string' '\n     @@ t/t0060-path-utils.sh: test_expect_success 'real path rejects the empty string' '\n    + '\n      \n      test_expect_success POSIX 'real path works on absolute paths 1' '\n    ++\techo / >expect &&\n    ++\ttest-tool path-utils real_path \"/\" >actual &&\n    ++\ttest_cmp expect actual &&\n    ++\n      \tnopath=\"hopefully-absent-path\" &&\n     -\ttest \"/\" = \"$(test-tool path-utils real_path \"/\")\" &&\n     -\ttest \"/$nopath\" = \"$(test-tool path-utils real_path \"/$nopath\")\"\n    -+\ttest_cmp_cmd / test-tool path-utils real_path \"/\" &&\n    -+\ttest_cmp_cmd \"/$nopath\" test-tool path-utils real_path \"/$nopath\"\n    ++\techo \"/$nopath\" >expect &&\n    ++\ttest-tool path-utils real_path \"/$nopath\" >actual &&\n    ++\ttest_cmp expect actual\n      '\n      \n      test_expect_success 'real path works on absolute paths 2' '\n    - \tnopath=\"hopefully-absent-path\" &&\n    +-\tnopath=\"hopefully-absent-path\" &&\n      \t# Find an existing top-level directory for the remaining tests:\n      \td=$(pwd -P | sed -e \"s|^\\([^/]*/[^/]*\\)/.*|\\1|\") &&\n     -\ttest \"$d\" = \"$(test-tool path-utils real_path \"$d\")\" &&\n     -\ttest \"$d/$nopath\" = \"$(test-tool path-utils real_path \"$d/$nopath\")\"\n    -+\ttest_cmp_cmd \"$d\" test-tool path-utils real_path \"$d\" &&\n    -+\ttest_cmp_cmd \"$d/$nopath\" test-tool path-utils real_path \"$d/$nopath\"\n    ++\techo \"$d\" >expect &&\n    ++\ttest-tool path-utils real_path \"$d\" >actual &&\n    ++\ttest_cmp expect actual &&\n    ++\n    ++\tnopath=\"hopefully-absent-path\" &&\n    ++\techo \"$d/$nopath\" >expect &&\n    ++\ttest-tool path-utils real_path \"$d/$nopath\" >actual &&\n    ++\ttest_cmp expect actual\n      '\n      \n      test_expect_success POSIX 'real path removes extra leading slashes' '\n    ++\techo \"/\" >expect &&\n    ++\ttest-tool path-utils real_path \"///\" >actual &&\n    ++\ttest_cmp expect actual &&\n    ++\n      \tnopath=\"hopefully-absent-path\" &&\n     -\ttest \"/\" = \"$(test-tool path-utils real_path \"///\")\" &&\n     -\ttest \"/$nopath\" = \"$(test-tool path-utils real_path \"///$nopath\")\" &&\n    -+\ttest_cmp_cmd \"/\" test-tool path-utils real_path \"///\" &&\n    -+\ttest_cmp_cmd \"/$nopath\" test-tool path-utils real_path \"///$nopath\" &&\n    ++\techo \"/$nopath\" >expect &&\n    ++\ttest-tool path-utils real_path \"///$nopath\" >actual &&\n    ++\ttest_cmp expect actual &&\n    ++\n      \t# Find an existing top-level directory for the remaining tests:\n      \td=$(pwd -P | sed -e \"s|^\\([^/]*/[^/]*\\)/.*|\\1|\") &&\n     -\ttest \"$d\" = \"$(test-tool path-utils real_path \"//$d\")\" &&\n     -\ttest \"$d/$nopath\" = \"$(test-tool path-utils real_path \"//$d/$nopath\")\"\n    -+\ttest_cmp_cmd \"$d\" test-tool path-utils real_path \"//$d\" &&\n    -+\ttest_cmp_cmd \"$d/$nopath\" test-tool path-utils real_path \"//$d/$nopath\"\n    ++\techo \"$d\" >expect &&\n    ++\ttest-tool path-utils real_path \"//$d\" >actual &&\n    ++\ttest_cmp expect actual &&\n    ++\n    ++\techo \"$d/$nopath\" >expect &&\n    ++\ttest-tool path-utils real_path \"//$d/$nopath\" >actual &&\n    ++\ttest_cmp expect actual\n      '\n      \n      test_expect_success 'real path removes other extra slashes' '\n    - \tnopath=\"hopefully-absent-path\" &&\n    +-\tnopath=\"hopefully-absent-path\" &&\n      \t# Find an existing top-level directory for the remaining tests:\n      \td=$(pwd -P | sed -e \"s|^\\([^/]*/[^/]*\\)/.*|\\1|\") &&\n     -\ttest \"$d\" = \"$(test-tool path-utils real_path \"$d///\")\" &&\n     -\ttest \"$d/$nopath\" = \"$(test-tool path-utils real_path \"$d///$nopath\")\"\n    -+\ttest_cmp_cmd \"$d\" test-tool path-utils real_path \"$d///\" &&\n    -+\ttest_cmp_cmd \"$d/$nopath\" test-tool path-utils real_path \"$d///$nopath\"\n    ++\techo \"$d\" >expect &&\n    ++\ttest-tool path-utils real_path \"$d///\" >actual &&\n    ++\ttest_cmp expect actual &&\n    ++\n    ++\tnopath=\"hopefully-absent-path\" &&\n    ++\techo \"$d/$nopath\" >expect &&\n    ++\ttest-tool path-utils real_path \"$d///$nopath\" >actual &&\n    ++\ttest_cmp expect actual\n      '\n      \n      test_expect_success SYMLINKS 'real path works on symlinks' '\n    @@ t/t0060-path-utils.sh: test_expect_success SYMLINKS 'real path works on symlinks\n      \tdir=\"$(cd .git && pwd -P)\" &&\n      \tdir2=third/../second/other/.git &&\n     -\ttest \"$dir\" = \"$(test-tool path-utils real_path $dir2)\" &&\n    -+\ttest_cmp_cmd \"$dir\" test-tool path-utils real_path $dir2 &&\n    ++\techo \"$dir\" >expect &&\n    ++\ttest-tool path-utils real_path $dir2 >actual &&\n    ++\ttest_cmp expect actual &&\n      \tfile=\"$dir\"/index &&\n     -\ttest \"$file\" = \"$(test-tool path-utils real_path $dir2/index)\" &&\n    -+\ttest_cmp_cmd \"$file\" test-tool path-utils real_path $dir2/index &&\n    ++\techo \"$file\" >expect &&\n    ++\ttest-tool path-utils real_path $dir2/index >actual &&\n    ++\ttest_cmp expect actual &&\n      \tbasename=blub &&\n     -\ttest \"$dir/$basename\" = \"$(cd .git && test-tool path-utils real_path \"$basename\")\" &&\n    -+\ttest_cmp_cmd \"$dir/$basename\" test-tool -C .git path-utils real_path \"$basename\" &&\n    ++\techo \"$dir/$basename\" >expect &&\n    ++\ttest-tool -C .git path-utils real_path \"$basename\" >actual &&\n    ++\ttest_cmp expect actual &&\n      \tln -s ../first/file .git/syml &&\n      \tsym=\"$(cd first && pwd -P)\"/file &&\n     -\ttest \"$sym\" = \"$(test-tool path-utils real_path \"$dir2/syml\")\"\n    -+\ttest_cmp_cmd \"$sym\" test-tool path-utils real_path \"$dir2/syml\"\n    ++\techo \"$sym\" >expect &&\n    ++\ttest-tool path-utils real_path \"$dir2/syml\" >actual &&\n    ++\ttest_cmp expect actual\n      '\n      \n      test_expect_success SYMLINKS 'prefix_path works with absolute paths to work tree symlinks' '\n      \tln -s target symlink &&\n     -\ttest \"$(test-tool path-utils prefix_path prefix \"$(pwd)/symlink\")\" = \"symlink\"\n    -+\ttest_cmp_cmd \"symlink\" test-tool path-utils prefix_path prefix \"$(pwd)/symlink\"\n    ++\techo \"symlink\" >expect &&\n    ++\ttest-tool path-utils prefix_path prefix \"$(pwd)/symlink\" >actual &&\n    ++\ttest_cmp expect actual\n      '\n      \n      test_expect_success 'prefix_path works with only absolute path to work tree' '\n    -@@ t/t0060-path-utils.sh: test_expect_success 'prefix_path rejects absolute path to dir with same beginnin\n    - test_expect_success SYMLINKS 'prefix_path works with absolute path to a symlink to work tree having  same beginning as work tree' '\n    - \tgit init repo &&\n    - \tln -s repo repolink &&\n    --\ttest \"a\" = \"$(cd repo && test-tool path-utils prefix_path prefix \"$(pwd)/../repolink/a\")\"\n    -+\ttest_cmp_cmd \"a\" test-tool -C repo path-utils prefix_path prefix \"$(cd repo && pwd)/../repolink/a\"\n    - '\n    - \n    - relative_path /foo/a/b/c/\t/foo/a/b/\tc/\n     \n      ## t/t0100-previous.sh ##\n     @@ t/t0100-previous.sh: test_expect_success 'branch -d @{-1}' '\n    @@ t/t0100-previous.sh: test_expect_success 'branch -d @{-1}' '\n      \tgit checkout -b junk &&\n      \tgit checkout - &&\n     -\ttest \"$(git symbolic-ref HEAD)\" = refs/heads/main &&\n    -+\ttest_cmp_cmd refs/heads/main git symbolic-ref HEAD &&\n    ++\techo refs/heads/main >expect &&\n    ++\tgit symbolic-ref HEAD >actual &&\n    ++\ttest_cmp expect actual &&\n      \tgit branch -d @{-1} &&\n      \ttest_must_fail git rev-parse --verify refs/heads/junk\n      '\n    @@ t/t0100-previous.sh: test_expect_success 'branch -d @{-12} when there is not eno\n      \tgit checkout -b junk2 &&\n      \tgit checkout - &&\n     -\ttest \"$(git symbolic-ref HEAD)\" = refs/heads/main &&\n    -+\ttest_cmp_cmd refs/heads/main git symbolic-ref HEAD &&\n    ++\techo refs/heads/main >expect &&\n    ++\tgit symbolic-ref HEAD >actual &&\n    ++\ttest_cmp expect actual &&\n      \ttest_must_fail git branch -d @{-12} &&\n      \tgit rev-parse --verify refs/heads/main\n      '\n    @@ t/t1504-ceiling-dirs.sh: TEST_PASSES_SANITIZE_LEAK=true\n     -\t\"test '$2' = \\\"\\$(git rev-parse --show-prefix)\\\"\"\n     +\tlocal expect=\"$2\" &&\n     +\ttest_expect_success \"$1: git rev-parse --show-prefix is '$2'\" '\n    -+\t\ttest_cmp_cmd \"$expect\" git rev-parse --show-prefix\n    ++\t\techo \"$expect\" >expect &&\n    ++\t\tgit rev-parse --show-prefix >actual &&\n    ++\t\ttest_cmp expect actual\n     +\t'\n      }\n      \n      test_fail() {\n     \n    - ## t/test-lib-functions.sh ##\n    -@@ t/test-lib-functions.sh: test_cmp_rev () {\n    - \tfi\n    - }\n    + ## t/t2005-checkout-index-symlinks.sh ##\n    +@@ t/t2005-checkout-index-symlinks.sh: test_expect_success \\\n    + git checkout-index symlink &&\n    + test -f symlink'\n      \n    -+# test_cmp_cmd is a convenience helper for doing the more verbose:\n    -+#\n    -+#\techo something >expect &&\n    -+#\t<some-command-and-args> >actual &&\n    -+#\ttest_cmp expect actual\n    -+#\n    -+# As:\n    -+#\n    -+#\ttest_cmp_cmd something <some-command-and-args>\n    -+test_cmp_cmd () {\n    -+\tlocal expect=\"$1\" &&\n    -+\tshift &&\n    -+\tprintf \"%s\\n\" \"$expect\" >expect &&\n    -+\t\"$@\" >actual 2>err &&\n    -+\ttest_must_be_empty err\n    +-test_expect_success \\\n    +-'the file must be the blob we added during the setup' '\n    +-test \"$(git hash-object -t blob symlink)\" = $l'\n    ++test_expect_success 'the file must be the blob we added during the setup' '\n    ++\techo \"$l\" >expect &&\n    ++\tgit hash-object -t blob symlink >actual &&\n     +\ttest_cmp expect actual\n    -+}\n    -+\n    - # Compare paths respecting core.ignoreCase\n    - test_cmp_fspath () {\n    - \tif test \"x$1\" = \"x$2\"\n    ++'\n    + \n    + test_done\n    +\n    + ## t/t5522-pull-symlink.sh ##\n    +@@ t/t5522-pull-symlink.sh: test_expect_success SYMLINKS 'pushing from symlinked subdir' '\n    + \t\tgit commit -m push ./file &&\n    + \t\tgit push\n    + \t) &&\n    +-\ttest push = $(git show HEAD:subdir/file)\n    ++\techo push >expect &&\n    ++\tgit show HEAD:subdir/file >actual &&\n    ++\ttest_cmp expect actual\n    + '\n    + \n    + test_done\n    +\n    + ## t/t7402-submodule-rebase.sh ##\n    +@@ t/t7402-submodule-rebase.sh: chmod a+x fake-editor.sh\n    + \n    + test_expect_success 'interactive rebase with a dirty submodule' '\n    + \n    +-\ttest submodule = $(git diff --name-only) &&\n    ++\techo submodule >expect &&\n    ++\tgit diff --name-only >actual &&\n    ++\ttest_cmp expect actual &&\n    + \tHEAD=$(git rev-parse HEAD) &&\n    + \tGIT_EDITOR=\"\\\"$(pwd)/fake-editor.sh\\\"\" EDITOR_TEXT=\"pick $HEAD\" \\\n    + \t\tgit rebase -i HEAD^ &&\n    +-\ttest submodule = $(git diff --name-only)\n    +-\n    ++\techo submodule >expect &&\n    ++\tgit diff --name-only >actual &&\n    ++\ttest_cmp expect actual\n    + '\n    + \n    + test_expect_success 'rebase with dirty file and submodule fails' '\n    +\n    + ## t/t7504-commit-msg-hook.sh ##\n    +@@ t/t7504-commit-msg-hook.sh: test_expect_success 'setup: commit-msg hook that always fails' '\n    + '\n    + \n    + commit_msg_is () {\n    +-\ttest \"$(git log --pretty=format:%s%b -1)\" = \"$1\"\n    ++\tprintf \"%s\" \"$1\" >expect &&\n    ++\tgit log --pretty=format:%s%b -1 >actual &&\n    ++\ttest_cmp expect actual\n    + }\n    + \n    + test_expect_success 'with failing hook' '\n    +\n    + ## t/t7810-grep.sh ##\n    +@@ t/t7810-grep.sh: test_expect_success 'log --committer does not search in timestamp' '\n    + test_expect_success 'grep with CE_VALID file' '\n    + \tgit update-index --assume-unchanged t/t &&\n    + \trm t/t &&\n    +-\ttest \"$(git grep test)\" = \"t/t:test\" &&\n    ++\techo \"t/t:test\" >expect &&\n    ++\tgit grep test >actual &&\n    ++\ttest_cmp expect actual &&\n    + \tgit update-index --no-assume-unchanged t/t &&\n    + \tgit checkout t/t\n    + '\n-:  ----------- > 7:  307f25db831 tests: don't lose \"git\" exit codes in \"! ( git ... | grep )\"\n8:  979a7f003f8 ! 8:  37c75f4a097 tests: use \"test_cmp_cmd\" in misc tests\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    tests: use \"test_cmp_cmd\" in misc tests\n    +    tests: don't lose mist \"git\" exit codes\n     \n    -    Change a few miscellaneous tests to use \"test_cmp_cmd\" to avoid losing\n    -    the exit code of \"git\".\n    +    Fix a few miscellaneous cases where:\n     \n    -    There's many offenders left that match patterns like:\n    -\n    -            /test .*\\$\\((test-tool|git)/\n    -\n    -    What these all have in common is that they were the rare odd cases out\n    -    in test files that were otherwise consistently checking the exit code.\n    +    - We lost the \"git\" exit code via \"git ... | grep\"\n    +    - Likewise by having a $(git) argument to git itself\n    +    - Used \"test -z\" to check that a command emitted no output, we can use\n    +      \"test_must_be_empty\" and &&-chaining instead.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n    @@ t/t1401-symbolic-ref.sh: test_expect_success 'symbolic-ref refuses non-ref for H\n      \n      reset_to_sane\n     \n    - ## t/t2005-checkout-index-symlinks.sh ##\n    -@@ t/t2005-checkout-index-symlinks.sh: test -f symlink'\n    - \n    - test_expect_success \\\n    - 'the file must be the blob we added during the setup' '\n    --test \"$(git hash-object -t blob symlink)\" = $l'\n    -+test_cmp_cmd \"$l\" git hash-object -t blob symlink'\n    - \n    - test_done\n    -\n      ## t/t3701-add-interactive.sh ##\n     @@ t/t3701-add-interactive.sh: test_expect_success FILEMODE 'stage mode and hunk' '\n      \techo content >>file &&\n    @@ t/t3701-add-interactive.sh: test_expect_success FILEMODE 'stage mode and hunk' '\n     -\tgit diff --cached file | grep \"+content\" &&\n     -\ttest -z \"$(git diff file)\"\n     +\tgit diff --cached file >out &&\n    -+\tgrep \"new mode\" <out &&\n    -+\tgit diff --cached file >out &&\n    -+\tgrep \"+content\" <out &&\n    ++\tgrep \"new mode\" out &&\n    ++\tgrep \"+content\" out &&\n     +\tgit diff file >out &&\n     +\ttest_must_be_empty out\n      '\n      \n      # end of tests disabled when filemode is not usable\n     \n    - ## t/t5522-pull-symlink.sh ##\n    -@@ t/t5522-pull-symlink.sh: test_expect_success SYMLINKS 'pushing from symlinked subdir' '\n    - \t\tgit commit -m push ./file &&\n    - \t\tgit push\n    - \t) &&\n    --\ttest push = $(git show HEAD:subdir/file)\n    -+\ttest_cmp_cmd push git show HEAD:subdir/file\n    - '\n    - \n    - test_done\n    -\n    - ## t/t7402-submodule-rebase.sh ##\n    -@@ t/t7402-submodule-rebase.sh: chmod a+x fake-editor.sh\n    - \n    - test_expect_success 'interactive rebase with a dirty submodule' '\n    - \n    --\ttest submodule = $(git diff --name-only) &&\n    -+\ttest_cmp_cmd submodule git diff --name-only &&\n    - \tHEAD=$(git rev-parse HEAD) &&\n    - \tGIT_EDITOR=\"\\\"$(pwd)/fake-editor.sh\\\"\" EDITOR_TEXT=\"pick $HEAD\" \\\n    - \t\tgit rebase -i HEAD^ &&\n    --\ttest submodule = $(git diff --name-only)\n    -+\ttest_cmp_cmd submodule git diff --name-only\n    - \n    - '\n    - \n    -\n    - ## t/t7504-commit-msg-hook.sh ##\n    -@@ t/t7504-commit-msg-hook.sh: test_expect_success 'setup: commit-msg hook that always fails' '\n    - '\n    - \n    - commit_msg_is () {\n    --\ttest \"$(git log --pretty=format:%s%b -1)\" = \"$1\"\n    -+\ttest_cmp_cmd \"$1\" git log --pretty=tformat:%s%b -1\n    - }\n    - \n    - test_expect_success 'with failing hook' '\n    -\n      ## t/t7516-commit-races.sh ##\n     @@ t/t7516-commit-races.sh: test_expect_success 'race to create orphan commit' '\n      \ttest_must_fail env EDITOR=./hare-editor git commit --allow-empty -m tortoise -e &&\n    @@ t/t7516-commit-races.sh: test_expect_success 'race to create orphan commit' '\n      '\n      \n      test_expect_success 'race to create non-orphan commit' '\n    -\n    - ## t/t7810-grep.sh ##\n    -@@ t/t7810-grep.sh: test_expect_success 'log --committer does not search in timestamp' '\n    - test_expect_success 'grep with CE_VALID file' '\n    - \tgit update-index --assume-unchanged t/t &&\n    - \trm t/t &&\n    --\ttest \"$(git grep test)\" = \"t/t:test\" &&\n    -+\ttest_cmp_cmd \"t/t:test\" git grep test &&\n    - \tgit update-index --no-assume-unchanged t/t &&\n    - \tgit checkout t/t\n    - '\n-- \n2.39.0.rc1.981.gf846af54b4b\n\n"},{"id":"468426","messageId":"patch-v3-2.8-394d5e46494-20221202T114733Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v3-0.8-00000000000-20221202T114733Z-avarab@gmail.com","subject":"[PATCH v3 2/8] auto-crlf tests: don't lose exit code in loops and outside tests","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-02T11:52:35Z","receivedAt":"2022-12-02T11:53:56Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the functions which are called from within\n\"test_expect_success\" to add the \"|| return 1\" idiom to their\nfor-loops, so we won't lose the exit code of \"cp\", \"git\" etc.\n\nThen for those setup functions that aren't called from a\n\"test_expect_success\" we need to put the setup code in a\n\"test_expect_success\" as well. It would not be enough to properly\n&&-chain these, as the calling code is the top-level script itself. As\nwe don't run the tests with \"set -e\" we won't report failing commands\nat the top-level.\n\nThe \"checkout\" part of this would miss memory leaks under\nSANITIZE=leak, this code doesn't leak (the relevant \"git checkout\"\nleak has been fixed), but in a past version of git we'd continue past\nthis failure under SANITIZE=leak when these invocations had errored\nout, even under \"--immediate\".\n\nHelped-by: René Scharfe <l.s.r@web.de>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t0027-auto-crlf.sh | 60 +++++++++++++++++++++++++-------------------\n 1 file changed, 34 insertions(+), 26 deletions(-)\n\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex a94ac1eae37..23f2e613401 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -70,7 +70,8 @@ create_NNO_MIX_files () {\n \t\t\t\tcp CRLF        ${pfx}_CRLF.txt &&\n \t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt &&\n \t\t\t\tcp LF_mix_CR   ${pfx}_LF_mix_CR.txt &&\n-\t\t\t\tcp CRLF_nul    ${pfx}_CRLF_nul.txt\n+\t\t\t\tcp CRLF_nul    ${pfx}_CRLF_nul.txt ||\n+\t\t\t\treturn 1\n \t\t\tdone\n \t\tdone\n \tdone\n@@ -101,7 +102,8 @@ commit_check_warn () {\n \tdo\n \t\tfname=${pfx}_$f.txt &&\n \t\tcp $f $fname &&\n-\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\"\n+\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\" ||\n+\t\treturn 1\n \tdone &&\n \tgit commit -m \"core.autocrlf $crlf\" &&\n \tcheck_warning \"$lfname\" ${pfx}_LF.err &&\n@@ -121,15 +123,19 @@ commit_chk_wrnNNO () {\n \tlfmixcr=$1 ; shift\n \tcrlfnul=$1 ; shift\n \tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n-\t#Commit files on top of existing file\n-\tcreate_gitattributes \"$attr\" $aeol &&\n-\tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n-\tdo\n-\t\tfname=${pfx}_$f.txt &&\n-\t\tcp $f $fname &&\n-\t\tprintf Z >>\"$fname\" &&\n-\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\"\n-\tdone\n+\n+\ttest_expect_success 'setup commit NNO files' '\n+\t\t#Commit files on top of existing file\n+\t\tcreate_gitattributes \"$attr\" $aeol &&\n+\t\tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n+\t\tdo\n+\t\t\tfname=${pfx}_$f.txt &&\n+\t\t\tcp $f $fname &&\n+\t\t\tprintf Z >>\"$fname\" &&\n+\t\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\" ||\n+\t\t\treturn 1\n+\t\tdone\n+\t'\n \n \ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr LF\" '\n \t\tcheck_warning \"$lfwarn\" ${pfx}_LF.err\n@@ -163,15 +169,19 @@ commit_MIX_chkwrn () {\n \tlfmixcr=$1 ; shift\n \tcrlfnul=$1 ; shift\n \tpfx=MIX_attr_${attr}_aeol_${aeol}_${crlf}\n-\t#Commit file with CLRF_mix_LF on top of existing file\n-\tcreate_gitattributes \"$attr\" $aeol &&\n-\tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n-\tdo\n-\t\tfname=${pfx}_$f.txt &&\n-\t\tcp CRLF_mix_LF $fname &&\n-\t\tprintf Z >>\"$fname\" &&\n-\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\"\n-\tdone\n+\n+\ttest_expect_success 'setup commit file with mixed EOL' '\n+\t\t#Commit file with CLRF_mix_LF on top of existing file\n+\t\tcreate_gitattributes \"$attr\" $aeol &&\n+\t\tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n+\t\tdo\n+\t\t\tfname=${pfx}_$f.txt &&\n+\t\t\tcp CRLF_mix_LF $fname &&\n+\t\t\tprintf Z >>\"$fname\" &&\n+\t\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\" ||\n+\t\t\treturn 1\n+\t\tdone\n+\t'\n \n \ttest_expect_success \"commit file with mixed EOL onto LF crlf=$crlf attr=$attr\" '\n \t\tcheck_warning \"$lfwarn\" ${pfx}_LF.err\n@@ -294,12 +304,10 @@ checkout_files () {\n \tpfx=eol_${ceol}_crlf_${crlf}_attr_${attr}_ &&\n \tfor f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul\n \tdo\n-\t\trm crlf_false_attr__$f.txt &&\n-\t\tif test -z \"$ceol\"; then\n-\t\t\tgit checkout -- crlf_false_attr__$f.txt\n-\t\telse\n-\t\t\tgit -c core.eol=$ceol checkout -- crlf_false_attr__$f.txt\n-\t\tfi\n+\t\ttest_expect_success \"setup $f checkout ${ceol:+ with -c core.eol=$ceol}\"  '\n+\t\t\trm -f crlf_false_attr__$f.txt &&\n+\t\t\tgit ${ceol:+-c core.eol=$ceol} checkout -- crlf_false_attr__$f.txt\n+\t\t'\n \tdone\n \n \ttest_expect_success \"ls-files --eol attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol\" '\n-- \n2.39.0.rc1.981.gf846af54b4b\n\n"},{"id":"468427","messageId":"patch-v3-3.8-4ec075689f6-20221202T114733Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v3-0.8-00000000000-20221202T114733Z-avarab@gmail.com","subject":"[PATCH v3 3/8] diff tests: fix ignored exit codes in t4023","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-02T11:52:36Z","receivedAt":"2022-12-02T11:53:59Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change a \"git diff-tree\" command to be &&-chained so that we won't\nignore its exit code, see the ea05fd5fbf7 (Merge branch\n'ab/keep-git-exit-codes-in-tests', 2022-03-16) topic for prior art.\n\nThis fixes code added in b45563a229f (rename: Break filepairs with\ndifferent types., 2007-11-30). Due to hiding the exit code we hid a\nmemory leak under SANITIZE=leak.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t4023-diff-rename-typechange.sh | 12 ++++++------\n 1 file changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/t/t4023-diff-rename-typechange.sh b/t/t4023-diff-rename-typechange.sh\nindex 7cb99092938..25c31b0cb1b 100755\n--- a/t/t4023-diff-rename-typechange.sh\n+++ b/t/t4023-diff-rename-typechange.sh\n@@ -52,8 +52,8 @@ test_expect_success setup '\n '\n \n test_expect_success 'cross renames to be detected for regular files' '\n-\n-\tgit diff-tree five six -r --name-status -B -M | sort >actual &&\n+\tgit diff-tree five six -r --name-status -B -M >out &&\n+\tsort <out >actual &&\n \t{\n \t\techo \"R100\tfoo\tbar\" &&\n \t\techo \"R100\tbar\tfoo\"\n@@ -63,8 +63,8 @@ test_expect_success 'cross renames to be detected for regular files' '\n '\n \n test_expect_success 'cross renames to be detected for typechange' '\n-\n-\tgit diff-tree one two -r --name-status -B -M | sort >actual &&\n+\tgit diff-tree one two -r --name-status -B -M >out &&\n+\tsort <out >actual &&\n \t{\n \t\techo \"R100\tfoo\tbar\" &&\n \t\techo \"R100\tbar\tfoo\"\n@@ -74,8 +74,8 @@ test_expect_success 'cross renames to be detected for typechange' '\n '\n \n test_expect_success 'moves and renames' '\n-\n-\tgit diff-tree three four -r --name-status -B -M | sort >actual &&\n+\tgit diff-tree three four -r --name-status -B -M >out &&\n+\tsort <out >actual &&\n \t{\n \t\t# see -B -M (#6) in t4008\n \t\techo \"C100\tfoo\tbar\" &&\n-- \n2.39.0.rc1.981.gf846af54b4b\n\n"},{"id":"468428","messageId":"patch-v3-4.8-c080899dd5f-20221202T114733Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v3-0.8-00000000000-20221202T114733Z-avarab@gmail.com","subject":"[PATCH v3 4/8] t/lib-patch-mode.sh: fix ignored exit codes","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-02T11:52:37Z","receivedAt":"2022-12-02T11:54:10Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Fix code added in b319ef70a94 (Add a small patch-mode testing library,\n2009-08-13) to use &&-chaining and the newly added \"test_cmp_cmd\".\nThis avoids losing both the exit code of a \"git\" and the \"cat\"\nprocesses.\n\nThis fixes cases where we'd have e.g. missed memory leaks under\nSANITIZE=leak, this code doesn't leak now as far as I can tell, but I\ndiscovered it while looking at leaks in related code.\n\nThe \"cat _head >expect\" here is redundant, we could simply give\n\"_head\" to \"test_cmp\", but let's be consistent in using the \"expect\"\nand \"actual\" names for clarity.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/lib-patch-mode.sh | 11 ++++++++---\n 1 file changed, 8 insertions(+), 3 deletions(-)\n\ndiff --git a/t/lib-patch-mode.sh b/t/lib-patch-mode.sh\nindex cfd76bf987b..89ca1f78055 100644\n--- a/t/lib-patch-mode.sh\n+++ b/t/lib-patch-mode.sh\n@@ -29,8 +29,12 @@ set_and_save_state () {\n \n # verify_state <path> <expected-worktree-content> <expected-index-content>\n verify_state () {\n-\ttest \"$(cat \"$1\")\" = \"$2\" &&\n-\ttest \"$(git show :\"$1\")\" = \"$3\"\n+\techo \"$2\" >expect &&\n+\ttest_cmp expect \"$1\" &&\n+\n+\techo \"$3\" >expect &&\n+\tgit show :\"$1\" >actual &&\n+\ttest_cmp expect actual\n }\n \n # verify_saved_state <path>\n@@ -46,5 +50,6 @@ save_head () {\n }\n \n verify_saved_head () {\n-\ttest \"$(cat _head)\" = \"$(git rev-parse HEAD)\"\n+\tgit rev-parse HEAD >actual &&\n+\ttest_cmp _head actual\n }\n-- \n2.39.0.rc1.981.gf846af54b4b\n\n"},{"id":"468429","messageId":"patch-v3-5.8-58ac6fe5604-20221202T114733Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v3-0.8-00000000000-20221202T114733Z-avarab@gmail.com","subject":"[PATCH v3 5/8] tests: use \"test_cmp\" instead of \"test\" in sub-shells","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-02T11:52:38Z","receivedAt":"2022-12-02T11:54:17Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Convert a few cases where we were using \"test\" inside a sub-shell, and\nwere losing the exit code of \"git\".\n\nIn the case of \"t3200-branch.sh\" some adjacent code outside of a\nsub-shell that was losing the exit code is also being converted, as\nit's within the same hunk.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/lib-httpd.sh              |  5 +++--\n t/lib-submodule-update.sh   | 22 +++++++++-------------\n t/t0060-path-utils.sh       |  4 +++-\n t/t3200-branch.sh           | 13 +++++++------\n t/t5605-clone-local.sh      | 15 ++++++++++-----\n t/t7402-submodule-rebase.sh | 14 +++++++++++---\n 6 files changed, 43 insertions(+), 30 deletions(-)\n\ndiff --git a/t/lib-httpd.sh b/t/lib-httpd.sh\nindex 608949ea80b..31e7fa3010c 100644\n--- a/t/lib-httpd.sh\n+++ b/t/lib-httpd.sh\n@@ -217,8 +217,9 @@ test_http_push_nonff () {\n \t\tgit commit -a -m path2 --amend &&\n \n \t\ttest_must_fail git push -v origin >output 2>&1 &&\n-\t\t(cd \"$REMOTE_REPO\" &&\n-\t\t test $HEAD = $(git rev-parse --verify HEAD))\n+\t\techo \"$HEAD\" >expect &&\n+\t\tgit -C \"$REMOTE_REPO\" rev-parse --verify HEAD >actual &&\n+\t\ttest_cmp expect actual\n \t'\n \n \ttest_expect_success 'non-fast-forward push show ref status' '\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 2d31fcfda1f..d7c2b670b4a 100644\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -168,20 +168,16 @@ replace_gitfile_with_git_dir () {\n # Note that this only supports submodules at the root level of the\n # superproject, with the default name, i.e. same as its path.\n test_git_directory_is_unchanged () {\n-\t(\n-\t\tcd \".git/modules/$1\" &&\n-\t\t# does core.worktree point at the right place?\n-\t\ttest \"$(git config core.worktree)\" = \"../../../$1\" &&\n-\t\t# remove it temporarily before comparing, as\n-\t\t# \"$1/.git/config\" lacks it...\n-\t\tgit config --unset core.worktree\n-\t) &&\n+\t# does core.worktree point at the right place?\n+\techo \"../../../$1\" >expect &&\n+\tgit -C \".git/modules/$1\" config core.worktree >actual &&\n+\ttest_cmp expect actual &&\n+\t# remove it temporarily before comparing, as\n+\t# \"$1/.git/config\" lacks it...\n+\tgit -C \".git/modules/$1\" config --unset core.worktree &&\n \tdiff -r \".git/modules/$1\" \"$1/.git\" &&\n-\t(\n-\t\t# ... and then restore.\n-\t\tcd \".git/modules/$1\" &&\n-\t\tgit config core.worktree \"../../../$1\"\n-\t)\n+\t# ... and then restore.\n+\tgit -C \".git/modules/$1\" config core.worktree \"../../../$1\"\n }\n \n test_git_directory_exists () {\ndiff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh\nindex 68e29c904a6..53ec717cbca 100755\n--- a/t/t0060-path-utils.sh\n+++ b/t/t0060-path-utils.sh\n@@ -255,7 +255,9 @@ test_expect_success 'prefix_path rejects absolute path to dir with same beginnin\n test_expect_success SYMLINKS 'prefix_path works with absolute path to a symlink to work tree having  same beginning as work tree' '\n \tgit init repo &&\n \tln -s repo repolink &&\n-\ttest \"a\" = \"$(cd repo && test-tool path-utils prefix_path prefix \"$(pwd)/../repolink/a\")\"\n+\techo \"a\" >expect &&\n+\ttest-tool -C repo path-utils prefix_path prefix \"$(cd repo && pwd)/../repolink/a\" >actual &&\n+\ttest_cmp expect actual\n '\n \n relative_path /foo/a/b/c/\t/foo/a/b/\tc/\ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex 5a169b68d6a..f5fbb84262b 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -242,12 +242,13 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou\n test_expect_success 'git branch -M baz bam should succeed within a worktree in which baz is checked out' '\n \tgit checkout -b baz &&\n \tgit worktree add -f bazdir baz &&\n-\t(\n-\t\tcd bazdir &&\n-\t\tgit branch -M baz bam &&\n-\t\ttest $(git rev-parse --abbrev-ref HEAD) = bam\n-\t) &&\n-\ttest $(git rev-parse --abbrev-ref HEAD) = bam &&\n+\tgit -C \"$bazdir\" branch -M baz bam &&\n+\techo \"bam\" >expect &&\n+\tgit -C \"$bazdir\" rev-parse --abbrev-ref HEAD >actual &&\n+\ttest_cmp expect actual &&\n+\techo \"bam\" >expect &&\n+\tgit rev-parse --abbrev-ref HEAD >actual &&\n+\ttest_cmp expect actual &&\n \trm -r bazdir &&\n \tgit worktree prune\n '\ndiff --git a/t/t5605-clone-local.sh b/t/t5605-clone-local.sh\nindex 38b850c10ef..61a2342bc2c 100755\n--- a/t/t5605-clone-local.sh\n+++ b/t/t5605-clone-local.sh\n@@ -15,8 +15,12 @@ test_expect_success 'preparing origin repository' '\n \t: >file && git add . && git commit -m1 &&\n \tgit clone --bare . a.git &&\n \tgit clone --bare . x &&\n-\ttest \"$(cd a.git && git config --bool core.bare)\" = true &&\n-\ttest \"$(cd x && git config --bool core.bare)\" = true &&\n+\techo true >expect &&\n+\tgit -C a.git config --bool core.bare >actual &&\n+\ttest_cmp expect actual &&\n+\techo true >expect &&\n+\tgit -C x config --bool core.bare >actual &&\n+\ttest_cmp expect actual &&\n \tgit bundle create b1.bundle --all &&\n \tgit bundle create b2.bundle main &&\n \tmkdir dir &&\n@@ -28,9 +32,10 @@ test_expect_success 'preparing origin repository' '\n \n test_expect_success 'local clone without .git suffix' '\n \tgit clone -l -s a b &&\n-\t(cd b &&\n-\ttest \"$(git config --bool core.bare)\" = false &&\n-\tgit fetch)\n+\techo false >expect &&\n+\tgit -C b config --bool core.bare >actual &&\n+\ttest_cmp expect actual &&\n+\tgit -C b fetch\n '\n \n test_expect_success 'local clone with .git suffix' '\ndiff --git a/t/t7402-submodule-rebase.sh b/t/t7402-submodule-rebase.sh\nindex ebeca12a711..1927a862839 100755\n--- a/t/t7402-submodule-rebase.sh\n+++ b/t/t7402-submodule-rebase.sh\n@@ -82,11 +82,19 @@ test_expect_success 'stash with a dirty submodule' '\n \tCURRENT=$(cd submodule && git rev-parse HEAD) &&\n \tgit stash &&\n \ttest new != $(cat file) &&\n-\ttest submodule = $(git diff --name-only) &&\n-\ttest $CURRENT = $(cd submodule && git rev-parse HEAD) &&\n+\techo submodule >expect &&\n+\tgit diff --name-only >actual &&\n+\ttest_cmp expect actual &&\n+\n+\techo \"$CURRENT\" >expect &&\n+\tgit -C submodule rev-parse HEAD >actual &&\n+\ttest_cmp expect actual &&\n+\n \tgit stash apply &&\n \ttest new = $(cat file) &&\n-\ttest $CURRENT = $(cd submodule && git rev-parse HEAD)\n+\techo \"$CURRENT\" >expect &&\n+\tgit -C submodule rev-parse HEAD >actual &&\n+\ttest_cmp expect actual\n \n '\n \n-- \n2.39.0.rc1.981.gf846af54b4b\n\n"},{"id":"468430","messageId":"patch-v3-7.8-307f25db831-20221202T114733Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v3-0.8-00000000000-20221202T114733Z-avarab@gmail.com","subject":"[PATCH v3 7/8] tests: don't lose \"git\" exit codes in \"! ( git ... | grep )\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-02T11:52:40Z","receivedAt":"2022-12-02T11:54:20Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change tests that would lose the \"git\" exit code via a negation\npattern to:\n\n- In the case of \"t0055-beyond-symlinks.sh\" compare against the\n  expected output instead.\n\n- For \"t3700-add.sh\" use \"sed -n\" to print the expected \"bad\" part,\n  and use \"test_must_be_empty\" to assert that it's not there.\n\n  We can also remove a repeated invocation of \"git ls-files\" for the\n  last test that's being modified in that file, and search the\n  existing \"files\" output instead.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t0055-beyond-symlinks.sh | 14 ++++++++++++--\n t/t3700-add.sh             | 18 +++++++++++++-----\n 2 files changed, 25 insertions(+), 7 deletions(-)\n\ndiff --git a/t/t0055-beyond-symlinks.sh b/t/t0055-beyond-symlinks.sh\nindex 6bada370225..c3eb1158ef9 100755\n--- a/t/t0055-beyond-symlinks.sh\n+++ b/t/t0055-beyond-symlinks.sh\n@@ -15,12 +15,22 @@ test_expect_success SYMLINKS setup '\n \n test_expect_success SYMLINKS 'update-index --add beyond symlinks' '\n \ttest_must_fail git update-index --add c/d &&\n-\t! ( git ls-files | grep c/d )\n+\tcat >expect <<-\\EOF &&\n+\ta\n+\tb/d\n+\tEOF\n+\tgit ls-files >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success SYMLINKS 'add beyond symlinks' '\n \ttest_must_fail git add c/d &&\n-\t! ( git ls-files | grep c/d )\n+\tcat >expect <<-\\EOF &&\n+\ta\n+\tb/d\n+\tEOF\n+\tgit ls-files >actual &&\n+\ttest_cmp expect actual\n '\n \n test_done\ndiff --git a/t/t3700-add.sh b/t/t3700-add.sh\nindex 51afbd7b24a..82dd768944f 100755\n--- a/t/t3700-add.sh\n+++ b/t/t3700-add.sh\n@@ -106,24 +106,32 @@ test_expect_success '.gitignore test setup' '\n \n test_expect_success '.gitignore is honored' '\n \tgit add . &&\n-\t! (git ls-files | grep \"\\\\.ig\")\n+\tgit ls-files >files &&\n+\tsed -n \"/\\\\.ig/p\" <files >actual &&\n+\ttest_must_be_empty actual\n '\n \n test_expect_success 'error out when attempting to add ignored ones without -f' '\n \ttest_must_fail git add a.?? &&\n-\t! (git ls-files | grep \"\\\\.ig\")\n+\tgit ls-files >files &&\n+\tsed -n \"/\\\\.ig/p\" <files >actual &&\n+\ttest_must_be_empty actual\n '\n \n test_expect_success 'error out when attempting to add ignored ones without -f' '\n \ttest_must_fail git add d.?? &&\n-\t! (git ls-files | grep \"\\\\.ig\")\n+\tgit ls-files >files &&\n+\tsed -n \"/\\\\.ig/p\" <files >actual &&\n+\ttest_must_be_empty actual\n '\n \n test_expect_success 'error out when attempting to add ignored ones but add others' '\n \ttouch a.if &&\n \ttest_must_fail git add a.?? &&\n-\t! (git ls-files | grep \"\\\\.ig\") &&\n-\t(git ls-files | grep a.if)\n+\tgit ls-files >files &&\n+\tsed -n \"/\\\\.ig/p\" <files >actual &&\n+\ttest_must_be_empty actual &&\n+\tgrep a.if files\n '\n \n test_expect_success 'add ignored ones with -f' '\n-- \n2.39.0.rc1.981.gf846af54b4b\n\n"},{"id":"468431","messageId":"patch-v3-6.8-51f32b42ce6-20221202T114733Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v3-0.8-00000000000-20221202T114733Z-avarab@gmail.com","subject":"[PATCH v3 6/8] tests: don't lose 'test <str> = $(cmd ...)\"' exit code","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-02T11:52:39Z","receivedAt":"2022-12-02T11:54:23Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Convert some cases in the test suite where we'd lose the exit code of\na command being interpolated as one of the arguments to the \"test\"\nbuiltin function to use &&-chaining and \"test_cmp\" instead.\n\nThis way we won't lose the exit code, and the failure output will be\nmore helpful.\n\nIn the case of \"t0060-path-utils.sh\" and\n\"t2005-checkout-index-symlinks.sh\" convert the relevant code to using\nthe modern style of indentation and newline wrapping while having to\nchange it.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/lib-submodule-update.sh          |   4 +-\n t/t0001-init.sh                    |   9 ++-\n t/t0002-gitfile.sh                 |   4 +-\n t/t0060-path-utils.sh              | 103 +++++++++++++++++++++--------\n t/t0100-previous.sh                |   8 ++-\n t/t1504-ceiling-dirs.sh            |   8 ++-\n t/t2005-checkout-index-symlinks.sh |   8 ++-\n t/t5522-pull-symlink.sh            |   4 +-\n t/t7402-submodule-rebase.sh        |   9 ++-\n t/t7504-commit-msg-hook.sh         |   4 +-\n t/t7810-grep.sh                    |   4 +-\n 11 files changed, 120 insertions(+), 45 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex d7c2b670b4a..dee14992c52 100644\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -185,7 +185,9 @@ test_git_directory_exists () {\n \tif test -f sub1/.git\n \tthen\n \t\t# does core.worktree point at the right place?\n-\t\ttest \"$(git -C .git/modules/$1 config core.worktree)\" = \"../../../$1\"\n+\t\techo \"../../../$1\" >expect &&\n+\t\tgit -C \".git/modules/$1\" config core.worktree >actual &&\n+\t\ttest_cmp expect actual\n \tfi\n }\n \ndiff --git a/t/t0001-init.sh b/t/t0001-init.sh\nindex d479303efa0..30a6edca1d2 100755\n--- a/t/t0001-init.sh\n+++ b/t/t0001-init.sh\n@@ -598,9 +598,14 @@ test_expect_success 'invalid default branch name' '\n test_expect_success 'branch -m with the initial branch' '\n \tgit init rename-initial &&\n \tgit -C rename-initial branch -m renamed &&\n-\ttest renamed = $(git -C rename-initial symbolic-ref --short HEAD) &&\n+\techo renamed >expect &&\n+\tgit -C rename-initial symbolic-ref --short HEAD >actual &&\n+\ttest_cmp expect actual &&\n+\n \tgit -C rename-initial branch -m renamed again &&\n-\ttest again = $(git -C rename-initial symbolic-ref --short HEAD)\n+\techo again >expect &&\n+\tgit -C rename-initial symbolic-ref --short HEAD >actual &&\n+\ttest_cmp expect actual\n '\n \n test_done\ndiff --git a/t/t0002-gitfile.sh b/t/t0002-gitfile.sh\nindex 26eaca095a2..e013d38f485 100755\n--- a/t/t0002-gitfile.sh\n+++ b/t/t0002-gitfile.sh\n@@ -33,7 +33,9 @@ test_expect_success 'bad setup: invalid .git file path' '\n \n test_expect_success 'final setup + check rev-parse --git-dir' '\n \techo \"gitdir: $REAL\" >.git &&\n-\ttest \"$REAL\" = \"$(git rev-parse --git-dir)\"\n+\techo \"$REAL\" >expect &&\n+\tgit rev-parse --git-dir >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'check hash-object' '\ndiff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh\nindex 53ec717cbca..6490ad5ca1b 100755\n--- a/t/t0060-path-utils.sh\n+++ b/t/t0060-path-utils.sh\n@@ -10,20 +10,27 @@ TEST_PASSES_SANITIZE_LEAK=true\n \n norm_path() {\n \texpected=$(test-tool path-utils print_path \"$2\")\n-\ttest_expect_success $3 \"normalize path: $1 => $2\" \\\n-\t\"test \\\"\\$(test-tool path-utils normalize_path_copy '$1')\\\" = '$expected'\"\n+\ttest_expect_success $3 \"normalize path: $1 => $2\" \"\n+\t\techo '$expected' >expect &&\n+\t\ttest-tool path-utils normalize_path_copy '$1' >actual &&\n+\t\ttest_cmp expect actual\n+\t\"\n }\n \n relative_path() {\n \texpected=$(test-tool path-utils print_path \"$3\")\n-\ttest_expect_success $4 \"relative path: $1 $2 => $3\" \\\n-\t\"test \\\"\\$(test-tool path-utils relative_path '$1' '$2')\\\" = '$expected'\"\n+\ttest_expect_success $4 \"relative path: $1 $2 => $3\" \"\n+\t\techo '$expected' >expect &&\n+\t\ttest-tool path-utils relative_path '$1' '$2' >actual &&\n+\t\ttest_cmp expect actual\n+\t\"\n }\n \n test_submodule_relative_url() {\n \ttest_expect_success \"test_submodule_relative_url: $1 $2 $3 => $4\" \"\n-\t\tactual=\\$(test-tool submodule resolve-relative-url '$1' '$2' '$3') &&\n-\t\ttest \\\"\\$actual\\\" = '$4'\n+\t\techo '$4' >expect &&\n+\t\ttest-tool submodule resolve-relative-url '$1' '$2' '$3' >actual &&\n+\t\ttest_cmp expect actual\n \t\"\n }\n \n@@ -64,9 +71,11 @@ ancestor() {\n \t\texpected=$(($expected-$rootslash+$rootoff))\n \t\t;;\n \tesac\n-\ttest_expect_success $4 \"longest ancestor: $1 $2 => $expected\" \\\n-\t\"actual=\\$(test-tool path-utils longest_ancestor_length '$1' '$2') &&\n-\t test \\\"\\$actual\\\" = '$expected'\"\n+\ttest_expect_success $4 \"longest ancestor: $1 $2 => $expected\" \"\n+\t\techo '$expected' >expect &&\n+\t\ttest-tool path-utils longest_ancestor_length '$1' '$2' >actual &&\n+\t\ttest_cmp expect actual\n+\t\"\n }\n \n # Some absolute path tests should be skipped on Windows due to path mangling\n@@ -166,8 +175,10 @@ ancestor D:/Users/me C:/ -1 MINGW\n ancestor //server/share/my-directory //server/share/ 14 MINGW\n \n test_expect_success 'strip_path_suffix' '\n-\ttest c:/msysgit = $(test-tool path-utils strip_path_suffix \\\n-\t\tc:/msysgit/libexec//git-core libexec/git-core)\n+\techo c:/msysgit >expect &&\n+\ttest-tool path-utils strip_path_suffix \\\n+\t\tc:/msysgit/libexec//git-core libexec/git-core >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'absolute path rejects the empty string' '\n@@ -188,35 +199,61 @@ test_expect_success 'real path rejects the empty string' '\n '\n \n test_expect_success POSIX 'real path works on absolute paths 1' '\n+\techo / >expect &&\n+\ttest-tool path-utils real_path \"/\" >actual &&\n+\ttest_cmp expect actual &&\n+\n \tnopath=\"hopefully-absent-path\" &&\n-\ttest \"/\" = \"$(test-tool path-utils real_path \"/\")\" &&\n-\ttest \"/$nopath\" = \"$(test-tool path-utils real_path \"/$nopath\")\"\n+\techo \"/$nopath\" >expect &&\n+\ttest-tool path-utils real_path \"/$nopath\" >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'real path works on absolute paths 2' '\n-\tnopath=\"hopefully-absent-path\" &&\n \t# Find an existing top-level directory for the remaining tests:\n \td=$(pwd -P | sed -e \"s|^\\([^/]*/[^/]*\\)/.*|\\1|\") &&\n-\ttest \"$d\" = \"$(test-tool path-utils real_path \"$d\")\" &&\n-\ttest \"$d/$nopath\" = \"$(test-tool path-utils real_path \"$d/$nopath\")\"\n+\techo \"$d\" >expect &&\n+\ttest-tool path-utils real_path \"$d\" >actual &&\n+\ttest_cmp expect actual &&\n+\n+\tnopath=\"hopefully-absent-path\" &&\n+\techo \"$d/$nopath\" >expect &&\n+\ttest-tool path-utils real_path \"$d/$nopath\" >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success POSIX 'real path removes extra leading slashes' '\n+\techo \"/\" >expect &&\n+\ttest-tool path-utils real_path \"///\" >actual &&\n+\ttest_cmp expect actual &&\n+\n \tnopath=\"hopefully-absent-path\" &&\n-\ttest \"/\" = \"$(test-tool path-utils real_path \"///\")\" &&\n-\ttest \"/$nopath\" = \"$(test-tool path-utils real_path \"///$nopath\")\" &&\n+\techo \"/$nopath\" >expect &&\n+\ttest-tool path-utils real_path \"///$nopath\" >actual &&\n+\ttest_cmp expect actual &&\n+\n \t# Find an existing top-level directory for the remaining tests:\n \td=$(pwd -P | sed -e \"s|^\\([^/]*/[^/]*\\)/.*|\\1|\") &&\n-\ttest \"$d\" = \"$(test-tool path-utils real_path \"//$d\")\" &&\n-\ttest \"$d/$nopath\" = \"$(test-tool path-utils real_path \"//$d/$nopath\")\"\n+\techo \"$d\" >expect &&\n+\ttest-tool path-utils real_path \"//$d\" >actual &&\n+\ttest_cmp expect actual &&\n+\n+\techo \"$d/$nopath\" >expect &&\n+\ttest-tool path-utils real_path \"//$d/$nopath\" >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'real path removes other extra slashes' '\n-\tnopath=\"hopefully-absent-path\" &&\n \t# Find an existing top-level directory for the remaining tests:\n \td=$(pwd -P | sed -e \"s|^\\([^/]*/[^/]*\\)/.*|\\1|\") &&\n-\ttest \"$d\" = \"$(test-tool path-utils real_path \"$d///\")\" &&\n-\ttest \"$d/$nopath\" = \"$(test-tool path-utils real_path \"$d///$nopath\")\"\n+\techo \"$d\" >expect &&\n+\ttest-tool path-utils real_path \"$d///\" >actual &&\n+\ttest_cmp expect actual &&\n+\n+\tnopath=\"hopefully-absent-path\" &&\n+\techo \"$d/$nopath\" >expect &&\n+\ttest-tool path-utils real_path \"$d///$nopath\" >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success SYMLINKS 'real path works on symlinks' '\n@@ -227,19 +264,29 @@ test_expect_success SYMLINKS 'real path works on symlinks' '\n \tmkdir third &&\n \tdir=\"$(cd .git && pwd -P)\" &&\n \tdir2=third/../second/other/.git &&\n-\ttest \"$dir\" = \"$(test-tool path-utils real_path $dir2)\" &&\n+\techo \"$dir\" >expect &&\n+\ttest-tool path-utils real_path $dir2 >actual &&\n+\ttest_cmp expect actual &&\n \tfile=\"$dir\"/index &&\n-\ttest \"$file\" = \"$(test-tool path-utils real_path $dir2/index)\" &&\n+\techo \"$file\" >expect &&\n+\ttest-tool path-utils real_path $dir2/index >actual &&\n+\ttest_cmp expect actual &&\n \tbasename=blub &&\n-\ttest \"$dir/$basename\" = \"$(cd .git && test-tool path-utils real_path \"$basename\")\" &&\n+\techo \"$dir/$basename\" >expect &&\n+\ttest-tool -C .git path-utils real_path \"$basename\" >actual &&\n+\ttest_cmp expect actual &&\n \tln -s ../first/file .git/syml &&\n \tsym=\"$(cd first && pwd -P)\"/file &&\n-\ttest \"$sym\" = \"$(test-tool path-utils real_path \"$dir2/syml\")\"\n+\techo \"$sym\" >expect &&\n+\ttest-tool path-utils real_path \"$dir2/syml\" >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success SYMLINKS 'prefix_path works with absolute paths to work tree symlinks' '\n \tln -s target symlink &&\n-\ttest \"$(test-tool path-utils prefix_path prefix \"$(pwd)/symlink\")\" = \"symlink\"\n+\techo \"symlink\" >expect &&\n+\ttest-tool path-utils prefix_path prefix \"$(pwd)/symlink\" >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'prefix_path works with only absolute path to work tree' '\ndiff --git a/t/t0100-previous.sh b/t/t0100-previous.sh\nindex a16cc3d2983..70a3223f219 100755\n--- a/t/t0100-previous.sh\n+++ b/t/t0100-previous.sh\n@@ -12,7 +12,9 @@ test_expect_success 'branch -d @{-1}' '\n \ttest_commit A &&\n \tgit checkout -b junk &&\n \tgit checkout - &&\n-\ttest \"$(git symbolic-ref HEAD)\" = refs/heads/main &&\n+\techo refs/heads/main >expect &&\n+\tgit symbolic-ref HEAD >actual &&\n+\ttest_cmp expect actual &&\n \tgit branch -d @{-1} &&\n \ttest_must_fail git rev-parse --verify refs/heads/junk\n '\n@@ -21,7 +23,9 @@ test_expect_success 'branch -d @{-12} when there is not enough switches yet' '\n \tgit reflog expire --expire=now &&\n \tgit checkout -b junk2 &&\n \tgit checkout - &&\n-\ttest \"$(git symbolic-ref HEAD)\" = refs/heads/main &&\n+\techo refs/heads/main >expect &&\n+\tgit symbolic-ref HEAD >actual &&\n+\ttest_cmp expect actual &&\n \ttest_must_fail git branch -d @{-12} &&\n \tgit rev-parse --verify refs/heads/main\n '\ndiff --git a/t/t1504-ceiling-dirs.sh b/t/t1504-ceiling-dirs.sh\nindex 0fafcf9dde3..c1679e31d8a 100755\n--- a/t/t1504-ceiling-dirs.sh\n+++ b/t/t1504-ceiling-dirs.sh\n@@ -6,8 +6,12 @@ TEST_PASSES_SANITIZE_LEAK=true\n . ./test-lib.sh\n \n test_prefix() {\n-\ttest_expect_success \"$1\" \\\n-\t\"test '$2' = \\\"\\$(git rev-parse --show-prefix)\\\"\"\n+\tlocal expect=\"$2\" &&\n+\ttest_expect_success \"$1: git rev-parse --show-prefix is '$2'\" '\n+\t\techo \"$expect\" >expect &&\n+\t\tgit rev-parse --show-prefix >actual &&\n+\t\ttest_cmp expect actual\n+\t'\n }\n \n test_fail() {\ndiff --git a/t/t2005-checkout-index-symlinks.sh b/t/t2005-checkout-index-symlinks.sh\nindex 112682a45a1..67d18cfa104 100755\n--- a/t/t2005-checkout-index-symlinks.sh\n+++ b/t/t2005-checkout-index-symlinks.sh\n@@ -22,8 +22,10 @@ test_expect_success \\\n git checkout-index symlink &&\n test -f symlink'\n \n-test_expect_success \\\n-'the file must be the blob we added during the setup' '\n-test \"$(git hash-object -t blob symlink)\" = $l'\n+test_expect_success 'the file must be the blob we added during the setup' '\n+\techo \"$l\" >expect &&\n+\tgit hash-object -t blob symlink >actual &&\n+\ttest_cmp expect actual\n+'\n \n test_done\ndiff --git a/t/t5522-pull-symlink.sh b/t/t5522-pull-symlink.sh\nindex bcff460d0a2..9fb73a8c3eb 100755\n--- a/t/t5522-pull-symlink.sh\n+++ b/t/t5522-pull-symlink.sh\n@@ -78,7 +78,9 @@ test_expect_success SYMLINKS 'pushing from symlinked subdir' '\n \t\tgit commit -m push ./file &&\n \t\tgit push\n \t) &&\n-\ttest push = $(git show HEAD:subdir/file)\n+\techo push >expect &&\n+\tgit show HEAD:subdir/file >actual &&\n+\ttest_cmp expect actual\n '\n \n test_done\ndiff --git a/t/t7402-submodule-rebase.sh b/t/t7402-submodule-rebase.sh\nindex 1927a862839..c74798e8d24 100755\n--- a/t/t7402-submodule-rebase.sh\n+++ b/t/t7402-submodule-rebase.sh\n@@ -55,12 +55,15 @@ chmod a+x fake-editor.sh\n \n test_expect_success 'interactive rebase with a dirty submodule' '\n \n-\ttest submodule = $(git diff --name-only) &&\n+\techo submodule >expect &&\n+\tgit diff --name-only >actual &&\n+\ttest_cmp expect actual &&\n \tHEAD=$(git rev-parse HEAD) &&\n \tGIT_EDITOR=\"\\\"$(pwd)/fake-editor.sh\\\"\" EDITOR_TEXT=\"pick $HEAD\" \\\n \t\tgit rebase -i HEAD^ &&\n-\ttest submodule = $(git diff --name-only)\n-\n+\techo submodule >expect &&\n+\tgit diff --name-only >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'rebase with dirty file and submodule fails' '\ndiff --git a/t/t7504-commit-msg-hook.sh b/t/t7504-commit-msg-hook.sh\nindex a39de8c1126..c0f024eb1ef 100755\n--- a/t/t7504-commit-msg-hook.sh\n+++ b/t/t7504-commit-msg-hook.sh\n@@ -101,7 +101,9 @@ test_expect_success 'setup: commit-msg hook that always fails' '\n '\n \n commit_msg_is () {\n-\ttest \"$(git log --pretty=format:%s%b -1)\" = \"$1\"\n+\tprintf \"%s\" \"$1\" >expect &&\n+\tgit log --pretty=format:%s%b -1 >actual &&\n+\ttest_cmp expect actual\n }\n \n test_expect_success 'with failing hook' '\ndiff --git a/t/t7810-grep.sh b/t/t7810-grep.sh\nindex 8eded6ab274..39d6d713ecb 100755\n--- a/t/t7810-grep.sh\n+++ b/t/t7810-grep.sh\n@@ -1001,7 +1001,9 @@ test_expect_success 'log --committer does not search in timestamp' '\n test_expect_success 'grep with CE_VALID file' '\n \tgit update-index --assume-unchanged t/t &&\n \trm t/t &&\n-\ttest \"$(git grep test)\" = \"t/t:test\" &&\n+\techo \"t/t:test\" >expect &&\n+\tgit grep test >actual &&\n+\ttest_cmp expect actual &&\n \tgit update-index --no-assume-unchanged t/t &&\n \tgit checkout t/t\n '\n-- \n2.39.0.rc1.981.gf846af54b4b\n\n"},{"id":"468432","messageId":"patch-v3-8.8-37c75f4a097-20221202T114733Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v3-0.8-00000000000-20221202T114733Z-avarab@gmail.com","subject":"[PATCH v3 8/8] tests: don't lose mist \"git\" exit codes","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-02T11:52:41Z","receivedAt":"2022-12-02T11:54:24Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Fix a few miscellaneous cases where:\n\n- We lost the \"git\" exit code via \"git ... | grep\"\n- Likewise by having a $(git) argument to git itself\n- Used \"test -z\" to check that a command emitted no output, we can use\n  \"test_must_be_empty\" and &&-chaining instead.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t1401-symbolic-ref.sh    | 3 ++-\n t/t3701-add-interactive.sh | 8 +++++---\n t/t7516-commit-races.sh    | 3 ++-\n 3 files changed, 9 insertions(+), 5 deletions(-)\n\ndiff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh\nindex d708acdb819..5e36899d207 100755\n--- a/t/t1401-symbolic-ref.sh\n+++ b/t/t1401-symbolic-ref.sh\n@@ -33,7 +33,8 @@ test_expect_success 'symbolic-ref refuses non-ref for HEAD' '\n reset_to_sane\n \n test_expect_success 'symbolic-ref refuses bare sha1' '\n-\ttest_must_fail git symbolic-ref HEAD $(git rev-parse HEAD)\n+\trev=$(git rev-parse HEAD) &&\n+\ttest_must_fail git symbolic-ref HEAD \"$rev\"\n '\n \n reset_to_sane\ndiff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh\nindex 5841f280fb2..f1fe5d60677 100755\n--- a/t/t3701-add-interactive.sh\n+++ b/t/t3701-add-interactive.sh\n@@ -296,9 +296,11 @@ test_expect_success FILEMODE 'stage mode and hunk' '\n \techo content >>file &&\n \tchmod +x file &&\n \tprintf \"y\\\\ny\\\\n\" | git add -p &&\n-\tgit diff --cached file | grep \"new mode\" &&\n-\tgit diff --cached file | grep \"+content\" &&\n-\ttest -z \"$(git diff file)\"\n+\tgit diff --cached file >out &&\n+\tgrep \"new mode\" out &&\n+\tgrep \"+content\" out &&\n+\tgit diff file >out &&\n+\ttest_must_be_empty out\n '\n \n # end of tests disabled when filemode is not usable\ndiff --git a/t/t7516-commit-races.sh b/t/t7516-commit-races.sh\nindex f2ce14e9071..2d38a16480e 100755\n--- a/t/t7516-commit-races.sh\n+++ b/t/t7516-commit-races.sh\n@@ -10,7 +10,8 @@ test_expect_success 'race to create orphan commit' '\n \ttest_must_fail env EDITOR=./hare-editor git commit --allow-empty -m tortoise -e &&\n \tgit show -s --pretty=format:%s >subject &&\n \tgrep hare subject &&\n-\ttest -z \"$(git show -s --pretty=format:%P)\"\n+\tgit show -s --pretty=format:%P >out &&\n+\ttest_must_be_empty out\n '\n \n test_expect_success 'race to create non-orphan commit' '\n-- \n2.39.0.rc1.981.gf846af54b4b\n\n"},{"id":"468440","messageId":"8cfb5bc5-6e17-4cac-cc2f-2f900f14fa60@web.de","threadId":"58200","inReplyTo":"patch-v3-2.8-394d5e46494-20221202T114733Z-avarab@gmail.com","subject":"Re: [PATCH v3 2/8] auto-crlf tests: don't lose exit code in loops and outside tests","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2022-12-02T15:59:52Z","receivedAt":"2022-12-02T16:00:22Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 02.12.22 um 12:52 schrieb Ævar Arnfjörð Bjarmason:\n> Change the functions which are called from within\n> \"test_expect_success\" to add the \"|| return 1\" idiom to their\n> for-loops, so we won't lose the exit code of \"cp\", \"git\" etc.\n>\n> Then for those setup functions that aren't called from a\n> \"test_expect_success\" we need to put the setup code in a\n> \"test_expect_success\" as well. It would not be enough to properly\n> &&-chain these, as the calling code is the top-level script itself. As\n> we don't run the tests with \"set -e\" we won't report failing commands\n> at the top-level.\n>\n> The \"checkout\" part of this would miss memory leaks under\n> SANITIZE=leak, this code doesn't leak (the relevant \"git checkout\"\n> leak has been fixed), but in a past version of git we'd continue past\n> this failure under SANITIZE=leak when these invocations had errored\n> out, even under \"--immediate\".\n>\n> Helped-by: René Scharfe <l.s.r@web.de>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  t/t0027-auto-crlf.sh | 60 +++++++++++++++++++++++++-------------------\n>  1 file changed, 34 insertions(+), 26 deletions(-)\n>\n> diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\n> index a94ac1eae37..23f2e613401 100755\n> --- a/t/t0027-auto-crlf.sh\n> +++ b/t/t0027-auto-crlf.sh\n> @@ -70,7 +70,8 @@ create_NNO_MIX_files () {\n>  \t\t\t\tcp CRLF        ${pfx}_CRLF.txt &&\n>  \t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt &&\n>  \t\t\t\tcp LF_mix_CR   ${pfx}_LF_mix_CR.txt &&\n> -\t\t\t\tcp CRLF_nul    ${pfx}_CRLF_nul.txt\n> +\t\t\t\tcp CRLF_nul    ${pfx}_CRLF_nul.txt ||\n> +\t\t\t\treturn 1\n>  \t\t\tdone\n>  \t\tdone\n>  \tdone\n> @@ -101,7 +102,8 @@ commit_check_warn () {\n>  \tdo\n>  \t\tfname=${pfx}_$f.txt &&\n>  \t\tcp $f $fname &&\n> -\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\"\n> +\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\" ||\n> +\t\treturn 1\n>  \tdone &&\n>  \tgit commit -m \"core.autocrlf $crlf\" &&\n>  \tcheck_warning \"$lfname\" ${pfx}_LF.err &&\n> @@ -121,15 +123,19 @@ commit_chk_wrnNNO () {\n>  \tlfmixcr=$1 ; shift\n>  \tcrlfnul=$1 ; shift\n>  \tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n> -\t#Commit files on top of existing file\n> -\tcreate_gitattributes \"$attr\" $aeol &&\n> -\tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n> -\tdo\n> -\t\tfname=${pfx}_$f.txt &&\n> -\t\tcp $f $fname &&\n> -\t\tprintf Z >>\"$fname\" &&\n> -\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\"\n> -\tdone\n> +\n> +\ttest_expect_success 'setup commit NNO files' '\n> +\t\t#Commit files on top of existing file\n> +\t\tcreate_gitattributes \"$attr\" $aeol &&\n> +\t\tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n> +\t\tdo\n> +\t\t\tfname=${pfx}_$f.txt &&\n> +\t\t\tcp $f $fname &&\n> +\t\t\tprintf Z >>\"$fname\" &&\n> +\t\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\" ||\n> +\t\t\treturn 1\n> +\t\tdone\n> +\t'\n>\n>  \ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr LF\" '\n>  \t\tcheck_warning \"$lfwarn\" ${pfx}_LF.err\n> @@ -163,15 +169,19 @@ commit_MIX_chkwrn () {\n>  \tlfmixcr=$1 ; shift\n>  \tcrlfnul=$1 ; shift\n>  \tpfx=MIX_attr_${attr}_aeol_${aeol}_${crlf}\n> -\t#Commit file with CLRF_mix_LF on top of existing file\n> -\tcreate_gitattributes \"$attr\" $aeol &&\n> -\tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n> -\tdo\n> -\t\tfname=${pfx}_$f.txt &&\n> -\t\tcp CRLF_mix_LF $fname &&\n> -\t\tprintf Z >>\"$fname\" &&\n> -\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\"\n> -\tdone\n> +\n> +\ttest_expect_success 'setup commit file with mixed EOL' '\n> +\t\t#Commit file with CLRF_mix_LF on top of existing file\n> +\t\tcreate_gitattributes \"$attr\" $aeol &&\n> +\t\tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n> +\t\tdo\n> +\t\t\tfname=${pfx}_$f.txt &&\n> +\t\t\tcp CRLF_mix_LF $fname &&\n> +\t\t\tprintf Z >>\"$fname\" &&\n> +\t\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\" ||\n> +\t\t\treturn 1\n> +\t\tdone\n> +\t'\n>\n>  \ttest_expect_success \"commit file with mixed EOL onto LF crlf=$crlf attr=$attr\" '\n>  \t\tcheck_warning \"$lfwarn\" ${pfx}_LF.err\n> @@ -294,12 +304,10 @@ checkout_files () {\n\nThe context lines right here are:\n\n\tcreate_gitattributes \"$attr\" $ident $aeol &&\n\tgit config core.autocrlf $crlf &&\n\nThose better be covered by test_expect_success as well, right?  Wrap them and\nthe whole loop in a single test_expect_success, like you did above?\n\n>  \tpfx=eol_${ceol}_crlf_${crlf}_attr_${attr}_ &&\n>  \tfor f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul\n>  \tdo\n> -\t\trm crlf_false_attr__$f.txt &&\n> -\t\tif test -z \"$ceol\"; then\n> -\t\t\tgit checkout -- crlf_false_attr__$f.txt\n> -\t\telse\n> -\t\t\tgit -c core.eol=$ceol checkout -- crlf_false_attr__$f.txt\n> -\t\tfi\n> +\t\ttest_expect_success \"setup $f checkout ${ceol:+ with -c core.eol=$ceol}\"  '\n> +\t\t\trm -f crlf_false_attr__$f.txt &&\n> +\t\t\tgit ${ceol:+-c core.eol=$ceol} checkout -- crlf_false_attr__$f.txt\n> +\t\t'\n>  \tdone\n>\n>  \ttest_expect_success \"ls-files --eol attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol\" '\n"},{"id":"468441","messageId":"674c54d5-2458-5e11-debb-9f88489be089@web.de","threadId":"58200","inReplyTo":"patch-v3-4.8-c080899dd5f-20221202T114733Z-avarab@gmail.com","subject":"Re: [PATCH v3 4/8] t/lib-patch-mode.sh: fix ignored exit codes","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2022-12-02T15:59:56Z","receivedAt":"2022-12-02T16:00:44Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 02.12.22 um 12:52 schrieb Ævar Arnfjörð Bjarmason:\n> Fix code added in b319ef70a94 (Add a small patch-mode testing library,\n> 2009-08-13) to use &&-chaining and the newly added \"test_cmp_cmd\".\n> This avoids losing both the exit code of a \"git\" and the \"cat\"\n> processes.\n>\n> This fixes cases where we'd have e.g. missed memory leaks under\n> SANITIZE=leak, this code doesn't leak now as far as I can tell, but I\n> discovered it while looking at leaks in related code.\n>\n> The \"cat _head >expect\" here is redundant, we could simply give\n> \"_head\" to \"test_cmp\", but let's be consistent in using the \"expect\"\n> and \"actual\" names for clarity.\n\nThe code at the bottom uses _head directly, which is fine IMHO, but then\nthis sentence should go.\n\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  t/lib-patch-mode.sh | 11 ++++++++---\n>  1 file changed, 8 insertions(+), 3 deletions(-)\n>\n> diff --git a/t/lib-patch-mode.sh b/t/lib-patch-mode.sh\n> index cfd76bf987b..89ca1f78055 100644\n> --- a/t/lib-patch-mode.sh\n> +++ b/t/lib-patch-mode.sh\n> @@ -29,8 +29,12 @@ set_and_save_state () {\n>\n>  # verify_state <path> <expected-worktree-content> <expected-index-content>\n>  verify_state () {\n> -\ttest \"$(cat \"$1\")\" = \"$2\" &&\n> -\ttest \"$(git show :\"$1\")\" = \"$3\"\n> +\techo \"$2\" >expect &&\n> +\ttest_cmp expect \"$1\" &&\n> +\n> +\techo \"$3\" >expect &&\n> +\tgit show :\"$1\" >actual &&\n> +\ttest_cmp expect actual\n>  }\n>\n>  # verify_saved_state <path>\n> @@ -46,5 +50,6 @@ save_head () {\n>  }\n>\n>  verify_saved_head () {\n> -\ttest \"$(cat _head)\" = \"$(git rev-parse HEAD)\"\n> +\tgit rev-parse HEAD >actual &&\n> +\ttest_cmp _head actual\n>  }\n"},{"id":"468457","messageId":"3304ac3c-0d45-7293-bd7f-08f374786dcc@web.de","threadId":"58200","inReplyTo":"patch-v3-7.8-307f25db831-20221202T114733Z-avarab@gmail.com","subject":"Re: [PATCH v3 7/8] tests: don't lose \"git\" exit codes in \"! ( git ... | grep )\"","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2022-12-02T18:31:00Z","receivedAt":"2022-12-02T18:31:13Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 02.12.22 um 12:52 schrieb Ævar Arnfjörð Bjarmason:\n> Change tests that would lose the \"git\" exit code via a negation\n> pattern to:\n>\n> - In the case of \"t0055-beyond-symlinks.sh\" compare against the\n>   expected output instead.\n>\n> - For \"t3700-add.sh\" use \"sed -n\" to print the expected \"bad\" part,\n>   and use \"test_must_be_empty\" to assert that it's not there.\n>\n>   We can also remove a repeated invocation of \"git ls-files\" for the\n>   last test that's being modified in that file, and search the\n>   existing \"files\" output instead.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  t/t0055-beyond-symlinks.sh | 14 ++++++++++++--\n>  t/t3700-add.sh             | 18 +++++++++++++-----\n>  2 files changed, 25 insertions(+), 7 deletions(-)\n>\n> diff --git a/t/t0055-beyond-symlinks.sh b/t/t0055-beyond-symlinks.sh\n> index 6bada370225..c3eb1158ef9 100755\n> --- a/t/t0055-beyond-symlinks.sh\n> +++ b/t/t0055-beyond-symlinks.sh\n> @@ -15,12 +15,22 @@ test_expect_success SYMLINKS setup '\n>\n>  test_expect_success SYMLINKS 'update-index --add beyond symlinks' '\n>  \ttest_must_fail git update-index --add c/d &&\n> -\t! ( git ls-files | grep c/d )\n> +\tcat >expect <<-\\EOF &&\n> +\ta\n> +\tb/d\n> +\tEOF\n> +\tgit ls-files >actual &&\n> +\ttest_cmp expect actual\n>  '\n\nHmm, this makes the test depend on the other files.  Adding more of them\nfor a different test now requires updating this test as well.  Why not\nhandle it like you did in t3700 below?\n\n>\n>  test_expect_success SYMLINKS 'add beyond symlinks' '\n>  \ttest_must_fail git add c/d &&\n> -\t! ( git ls-files | grep c/d )\n> +\tcat >expect <<-\\EOF &&\n> +\ta\n> +\tb/d\n> +\tEOF\n> +\tgit ls-files >actual &&\n> +\ttest_cmp expect actual\n>  '\n\nSame here.\n\n>\n>  test_done\n> diff --git a/t/t3700-add.sh b/t/t3700-add.sh\n> index 51afbd7b24a..82dd768944f 100755\n> --- a/t/t3700-add.sh\n> +++ b/t/t3700-add.sh\n> @@ -106,24 +106,32 @@ test_expect_success '.gitignore test setup' '\n>\n>  test_expect_success '.gitignore is honored' '\n>  \tgit add . &&\n> -\t! (git ls-files | grep \"\\\\.ig\")\n> +\tgit ls-files >files &&\n> +\tsed -n \"/\\\\.ig/p\" <files >actual &&\n> +\ttest_must_be_empty actual\n>  '\n\nYou use sed instead of grep because no match is expected and sed returns\n0 even then, while grep would exit with code 1, correct?  OK.\n\nCan we use that, though?  I.e. how about this?\n\n\tgit ls-files >files &&\n\ttest_expect_code 1 grep \"\\\\.ig\" files\n\nIt would print the unexpected lines in verbose mode like this:\n\n\texpecting success of 3700.12 '.gitignore is honored':\n\t\tgit add . &&\n\t\tgit ls-files >files &&\n\t\techo foo.ig >files &&\t# inject bogus value\n\t\ttest_expect_code 1 grep \"\\\\.ig\" files\n\n\tfoo.ig\n\ttest_expect_code: command exited with 0, we wanted 1 grep \\.ig files\n\nOr can we trust ls-files' own filtering?\n\n\tgit ls-files \"*.ig\" >actual &&\n\ttest_must_be_empty actual\n\nBoth variants are shorter and should be slightly faster, which can\nmatter if we use that pattern more widely.\n\n(Didn't measure here, but from a recent foray into t3920 on Windows I\ntook home that removing commands has a small, but measurable impact there:\nhttps://lore.kernel.org/git/203cb627-2423-8a35-d280-9f9ffc66e072@web.de/T/#u)\n\n>\n>  test_expect_success 'error out when attempting to add ignored ones without -f' '\n>  \ttest_must_fail git add a.?? &&\n> -\t! (git ls-files | grep \"\\\\.ig\")\n> +\tgit ls-files >files &&\n> +\tsed -n \"/\\\\.ig/p\" <files >actual &&\n> +\ttest_must_be_empty actual\n>  '\n>\n>  test_expect_success 'error out when attempting to add ignored ones without -f' '\n>  \ttest_must_fail git add d.?? &&\n> -\t! (git ls-files | grep \"\\\\.ig\")\n> +\tgit ls-files >files &&\n> +\tsed -n \"/\\\\.ig/p\" <files >actual &&\n> +\ttest_must_be_empty actual\n>  '\n>\n>  test_expect_success 'error out when attempting to add ignored ones but add others' '\n>  \ttouch a.if &&\n>  \ttest_must_fail git add a.?? &&\n> -\t! (git ls-files | grep \"\\\\.ig\") &&\n> -\t(git ls-files | grep a.if)\n> +\tgit ls-files >files &&\n> +\tsed -n \"/\\\\.ig/p\" <files >actual &&\n> +\ttest_must_be_empty actual &&\n> +\tgrep a.if files\n>  '\n>\n>  test_expect_success 'add ignored ones with -f' '\n"},{"id":"468494","messageId":"CAPig+cTh487GoAnw9CD7i2GmKzAtoG=1hwGdxXHQYoK6Vi=Arw@mail.gmail.com","threadId":"58200","inReplyTo":"patch-v3-8.8-37c75f4a097-20221202T114733Z-avarab@gmail.com","subject":"Re: [PATCH v3 8/8] tests: don't lose mist \"git\" exit codes","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2022-12-04T00:40:49Z","receivedAt":"2022-12-04T00:41:08Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, Dec 2, 2022 at 6:53 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n> tests: don't lose mist \"git\" exit codes\n\n\"mist\"?\n\n> Fix a few miscellaneous cases where:\n>\n> - We lost the \"git\" exit code via \"git ... | grep\"\n> - Likewise by having a $(git) argument to git itself\n> - Used \"test -z\" to check that a command emitted no output, we can use\n>   \"test_must_be_empty\" and &&-chaining instead.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n"},{"id":"468495","messageId":"CAPig+cTm5GbpbeSRajEe+uP4MwbAwACL2Q19o1RSLgHQ+eeKKg@mail.gmail.com","threadId":"58200","inReplyTo":"patch-v3-4.8-c080899dd5f-20221202T114733Z-avarab@gmail.com","subject":"Re: [PATCH v3 4/8] t/lib-patch-mode.sh: fix ignored exit codes","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2022-12-04T00:45:14Z","receivedAt":"2022-12-04T00:45:28Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, Dec 2, 2022 at 6:53 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n> Fix code added in b319ef70a94 (Add a small patch-mode testing library,\n> 2009-08-13) to use &&-chaining and the newly added \"test_cmp_cmd\".\n> This avoids losing both the exit code of a \"git\" and the \"cat\"\n> processes.\n\nThis still talks about test_cmp_cmd() which is no longer present in v3.\n\n> This fixes cases where we'd have e.g. missed memory leaks under\n> SANITIZE=leak, this code doesn't leak now as far as I can tell, but I\n> discovered it while looking at leaks in related code.\n>\n> The \"cat _head >expect\" here is redundant, we could simply give\n> \"_head\" to \"test_cmp\", but let's be consistent in using the \"expect\"\n> and \"actual\" names for clarity.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n"},{"id":"468501","messageId":"xmqqlenmu241.fsf@gitster.g","threadId":"58200","inReplyTo":"patch-v3-3.8-4ec075689f6-20221202T114733Z-avarab@gmail.com","subject":"Re: [PATCH v3 3/8] diff tests: fix ignored exit codes in t4023","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-12-05T00:26:54Z","receivedAt":"2022-12-05T00:28:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Change a \"git diff-tree\" command to be &&-chained so that we won't\n> ignore its exit code, see the ea05fd5fbf7 (Merge branch\n> 'ab/keep-git-exit-codes-in-tests', 2022-03-16) topic for prior art.\n>\n> This fixes code added in b45563a229f (rename: Break filepairs with\n> different types., 2007-11-30). Due to hiding the exit code we hid a\n> memory leak under SANITIZE=leak.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  t/t4023-diff-rename-typechange.sh | 12 ++++++------\n>  1 file changed, 6 insertions(+), 6 deletions(-)\n\nI already have this as 1ebeb849 (diff tests: fix ignored exit codes\nin t4023, 2022-12-02) on ab/t4023-avoid-losing-exit-status-of-diff\ntopic.\n\nThanks.\n\n\n>\n> diff --git a/t/t4023-diff-rename-typechange.sh b/t/t4023-diff-rename-typechange.sh\n> index 7cb99092938..25c31b0cb1b 100755\n> --- a/t/t4023-diff-rename-typechange.sh\n> +++ b/t/t4023-diff-rename-typechange.sh\n> @@ -52,8 +52,8 @@ test_expect_success setup '\n>  '\n>  \n>  test_expect_success 'cross renames to be detected for regular files' '\n> -\n> -\tgit diff-tree five six -r --name-status -B -M | sort >actual &&\n> +\tgit diff-tree five six -r --name-status -B -M >out &&\n> +\tsort <out >actual &&\n>  \t{\n>  \t\techo \"R100\tfoo\tbar\" &&\n>  \t\techo \"R100\tbar\tfoo\"\n> @@ -63,8 +63,8 @@ test_expect_success 'cross renames to be detected for regular files' '\n>  '\n>  \n>  test_expect_success 'cross renames to be detected for typechange' '\n> -\n> -\tgit diff-tree one two -r --name-status -B -M | sort >actual &&\n> +\tgit diff-tree one two -r --name-status -B -M >out &&\n> +\tsort <out >actual &&\n>  \t{\n>  \t\techo \"R100\tfoo\tbar\" &&\n>  \t\techo \"R100\tbar\tfoo\"\n> @@ -74,8 +74,8 @@ test_expect_success 'cross renames to be detected for typechange' '\n>  '\n>  \n>  test_expect_success 'moves and renames' '\n> -\n> -\tgit diff-tree three four -r --name-status -B -M | sort >actual &&\n> +\tgit diff-tree three four -r --name-status -B -M >out &&\n> +\tsort <out >actual &&\n>  \t{\n>  \t\t# see -B -M (#6) in t4008\n>  \t\techo \"C100\tfoo\tbar\" &&\n"},{"id":"468502","messageId":"xmqqpmcyu27w.fsf@gitster.g","threadId":"58200","inReplyTo":"patch-v3-1.8-64dfec31fb3-20221202T114733Z-avarab@gmail.com","subject":"Re: [PATCH v3 1/8] merge tests: don't ignore \"rev-parse\" exit code in helper","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-12-05T00:24:35Z","receivedAt":"2022-12-05T00:28:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Subject: Re: [PATCH v3 1/8] merge tests: don't ignore \"rev-parse\" exit code in helper\n\nJust one is inclded here, so I'll retitle (and I am tempted to\ndisassemble the \"series\" into separate individual topics, as that\nwill help to use good bits early without getting distracted by the\nrest) this to something like \"s/^[^:]*:/t7600:/\"\n\n> Change the verify_mergeheads() helper the check the exit code of \"git\n> rev-parse\".\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  t/t7600-merge.sh | 2 +-\n>  1 file changed, 1 insertion(+), 1 deletion(-)\n\nThanks.\n\n>\n> diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh\n> index 7c3f6ed9943..060e145957f 100755\n> --- a/t/t7600-merge.sh\n> +++ b/t/t7600-merge.sh\n> @@ -105,7 +105,7 @@ verify_mergeheads () {\n>  \ttest_write_lines \"$@\" >mergehead.expected &&\n>  \twhile read sha1 rest\n>  \tdo\n> -\t\tgit rev-parse $sha1\n> +\t\tgit rev-parse $sha1 || return 1\n>  \tdone <.git/MERGE_HEAD >mergehead.actual &&\n>  \ttest_cmp mergehead.expected mergehead.actual\n>  }\n"},{"id":"468503","messageId":"xmqq7cz6u1in.fsf@gitster.g","threadId":"58200","inReplyTo":"patch-v3-5.8-58ac6fe5604-20221202T114733Z-avarab@gmail.com","subject":"Re: [PATCH v3 5/8] tests: use \"test_cmp\" instead of \"test\" in sub-shells","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-12-05T00:39:44Z","receivedAt":"2022-12-05T00:39:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Convert a few cases where we were using \"test\" inside a sub-shell, and\n> were losing the exit code of \"git\".\n\nThat makes it sound like\n\n\t(\n\t\tcd there &&\n\t\ta=$(git something expected to be silent) &&\n\t\ttest -z \"$a\"\n\t) &&\n\t...\n\nis bad, and it can be improved somehow by using \"test_cmp\" instead\nof \"test\", but I do not think that is what you meant (in fact, the\ncommand substitution used above is safe and we catch failing git).\n\nAfter looking at a few samples from the patch s/sub-shell/command\nsubstitution/ might be what you meant, i.e.\n\n\ttest -z \"$(git something) &&\n\t...\n\nis bad and we want \n\n\tgit something >out &&\n\t! test -s out\n\nto keep the exit code from \"git\".  IOW, fixing the lossage of exit\ncode has little to do with the use of test vs test_cmp.\n\nPerhaps retitle to\n\n    Subject: [PATCH] tests: avoid \"test op $(git foo)\" lose exit status of git\n\n    Rewrite tests that ran \"git\" inside command substitution and\n    lost exit status of \"git\" so that we notice failing \"git\".\n\nor something like that.\n\n> In the case of \"t3200-branch.sh\" some adjacent code outside of a\n> sub-shell that was losing the exit code is also being converted, as\n> it's within the same hunk.\n\nAgain s/sub-shell/command substitution?, I think.\n\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  t/lib-httpd.sh              |  5 +++--\n>  t/lib-submodule-update.sh   | 22 +++++++++-------------\n>  t/t0060-path-utils.sh       |  4 +++-\n>  t/t3200-branch.sh           | 13 +++++++------\n>  t/t5605-clone-local.sh      | 15 ++++++++++-----\n>  t/t7402-submodule-rebase.sh | 14 +++++++++++---\n>  6 files changed, 43 insertions(+), 30 deletions(-)\n>\n> diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh\n> index 608949ea80b..31e7fa3010c 100644\n> --- a/t/lib-httpd.sh\n> +++ b/t/lib-httpd.sh\n> @@ -217,8 +217,9 @@ test_http_push_nonff () {\n>  \t\tgit commit -a -m path2 --amend &&\n>  \n>  \t\ttest_must_fail git push -v origin >output 2>&1 &&\n> -\t\t(cd \"$REMOTE_REPO\" &&\n> -\t\t test $HEAD = $(git rev-parse --verify HEAD))\n> +\t\techo \"$HEAD\" >expect &&\n> +\t\tgit -C \"$REMOTE_REPO\" rev-parse --verify HEAD >actual &&\n> +\t\ttest_cmp expect actual\n>  \t'\n>  \n>  \ttest_expect_success 'non-fast-forward push show ref status' '\n> diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\n> index 2d31fcfda1f..d7c2b670b4a 100644\n> --- a/t/lib-submodule-update.sh\n> +++ b/t/lib-submodule-update.sh\n> @@ -168,20 +168,16 @@ replace_gitfile_with_git_dir () {\n>  # Note that this only supports submodules at the root level of the\n>  # superproject, with the default name, i.e. same as its path.\n>  test_git_directory_is_unchanged () {\n> -\t(\n> -\t\tcd \".git/modules/$1\" &&\n> -\t\t# does core.worktree point at the right place?\n> -\t\ttest \"$(git config core.worktree)\" = \"../../../$1\" &&\n> -\t\t# remove it temporarily before comparing, as\n> -\t\t# \"$1/.git/config\" lacks it...\n> -\t\tgit config --unset core.worktree\n> -\t) &&\n> +\t# does core.worktree point at the right place?\n> +\techo \"../../../$1\" >expect &&\n> +\tgit -C \".git/modules/$1\" config core.worktree >actual &&\n> +\ttest_cmp expect actual &&\n> +\t# remove it temporarily before comparing, as\n> +\t# \"$1/.git/config\" lacks it...\n> +\tgit -C \".git/modules/$1\" config --unset core.worktree &&\n>  \tdiff -r \".git/modules/$1\" \"$1/.git\" &&\n> -\t(\n> -\t\t# ... and then restore.\n> -\t\tcd \".git/modules/$1\" &&\n> -\t\tgit config core.worktree \"../../../$1\"\n> -\t)\n> +\t# ... and then restore.\n> +\tgit -C \".git/modules/$1\" config core.worktree \"../../../$1\"\n>  }\n>  \n>  test_git_directory_exists () {\n> diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh\n> index 68e29c904a6..53ec717cbca 100755\n> --- a/t/t0060-path-utils.sh\n> +++ b/t/t0060-path-utils.sh\n> @@ -255,7 +255,9 @@ test_expect_success 'prefix_path rejects absolute path to dir with same beginnin\n>  test_expect_success SYMLINKS 'prefix_path works with absolute path to a symlink to work tree having  same beginning as work tree' '\n>  \tgit init repo &&\n>  \tln -s repo repolink &&\n> -\ttest \"a\" = \"$(cd repo && test-tool path-utils prefix_path prefix \"$(pwd)/../repolink/a\")\"\n> +\techo \"a\" >expect &&\n> +\ttest-tool -C repo path-utils prefix_path prefix \"$(cd repo && pwd)/../repolink/a\" >actual &&\n> +\ttest_cmp expect actual\n>  '\n>  \n>  relative_path /foo/a/b/c/\t/foo/a/b/\tc/\n> diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\n> index 5a169b68d6a..f5fbb84262b 100755\n> --- a/t/t3200-branch.sh\n> +++ b/t/t3200-branch.sh\n> @@ -242,12 +242,13 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou\n>  test_expect_success 'git branch -M baz bam should succeed within a worktree in which baz is checked out' '\n>  \tgit checkout -b baz &&\n>  \tgit worktree add -f bazdir baz &&\n> -\t(\n> -\t\tcd bazdir &&\n> -\t\tgit branch -M baz bam &&\n> -\t\ttest $(git rev-parse --abbrev-ref HEAD) = bam\n> -\t) &&\n> -\ttest $(git rev-parse --abbrev-ref HEAD) = bam &&\n> +\tgit -C \"$bazdir\" branch -M baz bam &&\n> +\techo \"bam\" >expect &&\n> +\tgit -C \"$bazdir\" rev-parse --abbrev-ref HEAD >actual &&\n> +\ttest_cmp expect actual &&\n> +\techo \"bam\" >expect &&\n> +\tgit rev-parse --abbrev-ref HEAD >actual &&\n> +\ttest_cmp expect actual &&\n>  \trm -r bazdir &&\n>  \tgit worktree prune\n>  '\n> diff --git a/t/t5605-clone-local.sh b/t/t5605-clone-local.sh\n> index 38b850c10ef..61a2342bc2c 100755\n> --- a/t/t5605-clone-local.sh\n> +++ b/t/t5605-clone-local.sh\n> @@ -15,8 +15,12 @@ test_expect_success 'preparing origin repository' '\n>  \t: >file && git add . && git commit -m1 &&\n>  \tgit clone --bare . a.git &&\n>  \tgit clone --bare . x &&\n> -\ttest \"$(cd a.git && git config --bool core.bare)\" = true &&\n> -\ttest \"$(cd x && git config --bool core.bare)\" = true &&\n> +\techo true >expect &&\n> +\tgit -C a.git config --bool core.bare >actual &&\n> +\ttest_cmp expect actual &&\n> +\techo true >expect &&\n> +\tgit -C x config --bool core.bare >actual &&\n> +\ttest_cmp expect actual &&\n>  \tgit bundle create b1.bundle --all &&\n>  \tgit bundle create b2.bundle main &&\n>  \tmkdir dir &&\n> @@ -28,9 +32,10 @@ test_expect_success 'preparing origin repository' '\n>  \n>  test_expect_success 'local clone without .git suffix' '\n>  \tgit clone -l -s a b &&\n> -\t(cd b &&\n> -\ttest \"$(git config --bool core.bare)\" = false &&\n> -\tgit fetch)\n> +\techo false >expect &&\n> +\tgit -C b config --bool core.bare >actual &&\n> +\ttest_cmp expect actual &&\n> +\tgit -C b fetch\n>  '\n>  \n>  test_expect_success 'local clone with .git suffix' '\n> diff --git a/t/t7402-submodule-rebase.sh b/t/t7402-submodule-rebase.sh\n> index ebeca12a711..1927a862839 100755\n> --- a/t/t7402-submodule-rebase.sh\n> +++ b/t/t7402-submodule-rebase.sh\n> @@ -82,11 +82,19 @@ test_expect_success 'stash with a dirty submodule' '\n>  \tCURRENT=$(cd submodule && git rev-parse HEAD) &&\n>  \tgit stash &&\n>  \ttest new != $(cat file) &&\n> -\ttest submodule = $(git diff --name-only) &&\n> -\ttest $CURRENT = $(cd submodule && git rev-parse HEAD) &&\n> +\techo submodule >expect &&\n> +\tgit diff --name-only >actual &&\n> +\ttest_cmp expect actual &&\n> +\n> +\techo \"$CURRENT\" >expect &&\n> +\tgit -C submodule rev-parse HEAD >actual &&\n> +\ttest_cmp expect actual &&\n> +\n>  \tgit stash apply &&\n>  \ttest new = $(cat file) &&\n> -\ttest $CURRENT = $(cd submodule && git rev-parse HEAD)\n> +\techo \"$CURRENT\" >expect &&\n> +\tgit -C submodule rev-parse HEAD >actual &&\n> +\ttest_cmp expect actual\n>  \n>  '\n"},{"id":"468504","messageId":"xmqq1qpeu18r.fsf@gitster.g","threadId":"58200","inReplyTo":"CAPig+cTh487GoAnw9CD7i2GmKzAtoG=1hwGdxXHQYoK6Vi=Arw@mail.gmail.com","subject":"Re: [PATCH v3 8/8] tests: don't lose mist \"git\" exit codes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-12-05T00:45:40Z","receivedAt":"2022-12-05T00:45:44Z","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> On Fri, Dec 2, 2022 at 6:53 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n>> tests: don't lose mist \"git\" exit codes\n>\n> \"mist\"?\n\ns/t/c/ I thought.\n\nIn any case, it seems like 5,6,7,8/8 all are about using $(cmd) as\nan argument to another command (as opposed to placing it on the\nright side of a variable assignment) that loses the exit status of\nrunning $(cmd), and it is a bit confusing which piece should go into\nwhich one of these four.  It might make more sense to reorganize\nthese four steps along the file boundary.\n\n\n"},{"id":"468692","messageId":"CAPig+cSgzzNhSx=iauGxgvP5OAqRChuDoenFYYs06iW_=Z_vEw@mail.gmail.com","threadId":"58200","inReplyTo":"221202.861qpiglto.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH v2 1/8] log tests: don't use \"exit 1\" outside a sub-shell","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2022-12-07T06:09:41Z","receivedAt":"2022-12-07T06:09:57Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, Dec 2, 2022 at 5:08 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n> On Fri, Dec 02 2022, Eric Sunshine wrote:\n> > It might make more sense to turn this on its head and make it a\n> > linting issue and simply throw a \"?!FOO?!\" as is done for other\n> > suspect shell code. In fact, I already have local chainlint.pl patches\n> > which detect whether a subshell is active so that the linter can\n> > complain if it sees `cd` outside of a subshell. I would think that\n> > warning about misuse of `exit 1` outside a subshell (and perhaps\n> > `return 1` inside a subshell) should be possible, though I haven't\n> > thought through all the possibilities.\n>\n> That would be great. As a reminder I think (maybe it's not what you have\n> in mind exactly?) that we had a brief discussion on this topic starting\n> at [1]. I.e. I was hoping chainlint.pl could be extended to detect\n> exactly these sort of \"test...$(git\" patterns (among other things).\n\nI recall it but haven't really put any additional thought into it. I\ndid put a little bit of thought into how to upgrade chainlint.pl to\nsupplant check-non-portable-shell.pl, though that doesn't help much\nwith your wish list. More recently, I've been thinking that it might\nmake more sense for chainlint.pl to generate an AST rather than\nworking against the raw token stream, which may mesh better with the\nsort of rewriting you mentioned, and may simplify (or complexify) some\nof the linting heuristics. I haven't really thought it through yet,\nand I'm always concerned about slowing down the script too much -- but\nperhaps I'm worrying unnecessarily if your Makefile-based\nparallelization patches land, or if we just rip out parallelization\naltogether as Peff was suggesting.\n\n> This topic doesn't get us there, but once we finally get rid of some of\n> those patterns it would be nice to have assertions to ensure they don't\n> come back.\n\nYa.\n"},{"id":"469268","messageId":"cover-v4-0.6-00000000000-20221219T101240Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v3-0.8-00000000000-20221202T114733Z-avarab@gmail.com","subject":"[PATCH v4 0/6] tests: fix ignored & hidden exit codes","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-19T10:19:23Z","receivedAt":"2022-12-19T10:19:40Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Various fixes for \"git\" on the LHS of a pipe, but mostly when in\n\"test\" expressions like:\n\n\ttest str = \"$(git some-command)\" &&\n\nChanges since v3[1]:\n\n * The previous 1/8 and 3/8 were picked independently, and have landed\n   on \"master\". I was waiting for those to graduate before a re-roll.\n * Add a missing test_expect_success to 1/6, as pointed out by René\n   (thanks!).\n * Remove commit message mention of the now-dead test_cmp_cmd (thanks\n   Eric!)\n * Reword commit messages, fix typos etc. (thanks Junio, and other\n   reviewers!)\n\nI think this should address all of the feedback on the v3, except\nJunio's suggestion of perhaps re-arranging this series around file\nboundaries.\n\nGiven the potential size of that range-diff I thought it was better to\nmosttly keep the same structure.\n\n1. https://lore.kernel.org/git/cover-v3-0.8-00000000000-20221202T114733Z-avarab@gmail.com/\n\nÆvar Arnfjörð Bjarmason (6):\n  auto-crlf tests: don't lose exit code in loops and outside tests\n  t/lib-patch-mode.sh: fix ignored exit codes\n  tests: don't lose exit status with \"(cd ...; test <op> $(git ...))\"\n  tests: don't lose exit status with \"test <op> $(git ...)\"\n  tests: don't lose \"git\" exit codes in \"! ( git ... | grep )\"\n  tests: don't lose misc \"git\" exit codes\n\n t/lib-httpd.sh                     |   5 +-\n t/lib-patch-mode.sh                |  11 ++-\n t/lib-submodule-update.sh          |  26 ++++---\n t/t0001-init.sh                    |   9 ++-\n t/t0002-gitfile.sh                 |   4 +-\n t/t0027-auto-crlf.sh               |  66 ++++++++++--------\n t/t0055-beyond-symlinks.sh         |  14 +++-\n t/t0060-path-utils.sh              | 107 +++++++++++++++++++++--------\n t/t0100-previous.sh                |   8 ++-\n t/t1401-symbolic-ref.sh            |   3 +-\n t/t1504-ceiling-dirs.sh            |   8 ++-\n t/t2005-checkout-index-symlinks.sh |   8 ++-\n t/t3200-branch.sh                  |  13 ++--\n t/t3700-add.sh                     |  18 +++--\n t/t3701-add-interactive.sh         |   8 ++-\n t/t5522-pull-symlink.sh            |   4 +-\n t/t5605-clone-local.sh             |  15 ++--\n t/t7402-submodule-rebase.sh        |  23 +++++--\n t/t7504-commit-msg-hook.sh         |   4 +-\n t/t7516-commit-races.sh            |   3 +-\n t/t7810-grep.sh                    |   4 +-\n 21 files changed, 243 insertions(+), 118 deletions(-)\n\nRange-diff against v3:\n1:  64dfec31fb3 < -:  ----------- merge tests: don't ignore \"rev-parse\" exit code in helper\n2:  394d5e46494 ! 1:  68d276dd421 auto-crlf tests: don't lose exit code in loops and outside tests\n    @@ t/t0027-auto-crlf.sh: commit_MIX_chkwrn () {\n      \ttest_expect_success \"commit file with mixed EOL onto LF crlf=$crlf attr=$attr\" '\n      \t\tcheck_warning \"$lfwarn\" ${pfx}_LF.err\n     @@ t/t0027-auto-crlf.sh: checkout_files () {\n    + \tlfmixcrlf=$1 ; shift\n    + \tlfmixcr=$1 ; shift\n    + \tcrlfnul=$1 ; shift\n    +-\tcreate_gitattributes \"$attr\" $ident $aeol &&\n    +-\tgit config core.autocrlf $crlf &&\n    ++\ttest_expect_success \"setup config for checkout attr=$attr ident=$ident aeol=$aeol core.autocrlf=$crlf\" '\n    ++\t\tcreate_gitattributes \"$attr\" $ident $aeol &&\n    ++\t\tgit config core.autocrlf $crlf\n    ++\t'\n      \tpfx=eol_${ceol}_crlf_${crlf}_attr_${attr}_ &&\n      \tfor f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul\n      \tdo\n3:  4ec075689f6 < -:  ----------- diff tests: fix ignored exit codes in t4023\n4:  c080899dd5f ! 2:  d351075f0ab t/lib-patch-mode.sh: fix ignored exit codes\n    @@ Commit message\n         t/lib-patch-mode.sh: fix ignored exit codes\n     \n         Fix code added in b319ef70a94 (Add a small patch-mode testing library,\n    -    2009-08-13) to use &&-chaining and the newly added \"test_cmp_cmd\".\n    +    2009-08-13) to use &&-chaining.\n    +\n         This avoids losing both the exit code of a \"git\" and the \"cat\"\n         processes.\n     \n    @@ Commit message\n         SANITIZE=leak, this code doesn't leak now as far as I can tell, but I\n         discovered it while looking at leaks in related code.\n     \n    -    The \"cat _head >expect\" here is redundant, we could simply give\n    -    \"_head\" to \"test_cmp\", but let's be consistent in using the \"expect\"\n    -    and \"actual\" names for clarity.\n    -\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## t/lib-patch-mode.sh ##\n5:  58ac6fe5604 ! 3:  f5b2489609c tests: use \"test_cmp\" instead of \"test\" in sub-shells\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    tests: use \"test_cmp\" instead of \"test\" in sub-shells\n    +    tests: don't lose exit status with \"(cd ...; test <op> $(git ...))\"\n     \n    -    Convert a few cases where we were using \"test\" inside a sub-shell, and\n    -    were losing the exit code of \"git\".\n    +    Rewrite tests that ran \"git\" inside command substitution and lost the\n    +    exit status of \"git\" so that we notice the failing \"git\".\n     \n    -    In the case of \"t3200-branch.sh\" some adjacent code outside of a\n    -    sub-shell that was losing the exit code is also being converted, as\n    -    it's within the same hunk.\n    +    Have them use modern patterns such as a \"test_cmp\" of the expected\n    +    outputs instead, and avoid needlessly spawning sub-shell in favor of\n    +    using \"git -C <dir>\".\n    +\n    +    We'll fix more of these these in the subsequent commit, for now we're\n    +    only converting the cases where this loss of exit code was combined\n    +    with spawning a sub-shell. The one exception to that is the casein\n    +    \"t3200-branch.sh\" where adjacent code didn't use a sub-shell, let's\n    +    convert that here as it's within the same hunk.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n6:  51f32b42ce6 ! 4:  da66e5bf1c1 tests: don't lose 'test <str> = $(cmd ...)\"' exit code\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    tests: don't lose 'test <str> = $(cmd ...)\"' exit code\n    +    tests: don't lose exit status with \"test <op> $(git ...)\"\n     \n    -    Convert some cases in the test suite where we'd lose the exit code of\n    -    a command being interpolated as one of the arguments to the \"test\"\n    -    builtin function to use &&-chaining and \"test_cmp\" instead.\n    -\n    -    This way we won't lose the exit code, and the failure output will be\n    -    more helpful.\n    +    As with the preceding commit, rewrite tests that ran \"git\" inside\n    +    command substitution and lost the exit status of \"git\" so that we\n    +    notice the failing \"git\". This time around we're converting cases that\n    +    didn't involve a containing sub-shell around the command substitution.\n     \n         In the case of \"t0060-path-utils.sh\" and\n         \"t2005-checkout-index-symlinks.sh\" convert the relevant code to using\n7:  307f25db831 ! 5:  9596702978e tests: don't lose \"git\" exit codes in \"! ( git ... | grep )\"\n    @@ Commit message\n         - In the case of \"t0055-beyond-symlinks.sh\" compare against the\n           expected output instead.\n     \n    +      We could use the same pattern as in the \"t3700-add.sh\" below, doing\n    +      so would have the advantage that if we added an earlier test we\n    +      wouldn't need to adjust the \"expect\" output.\n    +\n    +      But as \"t0055-beyond-symlinks.sh\" is a small and focused test (less\n    +      than 40 lines in total) let's use \"test_cmp\" instead.\n    +\n         - For \"t3700-add.sh\" use \"sed -n\" to print the expected \"bad\" part,\n    -      and use \"test_must_be_empty\" to assert that it's not there.\n    +      and use \"test_must_be_empty\" to assert that it's not there. If we used\n    +      \"grep\" we'd get a non-zero exit code.\n    +\n    +      We could use \"test_expect_code 1 grep\", but this is more consistent\n    +      with existing patterns in the test suite.\n     \n           We can also remove a repeated invocation of \"git ls-files\" for the\n           last test that's being modified in that file, and search the\n8:  37c75f4a097 ! 6:  94df7a1764e tests: don't lose mist \"git\" exit codes\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    tests: don't lose mist \"git\" exit codes\n    +    tests: don't lose misc \"git\" exit codes\n     \n         Fix a few miscellaneous cases where:\n     \n-- \n2.39.0.1071.g97ce8966538\n\n"},{"id":"469269","messageId":"patch-v4-1.6-68d276dd421-20221219T101240Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v4-0.6-00000000000-20221219T101240Z-avarab@gmail.com","subject":"[PATCH v4 1/6] auto-crlf tests: don't lose exit code in loops and outside tests","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-19T10:19:24Z","receivedAt":"2022-12-19T10:19:42Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the functions which are called from within\n\"test_expect_success\" to add the \"|| return 1\" idiom to their\nfor-loops, so we won't lose the exit code of \"cp\", \"git\" etc.\n\nThen for those setup functions that aren't called from a\n\"test_expect_success\" we need to put the setup code in a\n\"test_expect_success\" as well. It would not be enough to properly\n&&-chain these, as the calling code is the top-level script itself. As\nwe don't run the tests with \"set -e\" we won't report failing commands\nat the top-level.\n\nThe \"checkout\" part of this would miss memory leaks under\nSANITIZE=leak, this code doesn't leak (the relevant \"git checkout\"\nleak has been fixed), but in a past version of git we'd continue past\nthis failure under SANITIZE=leak when these invocations had errored\nout, even under \"--immediate\".\n\nHelped-by: René Scharfe <l.s.r@web.de>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t0027-auto-crlf.sh | 66 +++++++++++++++++++++++++-------------------\n 1 file changed, 38 insertions(+), 28 deletions(-)\n\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex a94ac1eae37..2f57c8669cb 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -70,7 +70,8 @@ create_NNO_MIX_files () {\n \t\t\t\tcp CRLF        ${pfx}_CRLF.txt &&\n \t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt &&\n \t\t\t\tcp LF_mix_CR   ${pfx}_LF_mix_CR.txt &&\n-\t\t\t\tcp CRLF_nul    ${pfx}_CRLF_nul.txt\n+\t\t\t\tcp CRLF_nul    ${pfx}_CRLF_nul.txt ||\n+\t\t\t\treturn 1\n \t\t\tdone\n \t\tdone\n \tdone\n@@ -101,7 +102,8 @@ commit_check_warn () {\n \tdo\n \t\tfname=${pfx}_$f.txt &&\n \t\tcp $f $fname &&\n-\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\"\n+\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\" ||\n+\t\treturn 1\n \tdone &&\n \tgit commit -m \"core.autocrlf $crlf\" &&\n \tcheck_warning \"$lfname\" ${pfx}_LF.err &&\n@@ -121,15 +123,19 @@ commit_chk_wrnNNO () {\n \tlfmixcr=$1 ; shift\n \tcrlfnul=$1 ; shift\n \tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n-\t#Commit files on top of existing file\n-\tcreate_gitattributes \"$attr\" $aeol &&\n-\tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n-\tdo\n-\t\tfname=${pfx}_$f.txt &&\n-\t\tcp $f $fname &&\n-\t\tprintf Z >>\"$fname\" &&\n-\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\"\n-\tdone\n+\n+\ttest_expect_success 'setup commit NNO files' '\n+\t\t#Commit files on top of existing file\n+\t\tcreate_gitattributes \"$attr\" $aeol &&\n+\t\tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n+\t\tdo\n+\t\t\tfname=${pfx}_$f.txt &&\n+\t\t\tcp $f $fname &&\n+\t\t\tprintf Z >>\"$fname\" &&\n+\t\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\" ||\n+\t\t\treturn 1\n+\t\tdone\n+\t'\n \n \ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr LF\" '\n \t\tcheck_warning \"$lfwarn\" ${pfx}_LF.err\n@@ -163,15 +169,19 @@ commit_MIX_chkwrn () {\n \tlfmixcr=$1 ; shift\n \tcrlfnul=$1 ; shift\n \tpfx=MIX_attr_${attr}_aeol_${aeol}_${crlf}\n-\t#Commit file with CLRF_mix_LF on top of existing file\n-\tcreate_gitattributes \"$attr\" $aeol &&\n-\tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n-\tdo\n-\t\tfname=${pfx}_$f.txt &&\n-\t\tcp CRLF_mix_LF $fname &&\n-\t\tprintf Z >>\"$fname\" &&\n-\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\"\n-\tdone\n+\n+\ttest_expect_success 'setup commit file with mixed EOL' '\n+\t\t#Commit file with CLRF_mix_LF on top of existing file\n+\t\tcreate_gitattributes \"$attr\" $aeol &&\n+\t\tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n+\t\tdo\n+\t\t\tfname=${pfx}_$f.txt &&\n+\t\t\tcp CRLF_mix_LF $fname &&\n+\t\t\tprintf Z >>\"$fname\" &&\n+\t\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\" ||\n+\t\t\treturn 1\n+\t\tdone\n+\t'\n \n \ttest_expect_success \"commit file with mixed EOL onto LF crlf=$crlf attr=$attr\" '\n \t\tcheck_warning \"$lfwarn\" ${pfx}_LF.err\n@@ -289,17 +299,17 @@ checkout_files () {\n \tlfmixcrlf=$1 ; shift\n \tlfmixcr=$1 ; shift\n \tcrlfnul=$1 ; shift\n-\tcreate_gitattributes \"$attr\" $ident $aeol &&\n-\tgit config core.autocrlf $crlf &&\n+\ttest_expect_success \"setup config for checkout attr=$attr ident=$ident aeol=$aeol core.autocrlf=$crlf\" '\n+\t\tcreate_gitattributes \"$attr\" $ident $aeol &&\n+\t\tgit config core.autocrlf $crlf\n+\t'\n \tpfx=eol_${ceol}_crlf_${crlf}_attr_${attr}_ &&\n \tfor f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul\n \tdo\n-\t\trm crlf_false_attr__$f.txt &&\n-\t\tif test -z \"$ceol\"; then\n-\t\t\tgit checkout -- crlf_false_attr__$f.txt\n-\t\telse\n-\t\t\tgit -c core.eol=$ceol checkout -- crlf_false_attr__$f.txt\n-\t\tfi\n+\t\ttest_expect_success \"setup $f checkout ${ceol:+ with -c core.eol=$ceol}\"  '\n+\t\t\trm -f crlf_false_attr__$f.txt &&\n+\t\t\tgit ${ceol:+-c core.eol=$ceol} checkout -- crlf_false_attr__$f.txt\n+\t\t'\n \tdone\n \n \ttest_expect_success \"ls-files --eol attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol\" '\n-- \n2.39.0.1071.g97ce8966538\n\n"},{"id":"469270","messageId":"patch-v4-2.6-d351075f0ab-20221219T101240Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v4-0.6-00000000000-20221219T101240Z-avarab@gmail.com","subject":"[PATCH v4 2/6] t/lib-patch-mode.sh: fix ignored exit codes","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-19T10:19:25Z","receivedAt":"2022-12-19T10:19:45Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Fix code added in b319ef70a94 (Add a small patch-mode testing library,\n2009-08-13) to use &&-chaining.\n\nThis avoids losing both the exit code of a \"git\" and the \"cat\"\nprocesses.\n\nThis fixes cases where we'd have e.g. missed memory leaks under\nSANITIZE=leak, this code doesn't leak now as far as I can tell, but I\ndiscovered it while looking at leaks in related code.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/lib-patch-mode.sh | 11 ++++++++---\n 1 file changed, 8 insertions(+), 3 deletions(-)\n\ndiff --git a/t/lib-patch-mode.sh b/t/lib-patch-mode.sh\nindex cfd76bf987b..89ca1f78055 100644\n--- a/t/lib-patch-mode.sh\n+++ b/t/lib-patch-mode.sh\n@@ -29,8 +29,12 @@ set_and_save_state () {\n \n # verify_state <path> <expected-worktree-content> <expected-index-content>\n verify_state () {\n-\ttest \"$(cat \"$1\")\" = \"$2\" &&\n-\ttest \"$(git show :\"$1\")\" = \"$3\"\n+\techo \"$2\" >expect &&\n+\ttest_cmp expect \"$1\" &&\n+\n+\techo \"$3\" >expect &&\n+\tgit show :\"$1\" >actual &&\n+\ttest_cmp expect actual\n }\n \n # verify_saved_state <path>\n@@ -46,5 +50,6 @@ save_head () {\n }\n \n verify_saved_head () {\n-\ttest \"$(cat _head)\" = \"$(git rev-parse HEAD)\"\n+\tgit rev-parse HEAD >actual &&\n+\ttest_cmp _head actual\n }\n-- \n2.39.0.1071.g97ce8966538\n\n"},{"id":"469271","messageId":"patch-v4-3.6-f5b2489609c-20221219T101240Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v4-0.6-00000000000-20221219T101240Z-avarab@gmail.com","subject":"[PATCH v4 3/6] tests: don't lose exit status with \"(cd ...; test <op> $(git ...))\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-19T10:19:26Z","receivedAt":"2022-12-19T10:19:46Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Rewrite tests that ran \"git\" inside command substitution and lost the\nexit status of \"git\" so that we notice the failing \"git\".\n\nHave them use modern patterns such as a \"test_cmp\" of the expected\noutputs instead, and avoid needlessly spawning sub-shell in favor of\nusing \"git -C <dir>\".\n\nWe'll fix more of these these in the subsequent commit, for now we're\nonly converting the cases where this loss of exit code was combined\nwith spawning a sub-shell. The one exception to that is the casein\n\"t3200-branch.sh\" where adjacent code didn't use a sub-shell, let's\nconvert that here as it's within the same hunk.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/lib-httpd.sh              |  5 +++--\n t/lib-submodule-update.sh   | 22 +++++++++-------------\n t/t0060-path-utils.sh       |  4 +++-\n t/t3200-branch.sh           | 13 +++++++------\n t/t5605-clone-local.sh      | 15 ++++++++++-----\n t/t7402-submodule-rebase.sh | 14 +++++++++++---\n 6 files changed, 43 insertions(+), 30 deletions(-)\n\ndiff --git a/t/lib-httpd.sh b/t/lib-httpd.sh\nindex 608949ea80b..31e7fa3010c 100644\n--- a/t/lib-httpd.sh\n+++ b/t/lib-httpd.sh\n@@ -217,8 +217,9 @@ test_http_push_nonff () {\n \t\tgit commit -a -m path2 --amend &&\n \n \t\ttest_must_fail git push -v origin >output 2>&1 &&\n-\t\t(cd \"$REMOTE_REPO\" &&\n-\t\t test $HEAD = $(git rev-parse --verify HEAD))\n+\t\techo \"$HEAD\" >expect &&\n+\t\tgit -C \"$REMOTE_REPO\" rev-parse --verify HEAD >actual &&\n+\t\ttest_cmp expect actual\n \t'\n \n \ttest_expect_success 'non-fast-forward push show ref status' '\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 2d31fcfda1f..d7c2b670b4a 100644\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -168,20 +168,16 @@ replace_gitfile_with_git_dir () {\n # Note that this only supports submodules at the root level of the\n # superproject, with the default name, i.e. same as its path.\n test_git_directory_is_unchanged () {\n-\t(\n-\t\tcd \".git/modules/$1\" &&\n-\t\t# does core.worktree point at the right place?\n-\t\ttest \"$(git config core.worktree)\" = \"../../../$1\" &&\n-\t\t# remove it temporarily before comparing, as\n-\t\t# \"$1/.git/config\" lacks it...\n-\t\tgit config --unset core.worktree\n-\t) &&\n+\t# does core.worktree point at the right place?\n+\techo \"../../../$1\" >expect &&\n+\tgit -C \".git/modules/$1\" config core.worktree >actual &&\n+\ttest_cmp expect actual &&\n+\t# remove it temporarily before comparing, as\n+\t# \"$1/.git/config\" lacks it...\n+\tgit -C \".git/modules/$1\" config --unset core.worktree &&\n \tdiff -r \".git/modules/$1\" \"$1/.git\" &&\n-\t(\n-\t\t# ... and then restore.\n-\t\tcd \".git/modules/$1\" &&\n-\t\tgit config core.worktree \"../../../$1\"\n-\t)\n+\t# ... and then restore.\n+\tgit -C \".git/modules/$1\" config core.worktree \"../../../$1\"\n }\n \n test_git_directory_exists () {\ndiff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh\nindex 68e29c904a6..53ec717cbca 100755\n--- a/t/t0060-path-utils.sh\n+++ b/t/t0060-path-utils.sh\n@@ -255,7 +255,9 @@ test_expect_success 'prefix_path rejects absolute path to dir with same beginnin\n test_expect_success SYMLINKS 'prefix_path works with absolute path to a symlink to work tree having  same beginning as work tree' '\n \tgit init repo &&\n \tln -s repo repolink &&\n-\ttest \"a\" = \"$(cd repo && test-tool path-utils prefix_path prefix \"$(pwd)/../repolink/a\")\"\n+\techo \"a\" >expect &&\n+\ttest-tool -C repo path-utils prefix_path prefix \"$(cd repo && pwd)/../repolink/a\" >actual &&\n+\ttest_cmp expect actual\n '\n \n relative_path /foo/a/b/c/\t/foo/a/b/\tc/\ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex 5a169b68d6a..f5fbb84262b 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -242,12 +242,13 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou\n test_expect_success 'git branch -M baz bam should succeed within a worktree in which baz is checked out' '\n \tgit checkout -b baz &&\n \tgit worktree add -f bazdir baz &&\n-\t(\n-\t\tcd bazdir &&\n-\t\tgit branch -M baz bam &&\n-\t\ttest $(git rev-parse --abbrev-ref HEAD) = bam\n-\t) &&\n-\ttest $(git rev-parse --abbrev-ref HEAD) = bam &&\n+\tgit -C \"$bazdir\" branch -M baz bam &&\n+\techo \"bam\" >expect &&\n+\tgit -C \"$bazdir\" rev-parse --abbrev-ref HEAD >actual &&\n+\ttest_cmp expect actual &&\n+\techo \"bam\" >expect &&\n+\tgit rev-parse --abbrev-ref HEAD >actual &&\n+\ttest_cmp expect actual &&\n \trm -r bazdir &&\n \tgit worktree prune\n '\ndiff --git a/t/t5605-clone-local.sh b/t/t5605-clone-local.sh\nindex 38b850c10ef..61a2342bc2c 100755\n--- a/t/t5605-clone-local.sh\n+++ b/t/t5605-clone-local.sh\n@@ -15,8 +15,12 @@ test_expect_success 'preparing origin repository' '\n \t: >file && git add . && git commit -m1 &&\n \tgit clone --bare . a.git &&\n \tgit clone --bare . x &&\n-\ttest \"$(cd a.git && git config --bool core.bare)\" = true &&\n-\ttest \"$(cd x && git config --bool core.bare)\" = true &&\n+\techo true >expect &&\n+\tgit -C a.git config --bool core.bare >actual &&\n+\ttest_cmp expect actual &&\n+\techo true >expect &&\n+\tgit -C x config --bool core.bare >actual &&\n+\ttest_cmp expect actual &&\n \tgit bundle create b1.bundle --all &&\n \tgit bundle create b2.bundle main &&\n \tmkdir dir &&\n@@ -28,9 +32,10 @@ test_expect_success 'preparing origin repository' '\n \n test_expect_success 'local clone without .git suffix' '\n \tgit clone -l -s a b &&\n-\t(cd b &&\n-\ttest \"$(git config --bool core.bare)\" = false &&\n-\tgit fetch)\n+\techo false >expect &&\n+\tgit -C b config --bool core.bare >actual &&\n+\ttest_cmp expect actual &&\n+\tgit -C b fetch\n '\n \n test_expect_success 'local clone with .git suffix' '\ndiff --git a/t/t7402-submodule-rebase.sh b/t/t7402-submodule-rebase.sh\nindex ebeca12a711..1927a862839 100755\n--- a/t/t7402-submodule-rebase.sh\n+++ b/t/t7402-submodule-rebase.sh\n@@ -82,11 +82,19 @@ test_expect_success 'stash with a dirty submodule' '\n \tCURRENT=$(cd submodule && git rev-parse HEAD) &&\n \tgit stash &&\n \ttest new != $(cat file) &&\n-\ttest submodule = $(git diff --name-only) &&\n-\ttest $CURRENT = $(cd submodule && git rev-parse HEAD) &&\n+\techo submodule >expect &&\n+\tgit diff --name-only >actual &&\n+\ttest_cmp expect actual &&\n+\n+\techo \"$CURRENT\" >expect &&\n+\tgit -C submodule rev-parse HEAD >actual &&\n+\ttest_cmp expect actual &&\n+\n \tgit stash apply &&\n \ttest new = $(cat file) &&\n-\ttest $CURRENT = $(cd submodule && git rev-parse HEAD)\n+\techo \"$CURRENT\" >expect &&\n+\tgit -C submodule rev-parse HEAD >actual &&\n+\ttest_cmp expect actual\n \n '\n \n-- \n2.39.0.1071.g97ce8966538\n\n"},{"id":"469272","messageId":"patch-v4-4.6-da66e5bf1c1-20221219T101240Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v4-0.6-00000000000-20221219T101240Z-avarab@gmail.com","subject":"[PATCH v4 4/6] tests: don't lose exit status with \"test <op> $(git ...)\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-19T10:19:27Z","receivedAt":"2022-12-19T10:19:50Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As with the preceding commit, rewrite tests that ran \"git\" inside\ncommand substitution and lost the exit status of \"git\" so that we\nnotice the failing \"git\". This time around we're converting cases that\ndidn't involve a containing sub-shell around the command substitution.\n\nIn the case of \"t0060-path-utils.sh\" and\n\"t2005-checkout-index-symlinks.sh\" convert the relevant code to using\nthe modern style of indentation and newline wrapping while having to\nchange it.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/lib-submodule-update.sh          |   4 +-\n t/t0001-init.sh                    |   9 ++-\n t/t0002-gitfile.sh                 |   4 +-\n t/t0060-path-utils.sh              | 103 +++++++++++++++++++++--------\n t/t0100-previous.sh                |   8 ++-\n t/t1504-ceiling-dirs.sh            |   8 ++-\n t/t2005-checkout-index-symlinks.sh |   8 ++-\n t/t5522-pull-symlink.sh            |   4 +-\n t/t7402-submodule-rebase.sh        |   9 ++-\n t/t7504-commit-msg-hook.sh         |   4 +-\n t/t7810-grep.sh                    |   4 +-\n 11 files changed, 120 insertions(+), 45 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex d7c2b670b4a..dee14992c52 100644\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -185,7 +185,9 @@ test_git_directory_exists () {\n \tif test -f sub1/.git\n \tthen\n \t\t# does core.worktree point at the right place?\n-\t\ttest \"$(git -C .git/modules/$1 config core.worktree)\" = \"../../../$1\"\n+\t\techo \"../../../$1\" >expect &&\n+\t\tgit -C \".git/modules/$1\" config core.worktree >actual &&\n+\t\ttest_cmp expect actual\n \tfi\n }\n \ndiff --git a/t/t0001-init.sh b/t/t0001-init.sh\nindex d479303efa0..30a6edca1d2 100755\n--- a/t/t0001-init.sh\n+++ b/t/t0001-init.sh\n@@ -598,9 +598,14 @@ test_expect_success 'invalid default branch name' '\n test_expect_success 'branch -m with the initial branch' '\n \tgit init rename-initial &&\n \tgit -C rename-initial branch -m renamed &&\n-\ttest renamed = $(git -C rename-initial symbolic-ref --short HEAD) &&\n+\techo renamed >expect &&\n+\tgit -C rename-initial symbolic-ref --short HEAD >actual &&\n+\ttest_cmp expect actual &&\n+\n \tgit -C rename-initial branch -m renamed again &&\n-\ttest again = $(git -C rename-initial symbolic-ref --short HEAD)\n+\techo again >expect &&\n+\tgit -C rename-initial symbolic-ref --short HEAD >actual &&\n+\ttest_cmp expect actual\n '\n \n test_done\ndiff --git a/t/t0002-gitfile.sh b/t/t0002-gitfile.sh\nindex 26eaca095a2..e013d38f485 100755\n--- a/t/t0002-gitfile.sh\n+++ b/t/t0002-gitfile.sh\n@@ -33,7 +33,9 @@ test_expect_success 'bad setup: invalid .git file path' '\n \n test_expect_success 'final setup + check rev-parse --git-dir' '\n \techo \"gitdir: $REAL\" >.git &&\n-\ttest \"$REAL\" = \"$(git rev-parse --git-dir)\"\n+\techo \"$REAL\" >expect &&\n+\tgit rev-parse --git-dir >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'check hash-object' '\ndiff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh\nindex 53ec717cbca..6490ad5ca1b 100755\n--- a/t/t0060-path-utils.sh\n+++ b/t/t0060-path-utils.sh\n@@ -10,20 +10,27 @@ TEST_PASSES_SANITIZE_LEAK=true\n \n norm_path() {\n \texpected=$(test-tool path-utils print_path \"$2\")\n-\ttest_expect_success $3 \"normalize path: $1 => $2\" \\\n-\t\"test \\\"\\$(test-tool path-utils normalize_path_copy '$1')\\\" = '$expected'\"\n+\ttest_expect_success $3 \"normalize path: $1 => $2\" \"\n+\t\techo '$expected' >expect &&\n+\t\ttest-tool path-utils normalize_path_copy '$1' >actual &&\n+\t\ttest_cmp expect actual\n+\t\"\n }\n \n relative_path() {\n \texpected=$(test-tool path-utils print_path \"$3\")\n-\ttest_expect_success $4 \"relative path: $1 $2 => $3\" \\\n-\t\"test \\\"\\$(test-tool path-utils relative_path '$1' '$2')\\\" = '$expected'\"\n+\ttest_expect_success $4 \"relative path: $1 $2 => $3\" \"\n+\t\techo '$expected' >expect &&\n+\t\ttest-tool path-utils relative_path '$1' '$2' >actual &&\n+\t\ttest_cmp expect actual\n+\t\"\n }\n \n test_submodule_relative_url() {\n \ttest_expect_success \"test_submodule_relative_url: $1 $2 $3 => $4\" \"\n-\t\tactual=\\$(test-tool submodule resolve-relative-url '$1' '$2' '$3') &&\n-\t\ttest \\\"\\$actual\\\" = '$4'\n+\t\techo '$4' >expect &&\n+\t\ttest-tool submodule resolve-relative-url '$1' '$2' '$3' >actual &&\n+\t\ttest_cmp expect actual\n \t\"\n }\n \n@@ -64,9 +71,11 @@ ancestor() {\n \t\texpected=$(($expected-$rootslash+$rootoff))\n \t\t;;\n \tesac\n-\ttest_expect_success $4 \"longest ancestor: $1 $2 => $expected\" \\\n-\t\"actual=\\$(test-tool path-utils longest_ancestor_length '$1' '$2') &&\n-\t test \\\"\\$actual\\\" = '$expected'\"\n+\ttest_expect_success $4 \"longest ancestor: $1 $2 => $expected\" \"\n+\t\techo '$expected' >expect &&\n+\t\ttest-tool path-utils longest_ancestor_length '$1' '$2' >actual &&\n+\t\ttest_cmp expect actual\n+\t\"\n }\n \n # Some absolute path tests should be skipped on Windows due to path mangling\n@@ -166,8 +175,10 @@ ancestor D:/Users/me C:/ -1 MINGW\n ancestor //server/share/my-directory //server/share/ 14 MINGW\n \n test_expect_success 'strip_path_suffix' '\n-\ttest c:/msysgit = $(test-tool path-utils strip_path_suffix \\\n-\t\tc:/msysgit/libexec//git-core libexec/git-core)\n+\techo c:/msysgit >expect &&\n+\ttest-tool path-utils strip_path_suffix \\\n+\t\tc:/msysgit/libexec//git-core libexec/git-core >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'absolute path rejects the empty string' '\n@@ -188,35 +199,61 @@ test_expect_success 'real path rejects the empty string' '\n '\n \n test_expect_success POSIX 'real path works on absolute paths 1' '\n+\techo / >expect &&\n+\ttest-tool path-utils real_path \"/\" >actual &&\n+\ttest_cmp expect actual &&\n+\n \tnopath=\"hopefully-absent-path\" &&\n-\ttest \"/\" = \"$(test-tool path-utils real_path \"/\")\" &&\n-\ttest \"/$nopath\" = \"$(test-tool path-utils real_path \"/$nopath\")\"\n+\techo \"/$nopath\" >expect &&\n+\ttest-tool path-utils real_path \"/$nopath\" >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'real path works on absolute paths 2' '\n-\tnopath=\"hopefully-absent-path\" &&\n \t# Find an existing top-level directory for the remaining tests:\n \td=$(pwd -P | sed -e \"s|^\\([^/]*/[^/]*\\)/.*|\\1|\") &&\n-\ttest \"$d\" = \"$(test-tool path-utils real_path \"$d\")\" &&\n-\ttest \"$d/$nopath\" = \"$(test-tool path-utils real_path \"$d/$nopath\")\"\n+\techo \"$d\" >expect &&\n+\ttest-tool path-utils real_path \"$d\" >actual &&\n+\ttest_cmp expect actual &&\n+\n+\tnopath=\"hopefully-absent-path\" &&\n+\techo \"$d/$nopath\" >expect &&\n+\ttest-tool path-utils real_path \"$d/$nopath\" >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success POSIX 'real path removes extra leading slashes' '\n+\techo \"/\" >expect &&\n+\ttest-tool path-utils real_path \"///\" >actual &&\n+\ttest_cmp expect actual &&\n+\n \tnopath=\"hopefully-absent-path\" &&\n-\ttest \"/\" = \"$(test-tool path-utils real_path \"///\")\" &&\n-\ttest \"/$nopath\" = \"$(test-tool path-utils real_path \"///$nopath\")\" &&\n+\techo \"/$nopath\" >expect &&\n+\ttest-tool path-utils real_path \"///$nopath\" >actual &&\n+\ttest_cmp expect actual &&\n+\n \t# Find an existing top-level directory for the remaining tests:\n \td=$(pwd -P | sed -e \"s|^\\([^/]*/[^/]*\\)/.*|\\1|\") &&\n-\ttest \"$d\" = \"$(test-tool path-utils real_path \"//$d\")\" &&\n-\ttest \"$d/$nopath\" = \"$(test-tool path-utils real_path \"//$d/$nopath\")\"\n+\techo \"$d\" >expect &&\n+\ttest-tool path-utils real_path \"//$d\" >actual &&\n+\ttest_cmp expect actual &&\n+\n+\techo \"$d/$nopath\" >expect &&\n+\ttest-tool path-utils real_path \"//$d/$nopath\" >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'real path removes other extra slashes' '\n-\tnopath=\"hopefully-absent-path\" &&\n \t# Find an existing top-level directory for the remaining tests:\n \td=$(pwd -P | sed -e \"s|^\\([^/]*/[^/]*\\)/.*|\\1|\") &&\n-\ttest \"$d\" = \"$(test-tool path-utils real_path \"$d///\")\" &&\n-\ttest \"$d/$nopath\" = \"$(test-tool path-utils real_path \"$d///$nopath\")\"\n+\techo \"$d\" >expect &&\n+\ttest-tool path-utils real_path \"$d///\" >actual &&\n+\ttest_cmp expect actual &&\n+\n+\tnopath=\"hopefully-absent-path\" &&\n+\techo \"$d/$nopath\" >expect &&\n+\ttest-tool path-utils real_path \"$d///$nopath\" >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success SYMLINKS 'real path works on symlinks' '\n@@ -227,19 +264,29 @@ test_expect_success SYMLINKS 'real path works on symlinks' '\n \tmkdir third &&\n \tdir=\"$(cd .git && pwd -P)\" &&\n \tdir2=third/../second/other/.git &&\n-\ttest \"$dir\" = \"$(test-tool path-utils real_path $dir2)\" &&\n+\techo \"$dir\" >expect &&\n+\ttest-tool path-utils real_path $dir2 >actual &&\n+\ttest_cmp expect actual &&\n \tfile=\"$dir\"/index &&\n-\ttest \"$file\" = \"$(test-tool path-utils real_path $dir2/index)\" &&\n+\techo \"$file\" >expect &&\n+\ttest-tool path-utils real_path $dir2/index >actual &&\n+\ttest_cmp expect actual &&\n \tbasename=blub &&\n-\ttest \"$dir/$basename\" = \"$(cd .git && test-tool path-utils real_path \"$basename\")\" &&\n+\techo \"$dir/$basename\" >expect &&\n+\ttest-tool -C .git path-utils real_path \"$basename\" >actual &&\n+\ttest_cmp expect actual &&\n \tln -s ../first/file .git/syml &&\n \tsym=\"$(cd first && pwd -P)\"/file &&\n-\ttest \"$sym\" = \"$(test-tool path-utils real_path \"$dir2/syml\")\"\n+\techo \"$sym\" >expect &&\n+\ttest-tool path-utils real_path \"$dir2/syml\" >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success SYMLINKS 'prefix_path works with absolute paths to work tree symlinks' '\n \tln -s target symlink &&\n-\ttest \"$(test-tool path-utils prefix_path prefix \"$(pwd)/symlink\")\" = \"symlink\"\n+\techo \"symlink\" >expect &&\n+\ttest-tool path-utils prefix_path prefix \"$(pwd)/symlink\" >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'prefix_path works with only absolute path to work tree' '\ndiff --git a/t/t0100-previous.sh b/t/t0100-previous.sh\nindex a16cc3d2983..70a3223f219 100755\n--- a/t/t0100-previous.sh\n+++ b/t/t0100-previous.sh\n@@ -12,7 +12,9 @@ test_expect_success 'branch -d @{-1}' '\n \ttest_commit A &&\n \tgit checkout -b junk &&\n \tgit checkout - &&\n-\ttest \"$(git symbolic-ref HEAD)\" = refs/heads/main &&\n+\techo refs/heads/main >expect &&\n+\tgit symbolic-ref HEAD >actual &&\n+\ttest_cmp expect actual &&\n \tgit branch -d @{-1} &&\n \ttest_must_fail git rev-parse --verify refs/heads/junk\n '\n@@ -21,7 +23,9 @@ test_expect_success 'branch -d @{-12} when there is not enough switches yet' '\n \tgit reflog expire --expire=now &&\n \tgit checkout -b junk2 &&\n \tgit checkout - &&\n-\ttest \"$(git symbolic-ref HEAD)\" = refs/heads/main &&\n+\techo refs/heads/main >expect &&\n+\tgit symbolic-ref HEAD >actual &&\n+\ttest_cmp expect actual &&\n \ttest_must_fail git branch -d @{-12} &&\n \tgit rev-parse --verify refs/heads/main\n '\ndiff --git a/t/t1504-ceiling-dirs.sh b/t/t1504-ceiling-dirs.sh\nindex 0fafcf9dde3..c1679e31d8a 100755\n--- a/t/t1504-ceiling-dirs.sh\n+++ b/t/t1504-ceiling-dirs.sh\n@@ -6,8 +6,12 @@ TEST_PASSES_SANITIZE_LEAK=true\n . ./test-lib.sh\n \n test_prefix() {\n-\ttest_expect_success \"$1\" \\\n-\t\"test '$2' = \\\"\\$(git rev-parse --show-prefix)\\\"\"\n+\tlocal expect=\"$2\" &&\n+\ttest_expect_success \"$1: git rev-parse --show-prefix is '$2'\" '\n+\t\techo \"$expect\" >expect &&\n+\t\tgit rev-parse --show-prefix >actual &&\n+\t\ttest_cmp expect actual\n+\t'\n }\n \n test_fail() {\ndiff --git a/t/t2005-checkout-index-symlinks.sh b/t/t2005-checkout-index-symlinks.sh\nindex 112682a45a1..67d18cfa104 100755\n--- a/t/t2005-checkout-index-symlinks.sh\n+++ b/t/t2005-checkout-index-symlinks.sh\n@@ -22,8 +22,10 @@ test_expect_success \\\n git checkout-index symlink &&\n test -f symlink'\n \n-test_expect_success \\\n-'the file must be the blob we added during the setup' '\n-test \"$(git hash-object -t blob symlink)\" = $l'\n+test_expect_success 'the file must be the blob we added during the setup' '\n+\techo \"$l\" >expect &&\n+\tgit hash-object -t blob symlink >actual &&\n+\ttest_cmp expect actual\n+'\n \n test_done\ndiff --git a/t/t5522-pull-symlink.sh b/t/t5522-pull-symlink.sh\nindex bcff460d0a2..9fb73a8c3eb 100755\n--- a/t/t5522-pull-symlink.sh\n+++ b/t/t5522-pull-symlink.sh\n@@ -78,7 +78,9 @@ test_expect_success SYMLINKS 'pushing from symlinked subdir' '\n \t\tgit commit -m push ./file &&\n \t\tgit push\n \t) &&\n-\ttest push = $(git show HEAD:subdir/file)\n+\techo push >expect &&\n+\tgit show HEAD:subdir/file >actual &&\n+\ttest_cmp expect actual\n '\n \n test_done\ndiff --git a/t/t7402-submodule-rebase.sh b/t/t7402-submodule-rebase.sh\nindex 1927a862839..c74798e8d24 100755\n--- a/t/t7402-submodule-rebase.sh\n+++ b/t/t7402-submodule-rebase.sh\n@@ -55,12 +55,15 @@ chmod a+x fake-editor.sh\n \n test_expect_success 'interactive rebase with a dirty submodule' '\n \n-\ttest submodule = $(git diff --name-only) &&\n+\techo submodule >expect &&\n+\tgit diff --name-only >actual &&\n+\ttest_cmp expect actual &&\n \tHEAD=$(git rev-parse HEAD) &&\n \tGIT_EDITOR=\"\\\"$(pwd)/fake-editor.sh\\\"\" EDITOR_TEXT=\"pick $HEAD\" \\\n \t\tgit rebase -i HEAD^ &&\n-\ttest submodule = $(git diff --name-only)\n-\n+\techo submodule >expect &&\n+\tgit diff --name-only >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'rebase with dirty file and submodule fails' '\ndiff --git a/t/t7504-commit-msg-hook.sh b/t/t7504-commit-msg-hook.sh\nindex 07ca46fb0d5..d1255228d5f 100755\n--- a/t/t7504-commit-msg-hook.sh\n+++ b/t/t7504-commit-msg-hook.sh\n@@ -102,7 +102,9 @@ test_expect_success 'setup: commit-msg hook that always fails' '\n '\n \n commit_msg_is () {\n-\ttest \"$(git log --pretty=format:%s%b -1)\" = \"$1\"\n+\tprintf \"%s\" \"$1\" >expect &&\n+\tgit log --pretty=format:%s%b -1 >actual &&\n+\ttest_cmp expect actual\n }\n \n test_expect_success 'with failing hook' '\ndiff --git a/t/t7810-grep.sh b/t/t7810-grep.sh\nindex 8eded6ab274..39d6d713ecb 100755\n--- a/t/t7810-grep.sh\n+++ b/t/t7810-grep.sh\n@@ -1001,7 +1001,9 @@ test_expect_success 'log --committer does not search in timestamp' '\n test_expect_success 'grep with CE_VALID file' '\n \tgit update-index --assume-unchanged t/t &&\n \trm t/t &&\n-\ttest \"$(git grep test)\" = \"t/t:test\" &&\n+\techo \"t/t:test\" >expect &&\n+\tgit grep test >actual &&\n+\ttest_cmp expect actual &&\n \tgit update-index --no-assume-unchanged t/t &&\n \tgit checkout t/t\n '\n-- \n2.39.0.1071.g97ce8966538\n\n"},{"id":"469273","messageId":"patch-v4-5.6-9596702978e-20221219T101240Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v4-0.6-00000000000-20221219T101240Z-avarab@gmail.com","subject":"[PATCH v4 5/6] tests: don't lose \"git\" exit codes in \"! ( git ... | grep )\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-19T10:19:28Z","receivedAt":"2022-12-19T10:19:58Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change tests that would lose the \"git\" exit code via a negation\npattern to:\n\n- In the case of \"t0055-beyond-symlinks.sh\" compare against the\n  expected output instead.\n\n  We could use the same pattern as in the \"t3700-add.sh\" below, doing\n  so would have the advantage that if we added an earlier test we\n  wouldn't need to adjust the \"expect\" output.\n\n  But as \"t0055-beyond-symlinks.sh\" is a small and focused test (less\n  than 40 lines in total) let's use \"test_cmp\" instead.\n\n- For \"t3700-add.sh\" use \"sed -n\" to print the expected \"bad\" part,\n  and use \"test_must_be_empty\" to assert that it's not there. If we used\n  \"grep\" we'd get a non-zero exit code.\n\n  We could use \"test_expect_code 1 grep\", but this is more consistent\n  with existing patterns in the test suite.\n\n  We can also remove a repeated invocation of \"git ls-files\" for the\n  last test that's being modified in that file, and search the\n  existing \"files\" output instead.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t0055-beyond-symlinks.sh | 14 ++++++++++++--\n t/t3700-add.sh             | 18 +++++++++++++-----\n 2 files changed, 25 insertions(+), 7 deletions(-)\n\ndiff --git a/t/t0055-beyond-symlinks.sh b/t/t0055-beyond-symlinks.sh\nindex 6bada370225..c3eb1158ef9 100755\n--- a/t/t0055-beyond-symlinks.sh\n+++ b/t/t0055-beyond-symlinks.sh\n@@ -15,12 +15,22 @@ test_expect_success SYMLINKS setup '\n \n test_expect_success SYMLINKS 'update-index --add beyond symlinks' '\n \ttest_must_fail git update-index --add c/d &&\n-\t! ( git ls-files | grep c/d )\n+\tcat >expect <<-\\EOF &&\n+\ta\n+\tb/d\n+\tEOF\n+\tgit ls-files >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success SYMLINKS 'add beyond symlinks' '\n \ttest_must_fail git add c/d &&\n-\t! ( git ls-files | grep c/d )\n+\tcat >expect <<-\\EOF &&\n+\ta\n+\tb/d\n+\tEOF\n+\tgit ls-files >actual &&\n+\ttest_cmp expect actual\n '\n \n test_done\ndiff --git a/t/t3700-add.sh b/t/t3700-add.sh\nindex 51afbd7b24a..82dd768944f 100755\n--- a/t/t3700-add.sh\n+++ b/t/t3700-add.sh\n@@ -106,24 +106,32 @@ test_expect_success '.gitignore test setup' '\n \n test_expect_success '.gitignore is honored' '\n \tgit add . &&\n-\t! (git ls-files | grep \"\\\\.ig\")\n+\tgit ls-files >files &&\n+\tsed -n \"/\\\\.ig/p\" <files >actual &&\n+\ttest_must_be_empty actual\n '\n \n test_expect_success 'error out when attempting to add ignored ones without -f' '\n \ttest_must_fail git add a.?? &&\n-\t! (git ls-files | grep \"\\\\.ig\")\n+\tgit ls-files >files &&\n+\tsed -n \"/\\\\.ig/p\" <files >actual &&\n+\ttest_must_be_empty actual\n '\n \n test_expect_success 'error out when attempting to add ignored ones without -f' '\n \ttest_must_fail git add d.?? &&\n-\t! (git ls-files | grep \"\\\\.ig\")\n+\tgit ls-files >files &&\n+\tsed -n \"/\\\\.ig/p\" <files >actual &&\n+\ttest_must_be_empty actual\n '\n \n test_expect_success 'error out when attempting to add ignored ones but add others' '\n \ttouch a.if &&\n \ttest_must_fail git add a.?? &&\n-\t! (git ls-files | grep \"\\\\.ig\") &&\n-\t(git ls-files | grep a.if)\n+\tgit ls-files >files &&\n+\tsed -n \"/\\\\.ig/p\" <files >actual &&\n+\ttest_must_be_empty actual &&\n+\tgrep a.if files\n '\n \n test_expect_success 'add ignored ones with -f' '\n-- \n2.39.0.1071.g97ce8966538\n\n"},{"id":"469274","messageId":"patch-v4-6.6-94df7a1764e-20221219T101240Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v4-0.6-00000000000-20221219T101240Z-avarab@gmail.com","subject":"[PATCH v4 6/6] tests: don't lose misc \"git\" exit codes","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-19T10:19:29Z","receivedAt":"2022-12-19T10:19:59Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Fix a few miscellaneous cases where:\n\n- We lost the \"git\" exit code via \"git ... | grep\"\n- Likewise by having a $(git) argument to git itself\n- Used \"test -z\" to check that a command emitted no output, we can use\n  \"test_must_be_empty\" and &&-chaining instead.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t1401-symbolic-ref.sh    | 3 ++-\n t/t3701-add-interactive.sh | 8 +++++---\n t/t7516-commit-races.sh    | 3 ++-\n 3 files changed, 9 insertions(+), 5 deletions(-)\n\ndiff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh\nindex d708acdb819..5e36899d207 100755\n--- a/t/t1401-symbolic-ref.sh\n+++ b/t/t1401-symbolic-ref.sh\n@@ -33,7 +33,8 @@ test_expect_success 'symbolic-ref refuses non-ref for HEAD' '\n reset_to_sane\n \n test_expect_success 'symbolic-ref refuses bare sha1' '\n-\ttest_must_fail git symbolic-ref HEAD $(git rev-parse HEAD)\n+\trev=$(git rev-parse HEAD) &&\n+\ttest_must_fail git symbolic-ref HEAD \"$rev\"\n '\n \n reset_to_sane\ndiff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh\nindex 5841f280fb2..f1fe5d60677 100755\n--- a/t/t3701-add-interactive.sh\n+++ b/t/t3701-add-interactive.sh\n@@ -296,9 +296,11 @@ test_expect_success FILEMODE 'stage mode and hunk' '\n \techo content >>file &&\n \tchmod +x file &&\n \tprintf \"y\\\\ny\\\\n\" | git add -p &&\n-\tgit diff --cached file | grep \"new mode\" &&\n-\tgit diff --cached file | grep \"+content\" &&\n-\ttest -z \"$(git diff file)\"\n+\tgit diff --cached file >out &&\n+\tgrep \"new mode\" out &&\n+\tgrep \"+content\" out &&\n+\tgit diff file >out &&\n+\ttest_must_be_empty out\n '\n \n # end of tests disabled when filemode is not usable\ndiff --git a/t/t7516-commit-races.sh b/t/t7516-commit-races.sh\nindex f2ce14e9071..2d38a16480e 100755\n--- a/t/t7516-commit-races.sh\n+++ b/t/t7516-commit-races.sh\n@@ -10,7 +10,8 @@ test_expect_success 'race to create orphan commit' '\n \ttest_must_fail env EDITOR=./hare-editor git commit --allow-empty -m tortoise -e &&\n \tgit show -s --pretty=format:%s >subject &&\n \tgrep hare subject &&\n-\ttest -z \"$(git show -s --pretty=format:%P)\"\n+\tgit show -s --pretty=format:%P >out &&\n+\ttest_must_be_empty out\n '\n \n test_expect_success 'race to create non-orphan commit' '\n-- \n2.39.0.1071.g97ce8966538\n\n"},{"id":"469283","messageId":"1182283a-4a78-3c99-e716-a8c3e58a5823@web.de","threadId":"58200","inReplyTo":"patch-v4-1.6-68d276dd421-20221219T101240Z-avarab@gmail.com","subject":"Re: [PATCH v4 1/6] auto-crlf tests: don't lose exit code in loops and outside tests","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2022-12-19T12:07:59Z","receivedAt":"2022-12-19T12:11:04Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 19.12.22 um 11:19 schrieb Ævar Arnfjörð Bjarmason:\n> Change the functions which are called from within\n> \"test_expect_success\" to add the \"|| return 1\" idiom to their\n> for-loops, so we won't lose the exit code of \"cp\", \"git\" etc.\n>\n> Then for those setup functions that aren't called from a\n> \"test_expect_success\" we need to put the setup code in a\n> \"test_expect_success\" as well. It would not be enough to properly\n> &&-chain these, as the calling code is the top-level script itself. As\n> we don't run the tests with \"set -e\" we won't report failing commands\n> at the top-level.\n>\n> The \"checkout\" part of this would miss memory leaks under\n> SANITIZE=leak, this code doesn't leak (the relevant \"git checkout\"\n> leak has been fixed), but in a past version of git we'd continue past\n> this failure under SANITIZE=leak when these invocations had errored\n> out, even under \"--immediate\".\n>\n> Helped-by: René Scharfe <l.s.r@web.de>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  t/t0027-auto-crlf.sh | 66 +++++++++++++++++++++++++-------------------\n>  1 file changed, 38 insertions(+), 28 deletions(-)\n>\n> diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\n> index a94ac1eae37..2f57c8669cb 100755\n> --- a/t/t0027-auto-crlf.sh\n> +++ b/t/t0027-auto-crlf.sh\n> @@ -70,7 +70,8 @@ create_NNO_MIX_files () {\n>  \t\t\t\tcp CRLF        ${pfx}_CRLF.txt &&\n>  \t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt &&\n>  \t\t\t\tcp LF_mix_CR   ${pfx}_LF_mix_CR.txt &&\n> -\t\t\t\tcp CRLF_nul    ${pfx}_CRLF_nul.txt\n> +\t\t\t\tcp CRLF_nul    ${pfx}_CRLF_nul.txt ||\n> +\t\t\t\treturn 1\n>  \t\t\tdone\n>  \t\tdone\n>  \tdone\n> @@ -101,7 +102,8 @@ commit_check_warn () {\n>  \tdo\n>  \t\tfname=${pfx}_$f.txt &&\n>  \t\tcp $f $fname &&\n> -\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\"\n> +\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\" ||\n> +\t\treturn 1\n>  \tdone &&\n>  \tgit commit -m \"core.autocrlf $crlf\" &&\n>  \tcheck_warning \"$lfname\" ${pfx}_LF.err &&\n> @@ -121,15 +123,19 @@ commit_chk_wrnNNO () {\n>  \tlfmixcr=$1 ; shift\n>  \tcrlfnul=$1 ; shift\n>  \tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n> -\t#Commit files on top of existing file\n> -\tcreate_gitattributes \"$attr\" $aeol &&\n> -\tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n> -\tdo\n> -\t\tfname=${pfx}_$f.txt &&\n> -\t\tcp $f $fname &&\n> -\t\tprintf Z >>\"$fname\" &&\n> -\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\"\n> -\tdone\n> +\n> +\ttest_expect_success 'setup commit NNO files' '\n> +\t\t#Commit files on top of existing file\n> +\t\tcreate_gitattributes \"$attr\" $aeol &&\n> +\t\tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n> +\t\tdo\n> +\t\t\tfname=${pfx}_$f.txt &&\n> +\t\t\tcp $f $fname &&\n> +\t\t\tprintf Z >>\"$fname\" &&\n> +\t\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\" ||\n> +\t\t\treturn 1\n> +\t\tdone\n> +\t'\n>\n>  \ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr LF\" '\n>  \t\tcheck_warning \"$lfwarn\" ${pfx}_LF.err\n> @@ -163,15 +169,19 @@ commit_MIX_chkwrn () {\n>  \tlfmixcr=$1 ; shift\n>  \tcrlfnul=$1 ; shift\n>  \tpfx=MIX_attr_${attr}_aeol_${aeol}_${crlf}\n> -\t#Commit file with CLRF_mix_LF on top of existing file\n> -\tcreate_gitattributes \"$attr\" $aeol &&\n> -\tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n> -\tdo\n> -\t\tfname=${pfx}_$f.txt &&\n> -\t\tcp CRLF_mix_LF $fname &&\n> -\t\tprintf Z >>\"$fname\" &&\n> -\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\"\n> -\tdone\n> +\n> +\ttest_expect_success 'setup commit file with mixed EOL' '\n> +\t\t#Commit file with CLRF_mix_LF on top of existing file\n> +\t\tcreate_gitattributes \"$attr\" $aeol &&\n> +\t\tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n> +\t\tdo\n> +\t\t\tfname=${pfx}_$f.txt &&\n> +\t\t\tcp CRLF_mix_LF $fname &&\n> +\t\t\tprintf Z >>\"$fname\" &&\n> +\t\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\" ||\n> +\t\t\treturn 1\n> +\t\tdone\n> +\t'\n>\n>  \ttest_expect_success \"commit file with mixed EOL onto LF crlf=$crlf attr=$attr\" '\n>  \t\tcheck_warning \"$lfwarn\" ${pfx}_LF.err\n> @@ -289,17 +299,17 @@ checkout_files () {\n>  \tlfmixcrlf=$1 ; shift\n>  \tlfmixcr=$1 ; shift\n>  \tcrlfnul=$1 ; shift\n> -\tcreate_gitattributes \"$attr\" $ident $aeol &&\n> -\tgit config core.autocrlf $crlf &&\n> +\ttest_expect_success \"setup config for checkout attr=$attr ident=$ident aeol=$aeol core.autocrlf=$crlf\" '\n> +\t\tcreate_gitattributes \"$attr\" $ident $aeol &&\n> +\t\tgit config core.autocrlf $crlf\n> +\t'\n>  \tpfx=eol_${ceol}_crlf_${crlf}_attr_${attr}_ &&\n>  \tfor f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul\n>  \tdo\n> -\t\trm crlf_false_attr__$f.txt &&\n> -\t\tif test -z \"$ceol\"; then\n> -\t\t\tgit checkout -- crlf_false_attr__$f.txt\n> -\t\telse\n> -\t\t\tgit -c core.eol=$ceol checkout -- crlf_false_attr__$f.txt\n> -\t\tfi\n> +\t\ttest_expect_success \"setup $f checkout ${ceol:+ with -c core.eol=$ceol}\"  '\n> +\t\t\trm -f crlf_false_attr__$f.txt &&\n> +\t\t\tgit ${ceol:+-c core.eol=$ceol} checkout -- crlf_false_attr__$f.txt\n> +\t\t'\n\nOK, but why have test_expect_success inside the loop here, while a simlilar\nloop is inside the two test_expect_success bodies above?  Do we really need\nfive invocations here instead of one?  It's just setup code.\n\n>  \tdone\n>\n>  \ttest_expect_success \"ls-files --eol attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol\" '\n"},{"id":"469323","messageId":"xmqq8rj32b2k.fsf@gitster.g","threadId":"58200","inReplyTo":"cover-v4-0.6-00000000000-20221219T101240Z-avarab@gmail.com","subject":"Re: [PATCH v4 0/6] tests: fix ignored & hidden exit codes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-12-20T00:06:11Z","receivedAt":"2022-12-20T00:07:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> I think this should address all of the feedback on the v3, except\n> Junio's suggestion of perhaps re-arranging this series around file\n> boundaries.\n>\n> Given the potential size of that range-diff I thought it was better to\n> mosttly keep the same structure.\n\nSorry, I do not recall making such a suggestion but if I did, it\nprobably was an indication that the group of patches I suggested\nsuch a change were unreviewable as-is, and by definition range-diff\nis irrelevant if that is the case (i.e. the part that was\nunreviewable would be freshly reviewed with reorganization).\n\nIn any case, I think we have been seeing patches to unhide the exit\nstatus from more individual command invocations, a theme this series\nshould fit well.  Thanks for working on it.\n"},{"id":"469324","messageId":"xmqq4jtr2awv.fsf@gitster.g","threadId":"58200","inReplyTo":"patch-v4-2.6-d351075f0ab-20221219T101240Z-avarab@gmail.com","subject":"Re: [PATCH v4 2/6] t/lib-patch-mode.sh: fix ignored exit codes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-12-20T00:09:36Z","receivedAt":"2022-12-20T00:09:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Fix code added in b319ef70a94 (Add a small patch-mode testing library,\n> 2009-08-13) to use &&-chaining.\n>\n> This avoids losing both the exit code of a \"git\" and the \"cat\"\n> processes.\n>\n> This fixes cases where we'd have e.g. missed memory leaks under\n> SANITIZE=leak, this code doesn't leak now as far as I can tell, but I\n> discovered it while looking at leaks in related code.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  t/lib-patch-mode.sh | 11 ++++++++---\n>  1 file changed, 8 insertions(+), 3 deletions(-)\n\nLooks quite sensible.\n\n> diff --git a/t/lib-patch-mode.sh b/t/lib-patch-mode.sh\n> index cfd76bf987b..89ca1f78055 100644\n> --- a/t/lib-patch-mode.sh\n> +++ b/t/lib-patch-mode.sh\n> @@ -29,8 +29,12 @@ set_and_save_state () {\n>  \n>  # verify_state <path> <expected-worktree-content> <expected-index-content>\n>  verify_state () {\n> -\ttest \"$(cat \"$1\")\" = \"$2\" &&\n> -\ttest \"$(git show :\"$1\")\" = \"$3\"\n> +\techo \"$2\" >expect &&\n> +\ttest_cmp expect \"$1\" &&\n> +\n> +\techo \"$3\" >expect &&\n> +\tgit show :\"$1\" >actual &&\n> +\ttest_cmp expect actual\n>  }\n>  \n>  # verify_saved_state <path>\n> @@ -46,5 +50,6 @@ save_head () {\n>  }\n>  \n>  verify_saved_head () {\n> -\ttest \"$(cat _head)\" = \"$(git rev-parse HEAD)\"\n> +\tgit rev-parse HEAD >actual &&\n> +\ttest_cmp _head actual\n>  }\n"},{"id":"469325","messageId":"xmqqsfhb0vum.fsf@gitster.g","threadId":"58200","inReplyTo":"patch-v4-3.6-f5b2489609c-20221219T101240Z-avarab@gmail.com","subject":"Re: [PATCH v4 3/6] tests: don't lose exit status with \"(cd ...; test <op> $(git ...))\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-12-20T00:20:17Z","receivedAt":"2022-12-20T00:20:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> -\ttest \"a\" = \"$(cd repo && test-tool path-utils prefix_path prefix \"$(pwd)/../repolink/a\")\"\n> +\techo \"a\" >expect &&\n> +\ttest-tool -C repo path-utils prefix_path prefix \"$(cd repo && pwd)/../repolink/a\" >actual &&\n\nIf we fail to cd to 'repo', \"$(cd repo && pwd)/../repolink/a\" would\nsilently expand to nonsense, but presumably \"test-tool -C repo\"\nwould fail loudly in such a case, so we should be OK here?\n\n> @@ -28,9 +32,10 @@ test_expect_success 'preparing origin repository' '\n>  \n>  test_expect_success 'local clone without .git suffix' '\n>  \tgit clone -l -s a b &&\n> -\t(cd b &&\n> -\ttest \"$(git config --bool core.bare)\" = false &&\n> -\tgit fetch)\n> +\techo false >expect &&\n> +\tgit -C b config --bool core.bare >actual &&\n> +\ttest_cmp expect actual &&\n> +\tgit -C b fetch\n>  '\n\nI am not sure if the above with full of \"git -C\" is strictly an\nimprovement over\n\n\t(\n\t\tcd b &&\n\t\techo false >expect &&\n\t\tgit config --bool core.bare >actual &&\n\t\ttest_cmp expect actual &&\n\t\tgit fetch\n\t)\n\nand even if it were, the reason why it is better would be vastly\ndifferent from the reason why it is better that we no longer do\n\"test $(cmd) = false\".  I very much hate the pattern described on\nthe commit title of this step (which by definition this patch fixes\nmany instances of).  I.e.\n\n\t(cd ...; test <op> $(git ...))\n\nmight be something you find that needs improvements, but \"don't lose\nexit status\" ONLY applies to the \"test <op> $(git ...)\" part, and\nthe other half, i.e. (cd ...), has nothing to do with \"don't lose\nexit status\" badness.\n"},{"id":"469531","messageId":"xmqqwn6fm0e1.fsf@gitster.g","threadId":"58200","inReplyTo":"patch-v4-4.6-da66e5bf1c1-20221219T101240Z-avarab@gmail.com","subject":"Re: [PATCH v4 4/6] tests: don't lose exit status with \"test <op> $(git ...)\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-12-26T01:14:46Z","receivedAt":"2022-12-26T01:14:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> As with the preceding commit, rewrite tests that ran \"git\" inside\n> command substitution and lost the exit status of \"git\" so that we\n> notice the failing \"git\". This time around we're converting cases that\n> didn't involve a containing sub-shell around the command substitution.\n>\n> In the case of \"t0060-path-utils.sh\" and\n> \"t2005-checkout-index-symlinks.sh\" convert the relevant code to using\n> the modern style of indentation and newline wrapping while having to\n> change it.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n\nUnlike the previous one, this looks sharply focused to deal with\nhaving $(git ...) as one of the arguments to \"test\".  Looking good.\n\n"},{"id":"469532","messageId":"xmqqr0wnm071.fsf@gitster.g","threadId":"58200","inReplyTo":"patch-v4-5.6-9596702978e-20221219T101240Z-avarab@gmail.com","subject":"Re: [PATCH v4 5/6] tests: don't lose \"git\" exit codes in \"! ( git ... | grep )\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-12-26T01:18:58Z","receivedAt":"2022-12-26T01:19:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Change tests that would lose the \"git\" exit code via a negation\n> pattern to:\n\nLooking good.  thanks.\n"},{"id":"469553","messageId":"d9053dbe-a9b4-3d85-626d-0f1633058646@dunelm.org.uk","threadId":"58200","inReplyTo":"patch-v4-2.6-d351075f0ab-20221219T101240Z-avarab@gmail.com","subject":"Re: [PATCH v4 2/6] t/lib-patch-mode.sh: fix ignored exit codes","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-12-27T16:40:25Z","receivedAt":"2022-12-27T16:40:56Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Ævar\n\nOn 19/12/2022 10:19, Ævar Arnfjörð Bjarmason wrote:\n> Fix code added in b319ef70a94 (Add a small patch-mode testing library,\n> 2009-08-13) to use &&-chaining.\n> \n> This avoids losing both the exit code of a \"git\" and the \"cat\"\n> processes.\n> \n> This fixes cases where we'd have e.g. missed memory leaks under\n> SANITIZE=leak, this code doesn't leak now as far as I can tell, but I\n> discovered it while looking at leaks in related code.\n> [...] \n>   # verify_saved_state <path>\n> @@ -46,5 +50,6 @@ save_head () {\n>   }\n>   \n>   verify_saved_head () {\n> -\ttest \"$(cat _head)\" = \"$(git rev-parse HEAD)\"\n> +\tgit rev-parse HEAD >actual &&\n> +\ttest_cmp _head actual\n\nAren't these two lines are re-implementing test_cmp_rev()?\n\nBest Wishes\n\nPhillip\n\n"},{"id":"469554","messageId":"0825da46-b659-d18c-6e65-ced6ce85bd29@dunelm.org.uk","threadId":"58200","inReplyTo":"patch-v4-5.6-9596702978e-20221219T101240Z-avarab@gmail.com","subject":"Re: [PATCH v4 5/6] tests: don't lose \"git\" exit codes in \"! ( git ... | grep )\"","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-12-27T16:44:23Z","receivedAt":"2022-12-27T16:44:31Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Ævar\n\nOn 19/12/2022 10:19, Ævar Arnfjörð Bjarmason wrote:\n> Change tests that would lose the \"git\" exit code via a negation\n> pattern to:\n> \n> - In the case of \"t0055-beyond-symlinks.sh\" compare against the\n>    expected output instead.\n> \n>    We could use the same pattern as in the \"t3700-add.sh\" below, doing\n>    so would have the advantage that if we added an earlier test we\n>    wouldn't need to adjust the \"expect\" output.\n> \n>    But as \"t0055-beyond-symlinks.sh\" is a small and focused test (less\n>    than 40 lines in total) let's use \"test_cmp\" instead.\n> \n> - For \"t3700-add.sh\" use \"sed -n\" to print the expected \"bad\" part,\n>    and use \"test_must_be_empty\" to assert that it's not there. If we used\n>    \"grep\" we'd get a non-zero exit code.\n> \n>    We could use \"test_expect_code 1 grep\", but this is more consistent\n>    with existing patterns in the test suite.\n\nIt seems strange to use sed here, you could just keep using grep and \ncheck the output is empty if you don't want to use test_expect_code. \nThere is also no need to redirect the input of the sed commands.\n\nBest Wishes\n\nPhillip\n\n>    We can also remove a repeated invocation of \"git ls-files\" for the\n>    last test that's being modified in that file, and search the\n>    existing \"files\" output instead.\n> \n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>   t/t0055-beyond-symlinks.sh | 14 ++++++++++++--\n>   t/t3700-add.sh             | 18 +++++++++++++-----\n>   2 files changed, 25 insertions(+), 7 deletions(-)\n> \n> diff --git a/t/t0055-beyond-symlinks.sh b/t/t0055-beyond-symlinks.sh\n> index 6bada370225..c3eb1158ef9 100755\n> --- a/t/t0055-beyond-symlinks.sh\n> +++ b/t/t0055-beyond-symlinks.sh\n> @@ -15,12 +15,22 @@ test_expect_success SYMLINKS setup '\n>   \n>   test_expect_success SYMLINKS 'update-index --add beyond symlinks' '\n>   \ttest_must_fail git update-index --add c/d &&\n> -\t! ( git ls-files | grep c/d )\n> +\tcat >expect <<-\\EOF &&\n> +\ta\n> +\tb/d\n> +\tEOF\n> +\tgit ls-files >actual &&\n> +\ttest_cmp expect actual\n>   '\n>   \n>   test_expect_success SYMLINKS 'add beyond symlinks' '\n>   \ttest_must_fail git add c/d &&\n> -\t! ( git ls-files | grep c/d )\n> +\tcat >expect <<-\\EOF &&\n> +\ta\n> +\tb/d\n> +\tEOF\n> +\tgit ls-files >actual &&\n> +\ttest_cmp expect actual\n>   '\n>   \n>   test_done\n> diff --git a/t/t3700-add.sh b/t/t3700-add.sh\n> index 51afbd7b24a..82dd768944f 100755\n> --- a/t/t3700-add.sh\n> +++ b/t/t3700-add.sh\n> @@ -106,24 +106,32 @@ test_expect_success '.gitignore test setup' '\n>   \n>   test_expect_success '.gitignore is honored' '\n>   \tgit add . &&\n> -\t! (git ls-files | grep \"\\\\.ig\")\n> +\tgit ls-files >files &&\n> +\tsed -n \"/\\\\.ig/p\" <files >actual &&\n> +\ttest_must_be_empty actual\n>   '\n>   \n>   test_expect_success 'error out when attempting to add ignored ones without -f' '\n>   \ttest_must_fail git add a.?? &&\n> -\t! (git ls-files | grep \"\\\\.ig\")\n> +\tgit ls-files >files &&\n> +\tsed -n \"/\\\\.ig/p\" <files >actual &&\n> +\ttest_must_be_empty actual\n>   '\n>   \n>   test_expect_success 'error out when attempting to add ignored ones without -f' '\n>   \ttest_must_fail git add d.?? &&\n> -\t! (git ls-files | grep \"\\\\.ig\")\n> +\tgit ls-files >files &&\n> +\tsed -n \"/\\\\.ig/p\" <files >actual &&\n> +\ttest_must_be_empty actual\n>   '\n>   \n>   test_expect_success 'error out when attempting to add ignored ones but add others' '\n>   \ttouch a.if &&\n>   \ttest_must_fail git add a.?? &&\n> -\t! (git ls-files | grep \"\\\\.ig\") &&\n> -\t(git ls-files | grep a.if)\n> +\tgit ls-files >files &&\n> +\tsed -n \"/\\\\.ig/p\" <files >actual &&\n> +\ttest_must_be_empty actual &&\n> +\tgrep a.if files\n>   '\n>   \n>   test_expect_success 'add ignored ones with -f' '\n"},{"id":"469555","messageId":"6efe13ea-8782-2337-1626-9687e2219680@dunelm.org.uk","threadId":"58200","inReplyTo":"patch-v4-6.6-94df7a1764e-20221219T101240Z-avarab@gmail.com","subject":"Re: [PATCH v4 6/6] tests: don't lose misc \"git\" exit codes","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-12-27T16:46:59Z","receivedAt":"2022-12-27T16:47:49Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Ævar\n\nOn 19/12/2022 10:19, Ævar Arnfjörð Bjarmason wrote:\n> Fix a few miscellaneous cases where:\n> \n> - We lost the \"git\" exit code via \"git ... | grep\"\n> - Likewise by having a $(git) argument to git itself\n> - Used \"test -z\" to check that a command emitted no output, we can use\n>    \"test_must_be_empty\" and &&-chaining instead.\n> \n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> [...]\n> diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh\n> index 5841f280fb2..f1fe5d60677 100755\n> --- a/t/t3701-add-interactive.sh\n> +++ b/t/t3701-add-interactive.sh\n> @@ -296,9 +296,11 @@ test_expect_success FILEMODE 'stage mode and hunk' '\n>   \techo content >>file &&\n>   \tchmod +x file &&\n>   \tprintf \"y\\\\ny\\\\n\" | git add -p &&\n> -\tgit diff --cached file | grep \"new mode\" &&\n> -\tgit diff --cached file | grep \"+content\" &&\n> -\ttest -z \"$(git diff file)\"\n> +\tgit diff --cached file >out &&\n> +\tgrep \"new mode\" out &&\n> +\tgrep \"+content\" out &&\n> +\tgit diff file >out &&\n> +\ttest_must_be_empty out\n\n\"git diff --exit-code file\" would suffice here, we don't need to \nredirect the output and check that it is empty.\n\nBest Wishes\n\nPhillip\n"},{"id":"469556","messageId":"2f41ce2e-cc6e-815e-9744-ea4e5c659b35@dunelm.org.uk","threadId":"58200","inReplyTo":"0825da46-b659-d18c-6e65-ced6ce85bd29@dunelm.org.uk","subject":"Re: [PATCH v4 5/6] tests: don't lose \"git\" exit codes in \"! ( git ... | grep )\"","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-12-27T17:13:49Z","receivedAt":"2022-12-27T17:13:58Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 27/12/2022 16:44, Phillip Wood wrote:\n> On 19/12/2022 10:19, Ævar Arnfjörð Bjarmason wrote:\n>> - For \"t3700-add.sh\" use \"sed -n\" to print the expected \"bad\" part,\n>>    and use \"test_must_be_empty\" to assert that it's not there. If we used\n>>    \"grep\" we'd get a non-zero exit code.\n>>\n>>    We could use \"test_expect_code 1 grep\", but this is more consistent\n>>    with existing patterns in the test suite.\n> \n> It seems strange to use sed here, you could just keep using grep and \n> check the output is empty if you don't want to use test_expect_code.\n\nSorry ignore that, using 'sed -n' means we don't have to worry about the \nexit code.\n\n> There is also no need to redirect the input of the sed commands.\n> \n> Best Wishes\n> \n> Phillip\n> \n>>    We can also remove a repeated invocation of \"git ls-files\" for the\n>>    last test that's being modified in that file, and search the\n>>    existing \"files\" output instead.\n>>\n>> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n>> ---\n>>   t/t0055-beyond-symlinks.sh | 14 ++++++++++++--\n>>   t/t3700-add.sh             | 18 +++++++++++++-----\n>>   2 files changed, 25 insertions(+), 7 deletions(-)\n>>\n>> diff --git a/t/t0055-beyond-symlinks.sh b/t/t0055-beyond-symlinks.sh\n>> index 6bada370225..c3eb1158ef9 100755\n>> --- a/t/t0055-beyond-symlinks.sh\n>> +++ b/t/t0055-beyond-symlinks.sh\n>> @@ -15,12 +15,22 @@ test_expect_success SYMLINKS setup '\n>>   test_expect_success SYMLINKS 'update-index --add beyond symlinks' '\n>>       test_must_fail git update-index --add c/d &&\n>> -    ! ( git ls-files | grep c/d )\n>> +    cat >expect <<-\\EOF &&\n>> +    a\n>> +    b/d\n>> +    EOF\n>> +    git ls-files >actual &&\n>> +    test_cmp expect actual\n>>   '\n>>   test_expect_success SYMLINKS 'add beyond symlinks' '\n>>       test_must_fail git add c/d &&\n>> -    ! ( git ls-files | grep c/d )\n>> +    cat >expect <<-\\EOF &&\n>> +    a\n>> +    b/d\n>> +    EOF\n>> +    git ls-files >actual &&\n>> +    test_cmp expect actual\n>>   '\n>>   test_done\n>> diff --git a/t/t3700-add.sh b/t/t3700-add.sh\n>> index 51afbd7b24a..82dd768944f 100755\n>> --- a/t/t3700-add.sh\n>> +++ b/t/t3700-add.sh\n>> @@ -106,24 +106,32 @@ test_expect_success '.gitignore test setup' '\n>>   test_expect_success '.gitignore is honored' '\n>>       git add . &&\n>> -    ! (git ls-files | grep \"\\\\.ig\")\n>> +    git ls-files >files &&\n>> +    sed -n \"/\\\\.ig/p\" <files >actual &&\n>> +    test_must_be_empty actual\n>>   '\n>>   test_expect_success 'error out when attempting to add ignored ones \n>> without -f' '\n>>       test_must_fail git add a.?? &&\n>> -    ! (git ls-files | grep \"\\\\.ig\")\n>> +    git ls-files >files &&\n>> +    sed -n \"/\\\\.ig/p\" <files >actual &&\n>> +    test_must_be_empty actual\n>>   '\n>>   test_expect_success 'error out when attempting to add ignored ones \n>> without -f' '\n>>       test_must_fail git add d.?? &&\n>> -    ! (git ls-files | grep \"\\\\.ig\")\n>> +    git ls-files >files &&\n>> +    sed -n \"/\\\\.ig/p\" <files >actual &&\n>> +    test_must_be_empty actual\n>>   '\n>>   test_expect_success 'error out when attempting to add ignored ones \n>> but add others' '\n>>       touch a.if &&\n>>       test_must_fail git add a.?? &&\n>> -    ! (git ls-files | grep \"\\\\.ig\") &&\n>> -    (git ls-files | grep a.if)\n>> +    git ls-files >files &&\n>> +    sed -n \"/\\\\.ig/p\" <files >actual &&\n>> +    test_must_be_empty actual &&\n>> +    grep a.if files\n>>   '\n>>   test_expect_success 'add ignored ones with -f' '\n"},{"id":"469557","messageId":"221227.86h6xgvhgi.gmgdl@evledraar.gmail.com","threadId":"58200","inReplyTo":"d9053dbe-a9b4-3d85-626d-0f1633058646@dunelm.org.uk","subject":"Re: [PATCH v4 2/6] t/lib-patch-mode.sh: fix ignored exit codes","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-27T18:14:52Z","receivedAt":"2022-12-27T18:18:13Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Dec 27 2022, Phillip Wood wrote:\n\n> Hi Ævar\n>\n> On 19/12/2022 10:19, Ævar Arnfjörð Bjarmason wrote:\n>> Fix code added in b319ef70a94 (Add a small patch-mode testing library,\n>> 2009-08-13) to use &&-chaining.\n>> This avoids losing both the exit code of a \"git\" and the \"cat\"\n>> processes.\n>> This fixes cases where we'd have e.g. missed memory leaks under\n>> SANITIZE=leak, this code doesn't leak now as far as I can tell, but I\n>> discovered it while looking at leaks in related code.\n>> [...]   # verify_saved_state <path>\n>> @@ -46,5 +50,6 @@ save_head () {\n>>   }\n>>     verify_saved_head () {\n>> -\ttest \"$(cat _head)\" = \"$(git rev-parse HEAD)\"\n>> +\tgit rev-parse HEAD >actual &&\n>> +\ttest_cmp _head actual\n>\n> Aren't these two lines are re-implementing test_cmp_rev()?\n\nIt does --verify, and this does not.\n\nCould we use it? Yes, but I wanted to narrowly focus on just fixing the\nlost exit codes in this series. Once you start to untangle \"save_head\"\nand \"verify_saved_head\" you'll see that whether we narrowly used a\nhelper here or not isn't the only thing we could improve.\n\nBut such an improvement would make use use --verify, and we'd then want\nto use that \"--verify\" for the earlier saved_head too, etc.\n"},{"id":"469558","messageId":"221227.86cz84vh1q.gmgdl@evledraar.gmail.com","threadId":"58200","inReplyTo":"6efe13ea-8782-2337-1626-9687e2219680@dunelm.org.uk","subject":"Re: [PATCH v4 6/6] tests: don't lose misc \"git\" exit codes","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-27T18:18:18Z","receivedAt":"2022-12-27T18:27:03Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Dec 27 2022, Phillip Wood wrote:\n\n> Hi Ævar\n>\n> On 19/12/2022 10:19, Ævar Arnfjörð Bjarmason wrote:\n>> Fix a few miscellaneous cases where:\n>> - We lost the \"git\" exit code via \"git ... | grep\"\n>> - Likewise by having a $(git) argument to git itself\n>> - Used \"test -z\" to check that a command emitted no output, we can use\n>>    \"test_must_be_empty\" and &&-chaining instead.\n>> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n>> [...]\n>> diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh\n>> index 5841f280fb2..f1fe5d60677 100755\n>> --- a/t/t3701-add-interactive.sh\n>> +++ b/t/t3701-add-interactive.sh\n>> @@ -296,9 +296,11 @@ test_expect_success FILEMODE 'stage mode and hunk' '\n>>   \techo content >>file &&\n>>   \tchmod +x file &&\n>>   \tprintf \"y\\\\ny\\\\n\" | git add -p &&\n>> -\tgit diff --cached file | grep \"new mode\" &&\n>> -\tgit diff --cached file | grep \"+content\" &&\n>> -\ttest -z \"$(git diff file)\"\n>> +\tgit diff --cached file >out &&\n>> +\tgrep \"new mode\" out &&\n>> +\tgrep \"+content\" out &&\n>> +\tgit diff file >out &&\n>> +\ttest_must_be_empty out\n>\n> \"git diff --exit-code file\" would suffice here, we don't need to\n> redirect the output and check that it is empty.\n\nCorrect.\n\nOr even \"git diff-files -s --exit-code\", which might make things clearer\nstill, or have this use the \"diff_cmp\" helper defined in the test file,\nas most of its siblings do.\n\nBut as with a sibling comment of mine I wanted to avoid starting to\nrefactoring these tests for general betterment, and just to narrowly\navoid losing the exit code.\n\n"},{"id":"469569","messageId":"xmqqsfh0qvy5.fsf@gitster.g","threadId":"58200","inReplyTo":"0825da46-b659-d18c-6e65-ced6ce85bd29@dunelm.org.uk","subject":"Re: [PATCH v4 5/6] tests: don't lose \"git\" exit codes in \"! ( git ... | grep )\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-12-27T23:16:18Z","receivedAt":"2022-12-27T23:16:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Phillip Wood <phillip.wood123@gmail.com> writes:\n\n> It seems strange to use sed here, you could just keep using grep and\n> check the output is empty if you don't want to use\n> test_expect_code.\n\nI am not sure what you mean by test_expect_code, but we can do the\n\"! grep -e pattern file\" to ensure that the unwanted pattern does\nnot exist.  Unlike our command, we do not worry about system \"grep\"\nbeing buggy, so if it yields non-zero, it is because no line in the\nfile matches the pattern.  After all, that is what the original code\nfixed by this patch wanted to check.\n\nThe \"do not lose exit code of the git command\" part of the goal is\nachieved by breaking the pipeline already, and we can keep the test\nthat uses grep.\n\nHaving said that, switching to \"sed\" is not too bad.  If we wanted\nto expect N lines that matches the pattern in the file, with grep,\nwe need to do \"! grep\" dance when (and only when) N is zero.  With\nsed, we do not have to worry about it.\n\n> There is also no need to redirect the input of the\n> sed commands.\n\nThat's true.\n"},{"id":"469570","messageId":"xmqqo7roqvw7.fsf@gitster.g","threadId":"58200","inReplyTo":"6efe13ea-8782-2337-1626-9687e2219680@dunelm.org.uk","subject":"Re: [PATCH v4 6/6] tests: don't lose misc \"git\" exit codes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-12-27T23:17:28Z","receivedAt":"2022-12-27T23:17:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Phillip Wood <phillip.wood123@gmail.com> writes:\n\n>> -\ttest -z \"$(git diff file)\"\n>> ...\n>> +\tgit diff file >out &&\n>> +\ttest_must_be_empty out\n>\n> \"git diff --exit-code file\" would suffice here, we don't need to\n> redirect the output and check that it is empty.\n\nYes, but the test is trying to be faithful to not just the intent\nbut also the implementation of the original, I think.\n"},{"id":"471623","messageId":"cover-v5-0.6-00000000000-20230206T224200Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v4-0.6-00000000000-20221219T101240Z-avarab@gmail.com","subject":"[PATCH v5 0/6] tests: fix ignored & hidden exit codes","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2023-02-06T22:44:27Z","receivedAt":"2023-02-06T22:44:48Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Various fixes for \"git\" on the LHS of a pipe, but mostly when in\n\"test\" expressions like:\n\n       test str = \"$(git some-command)\" &&\n\nChanges since v4[1]:\n\n * Tried to address all outstanding concernse, some with commit\n   message clarifications, others with code changes.\n * The main code change here is to avoid converting code adjacent to\n   the fixed \"test\" code away from sub-shell use, per Junio's request.\n\nBranch & CI for this at:\nhttps://github.com/avar/git/tree/avar/fix-even-more-broken-test-code-hiding-failures-5\n\n1. https://lore.kernel.org/git/cover-v4-0.6-00000000000-20221219T101240Z-avarab@gmail.com/\n\nÆvar Arnfjörð Bjarmason (6):\n  auto-crlf tests: don't lose exit code in loops and outside tests\n  t/lib-patch-mode.sh: fix ignored exit codes\n  tests: don't lose exit status with \"(cd ...; test <op> $(git ...))\"\n  tests: don't lose exit status with \"test <op> $(git ...)\"\n  tests: don't lose \"git\" exit codes in \"! ( git ... | grep )\"\n  tests: don't lose misc \"git\" exit codes\n\n t/lib-httpd.sh                     |   8 ++-\n t/lib-patch-mode.sh                |  11 ++-\n t/lib-submodule-update.sh          |  26 ++++---\n t/t0001-init.sh                    |   9 ++-\n t/t0002-gitfile.sh                 |   4 +-\n t/t0027-auto-crlf.sh               |  66 ++++++++++--------\n t/t0055-beyond-symlinks.sh         |  14 +++-\n t/t0060-path-utils.sh              | 108 +++++++++++++++++++++--------\n t/t0100-previous.sh                |   8 ++-\n t/t1401-symbolic-ref.sh            |   3 +-\n t/t1504-ceiling-dirs.sh            |   8 ++-\n t/t2005-checkout-index-symlinks.sh |   8 ++-\n t/t3200-branch.sh                  |   8 ++-\n t/t3700-add.sh                     |  18 +++--\n t/t3701-add-interactive.sh         |   8 ++-\n t/t5522-pull-symlink.sh            |   4 +-\n t/t5605-clone-local.sh             |  12 +++-\n t/t7402-submodule-rebase.sh        |  23 ++++--\n t/t7504-commit-msg-hook.sh         |   4 +-\n t/t7516-commit-races.sh            |   3 +-\n t/t7810-grep.sh                    |   4 +-\n 21 files changed, 245 insertions(+), 112 deletions(-)\n\nRange-diff against v4:\n1:  68d276dd421 ! 1:  66d0f91e6aa auto-crlf tests: don't lose exit code in loops and outside tests\n    @@ Commit message\n         this failure under SANITIZE=leak when these invocations had errored\n         out, even under \"--immediate\".\n     \n    +    For checkout_files() we could run one test_expect_success() instead of\n    +    the 5 we run now in a loop.\n    +\n    +    But as this function added in [1] is already taking pains to split up\n    +    its setup into phases (there are 5 more \"test_expect_success()\" at the\n    +    end of it already, see [1]), let's follow that existing convention.\n    +\n    +    1. 343151dcbdf (t0027: combinations of core.autocrlf, core.eol and text, 2014-06-29)\n    +\n         Helped-by: René Scharfe <l.s.r@web.de>\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n2:  d351075f0ab ! 2:  97f8b6a7b86 t/lib-patch-mode.sh: fix ignored exit codes\n    @@ Commit message\n         SANITIZE=leak, this code doesn't leak now as far as I can tell, but I\n         discovered it while looking at leaks in related code.\n     \n    +    For \"verify_saved_head()\" we could make use of \"test_cmp_rev\" with\n    +    some changes, but it uses \"git rev-parse --verify\", and this existing\n    +    test does not. I think it could safely use it, but let's avoid the\n    +    while-at-it change, and narrowly fix the exit code problem.\n    +\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## t/lib-patch-mode.sh ##\n3:  f5b2489609c ! 3:  d8f4c4a6d9e tests: don't lose exit status with \"(cd ...; test <op> $(git ...))\"\n    @@ Commit message\n         exit status of \"git\" so that we notice the failing \"git\".\n     \n         Have them use modern patterns such as a \"test_cmp\" of the expected\n    -    outputs instead, and avoid needlessly spawning sub-shell in favor of\n    -    using \"git -C <dir>\".\n    +    outputs instead.\n     \n         We'll fix more of these these in the subsequent commit, for now we're\n         only converting the cases where this loss of exit code was combined\n    -    with spawning a sub-shell. The one exception to that is the casein\n    -    \"t3200-branch.sh\" where adjacent code didn't use a sub-shell, let's\n    -    convert that here as it's within the same hunk.\n    +    with spawning a sub-shell.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n    @@ t/lib-httpd.sh: test_http_push_nonff () {\n      \t\ttest_must_fail git push -v origin >output 2>&1 &&\n     -\t\t(cd \"$REMOTE_REPO\" &&\n     -\t\t test $HEAD = $(git rev-parse --verify HEAD))\n    -+\t\techo \"$HEAD\" >expect &&\n    -+\t\tgit -C \"$REMOTE_REPO\" rev-parse --verify HEAD >actual &&\n    -+\t\ttest_cmp expect actual\n    ++\t\t(\n    ++\t\t\tcd \"$REMOTE_REPO\" &&\n    ++\t\t\techo \"$HEAD\" >expect &&\n    ++\t\t\tgit rev-parse --verify HEAD >actual &&\n    ++\t\t\ttest_cmp expect actual\n    ++\t\t)\n      \t'\n      \n      \ttest_expect_success 'non-fast-forward push show ref status' '\n    @@ t/t0060-path-utils.sh: test_expect_success 'prefix_path rejects absolute path to\n      \tln -s repo repolink &&\n     -\ttest \"a\" = \"$(cd repo && test-tool path-utils prefix_path prefix \"$(pwd)/../repolink/a\")\"\n     +\techo \"a\" >expect &&\n    -+\ttest-tool -C repo path-utils prefix_path prefix \"$(cd repo && pwd)/../repolink/a\" >actual &&\n    ++\trepo_path=\"$(cd repo && pwd)\" &&\n    ++\ttest-tool -C repo path-utils prefix_path prefix \"$repo_path/../repolink/a\" >actual &&\n     +\ttest_cmp expect actual\n      '\n      \n      relative_path /foo/a/b/c/\t/foo/a/b/\tc/\n     \n      ## t/t3200-branch.sh ##\n    -@@ t/t3200-branch.sh: test_expect_success 'git branch -M baz bam should succeed when baz is checked ou\n    - test_expect_success 'git branch -M baz bam should succeed within a worktree in which baz is checked out' '\n    - \tgit checkout -b baz &&\n    - \tgit worktree add -f bazdir baz &&\n    --\t(\n    --\t\tcd bazdir &&\n    --\t\tgit branch -M baz bam &&\n    +@@ t/t3200-branch.sh: test_expect_success 'git branch -M baz bam should succeed within a worktree in w\n    + \t(\n    + \t\tcd bazdir &&\n    + \t\tgit branch -M baz bam &&\n     -\t\ttest $(git rev-parse --abbrev-ref HEAD) = bam\n    --\t) &&\n    ++\t\techo bam >expect &&\n    ++\t\tgit rev-parse --abbrev-ref HEAD >actual &&\n    ++\t\ttest_cmp expect actual\n    + \t) &&\n     -\ttest $(git rev-parse --abbrev-ref HEAD) = bam &&\n    -+\tgit -C \"$bazdir\" branch -M baz bam &&\n    -+\techo \"bam\" >expect &&\n    -+\tgit -C \"$bazdir\" rev-parse --abbrev-ref HEAD >actual &&\n    -+\ttest_cmp expect actual &&\n    -+\techo \"bam\" >expect &&\n    ++\techo bam >expect &&\n     +\tgit rev-parse --abbrev-ref HEAD >actual &&\n     +\ttest_cmp expect actual &&\n      \trm -r bazdir &&\n    @@ t/t5605-clone-local.sh: test_expect_success 'preparing origin repository' '\n      \tgit bundle create b2.bundle main &&\n      \tmkdir dir &&\n     @@ t/t5605-clone-local.sh: test_expect_success 'preparing origin repository' '\n    - \n      test_expect_success 'local clone without .git suffix' '\n      \tgit clone -l -s a b &&\n    --\t(cd b &&\n    + \t(cd b &&\n     -\ttest \"$(git config --bool core.bare)\" = false &&\n    --\tgit fetch)\n     +\techo false >expect &&\n    -+\tgit -C b config --bool core.bare >actual &&\n    ++\tgit config --bool core.bare >actual &&\n     +\ttest_cmp expect actual &&\n    -+\tgit -C b fetch\n    + \tgit fetch)\n      '\n      \n    - test_expect_success 'local clone with .git suffix' '\n     \n      ## t/t7402-submodule-rebase.sh ##\n     @@ t/t7402-submodule-rebase.sh: test_expect_success 'stash with a dirty submodule' '\n4:  da66e5bf1c1 = 4:  e6f56478b65 tests: don't lose exit status with \"test <op> $(git ...)\"\n5:  9596702978e = 5:  55abdbef49f tests: don't lose \"git\" exit codes in \"! ( git ... | grep )\"\n6:  94df7a1764e = 6:  e7f10c0641a tests: don't lose misc \"git\" exit codes\n-- \n2.39.1.1425.gac85d95d48c\n\n"},{"id":"471624","messageId":"patch-v5-1.6-66d0f91e6aa-20230206T224200Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v5-0.6-00000000000-20230206T224200Z-avarab@gmail.com","subject":"[PATCH v5 1/6] auto-crlf tests: don't lose exit code in loops and outside tests","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2023-02-06T22:44:28Z","receivedAt":"2023-02-06T22:44:49Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the functions which are called from within\n\"test_expect_success\" to add the \"|| return 1\" idiom to their\nfor-loops, so we won't lose the exit code of \"cp\", \"git\" etc.\n\nThen for those setup functions that aren't called from a\n\"test_expect_success\" we need to put the setup code in a\n\"test_expect_success\" as well. It would not be enough to properly\n&&-chain these, as the calling code is the top-level script itself. As\nwe don't run the tests with \"set -e\" we won't report failing commands\nat the top-level.\n\nThe \"checkout\" part of this would miss memory leaks under\nSANITIZE=leak, this code doesn't leak (the relevant \"git checkout\"\nleak has been fixed), but in a past version of git we'd continue past\nthis failure under SANITIZE=leak when these invocations had errored\nout, even under \"--immediate\".\n\nFor checkout_files() we could run one test_expect_success() instead of\nthe 5 we run now in a loop.\n\nBut as this function added in [1] is already taking pains to split up\nits setup into phases (there are 5 more \"test_expect_success()\" at the\nend of it already, see [1]), let's follow that existing convention.\n\n1. 343151dcbdf (t0027: combinations of core.autocrlf, core.eol and text, 2014-06-29)\n\nHelped-by: René Scharfe <l.s.r@web.de>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t0027-auto-crlf.sh | 66 +++++++++++++++++++++++++-------------------\n 1 file changed, 38 insertions(+), 28 deletions(-)\n\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex a94ac1eae37..2f57c8669cb 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -70,7 +70,8 @@ create_NNO_MIX_files () {\n \t\t\t\tcp CRLF        ${pfx}_CRLF.txt &&\n \t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt &&\n \t\t\t\tcp LF_mix_CR   ${pfx}_LF_mix_CR.txt &&\n-\t\t\t\tcp CRLF_nul    ${pfx}_CRLF_nul.txt\n+\t\t\t\tcp CRLF_nul    ${pfx}_CRLF_nul.txt ||\n+\t\t\t\treturn 1\n \t\t\tdone\n \t\tdone\n \tdone\n@@ -101,7 +102,8 @@ commit_check_warn () {\n \tdo\n \t\tfname=${pfx}_$f.txt &&\n \t\tcp $f $fname &&\n-\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\"\n+\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\" ||\n+\t\treturn 1\n \tdone &&\n \tgit commit -m \"core.autocrlf $crlf\" &&\n \tcheck_warning \"$lfname\" ${pfx}_LF.err &&\n@@ -121,15 +123,19 @@ commit_chk_wrnNNO () {\n \tlfmixcr=$1 ; shift\n \tcrlfnul=$1 ; shift\n \tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n-\t#Commit files on top of existing file\n-\tcreate_gitattributes \"$attr\" $aeol &&\n-\tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n-\tdo\n-\t\tfname=${pfx}_$f.txt &&\n-\t\tcp $f $fname &&\n-\t\tprintf Z >>\"$fname\" &&\n-\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\"\n-\tdone\n+\n+\ttest_expect_success 'setup commit NNO files' '\n+\t\t#Commit files on top of existing file\n+\t\tcreate_gitattributes \"$attr\" $aeol &&\n+\t\tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n+\t\tdo\n+\t\t\tfname=${pfx}_$f.txt &&\n+\t\t\tcp $f $fname &&\n+\t\t\tprintf Z >>\"$fname\" &&\n+\t\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\" ||\n+\t\t\treturn 1\n+\t\tdone\n+\t'\n \n \ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr LF\" '\n \t\tcheck_warning \"$lfwarn\" ${pfx}_LF.err\n@@ -163,15 +169,19 @@ commit_MIX_chkwrn () {\n \tlfmixcr=$1 ; shift\n \tcrlfnul=$1 ; shift\n \tpfx=MIX_attr_${attr}_aeol_${aeol}_${crlf}\n-\t#Commit file with CLRF_mix_LF on top of existing file\n-\tcreate_gitattributes \"$attr\" $aeol &&\n-\tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n-\tdo\n-\t\tfname=${pfx}_$f.txt &&\n-\t\tcp CRLF_mix_LF $fname &&\n-\t\tprintf Z >>\"$fname\" &&\n-\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\"\n-\tdone\n+\n+\ttest_expect_success 'setup commit file with mixed EOL' '\n+\t\t#Commit file with CLRF_mix_LF on top of existing file\n+\t\tcreate_gitattributes \"$attr\" $aeol &&\n+\t\tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n+\t\tdo\n+\t\t\tfname=${pfx}_$f.txt &&\n+\t\t\tcp CRLF_mix_LF $fname &&\n+\t\t\tprintf Z >>\"$fname\" &&\n+\t\t\tgit -c core.autocrlf=$crlf add $fname 2>\"${pfx}_$f.err\" ||\n+\t\t\treturn 1\n+\t\tdone\n+\t'\n \n \ttest_expect_success \"commit file with mixed EOL onto LF crlf=$crlf attr=$attr\" '\n \t\tcheck_warning \"$lfwarn\" ${pfx}_LF.err\n@@ -289,17 +299,17 @@ checkout_files () {\n \tlfmixcrlf=$1 ; shift\n \tlfmixcr=$1 ; shift\n \tcrlfnul=$1 ; shift\n-\tcreate_gitattributes \"$attr\" $ident $aeol &&\n-\tgit config core.autocrlf $crlf &&\n+\ttest_expect_success \"setup config for checkout attr=$attr ident=$ident aeol=$aeol core.autocrlf=$crlf\" '\n+\t\tcreate_gitattributes \"$attr\" $ident $aeol &&\n+\t\tgit config core.autocrlf $crlf\n+\t'\n \tpfx=eol_${ceol}_crlf_${crlf}_attr_${attr}_ &&\n \tfor f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul\n \tdo\n-\t\trm crlf_false_attr__$f.txt &&\n-\t\tif test -z \"$ceol\"; then\n-\t\t\tgit checkout -- crlf_false_attr__$f.txt\n-\t\telse\n-\t\t\tgit -c core.eol=$ceol checkout -- crlf_false_attr__$f.txt\n-\t\tfi\n+\t\ttest_expect_success \"setup $f checkout ${ceol:+ with -c core.eol=$ceol}\"  '\n+\t\t\trm -f crlf_false_attr__$f.txt &&\n+\t\t\tgit ${ceol:+-c core.eol=$ceol} checkout -- crlf_false_attr__$f.txt\n+\t\t'\n \tdone\n \n \ttest_expect_success \"ls-files --eol attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol\" '\n-- \n2.39.1.1425.gac85d95d48c\n\n"},{"id":"471625","messageId":"patch-v5-2.6-97f8b6a7b86-20230206T224200Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v5-0.6-00000000000-20230206T224200Z-avarab@gmail.com","subject":"[PATCH v5 2/6] t/lib-patch-mode.sh: fix ignored exit codes","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2023-02-06T22:44:29Z","receivedAt":"2023-02-06T22:44:57Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Fix code added in b319ef70a94 (Add a small patch-mode testing library,\n2009-08-13) to use &&-chaining.\n\nThis avoids losing both the exit code of a \"git\" and the \"cat\"\nprocesses.\n\nThis fixes cases where we'd have e.g. missed memory leaks under\nSANITIZE=leak, this code doesn't leak now as far as I can tell, but I\ndiscovered it while looking at leaks in related code.\n\nFor \"verify_saved_head()\" we could make use of \"test_cmp_rev\" with\nsome changes, but it uses \"git rev-parse --verify\", and this existing\ntest does not. I think it could safely use it, but let's avoid the\nwhile-at-it change, and narrowly fix the exit code problem.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/lib-patch-mode.sh | 11 ++++++++---\n 1 file changed, 8 insertions(+), 3 deletions(-)\n\ndiff --git a/t/lib-patch-mode.sh b/t/lib-patch-mode.sh\nindex cfd76bf987b..89ca1f78055 100644\n--- a/t/lib-patch-mode.sh\n+++ b/t/lib-patch-mode.sh\n@@ -29,8 +29,12 @@ set_and_save_state () {\n \n # verify_state <path> <expected-worktree-content> <expected-index-content>\n verify_state () {\n-\ttest \"$(cat \"$1\")\" = \"$2\" &&\n-\ttest \"$(git show :\"$1\")\" = \"$3\"\n+\techo \"$2\" >expect &&\n+\ttest_cmp expect \"$1\" &&\n+\n+\techo \"$3\" >expect &&\n+\tgit show :\"$1\" >actual &&\n+\ttest_cmp expect actual\n }\n \n # verify_saved_state <path>\n@@ -46,5 +50,6 @@ save_head () {\n }\n \n verify_saved_head () {\n-\ttest \"$(cat _head)\" = \"$(git rev-parse HEAD)\"\n+\tgit rev-parse HEAD >actual &&\n+\ttest_cmp _head actual\n }\n-- \n2.39.1.1425.gac85d95d48c\n\n"},{"id":"471626","messageId":"patch-v5-3.6-d8f4c4a6d9e-20230206T224200Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v5-0.6-00000000000-20230206T224200Z-avarab@gmail.com","subject":"[PATCH v5 3/6] tests: don't lose exit status with \"(cd ...; test <op> $(git ...))\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2023-02-06T22:44:30Z","receivedAt":"2023-02-06T22:45:00Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Rewrite tests that ran \"git\" inside command substitution and lost the\nexit status of \"git\" so that we notice the failing \"git\".\n\nHave them use modern patterns such as a \"test_cmp\" of the expected\noutputs instead.\n\nWe'll fix more of these these in the subsequent commit, for now we're\nonly converting the cases where this loss of exit code was combined\nwith spawning a sub-shell.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/lib-httpd.sh              |  8 ++++++--\n t/lib-submodule-update.sh   | 22 +++++++++-------------\n t/t0060-path-utils.sh       |  5 ++++-\n t/t3200-branch.sh           |  8 ++++++--\n t/t5605-clone-local.sh      | 12 +++++++++---\n t/t7402-submodule-rebase.sh | 14 +++++++++++---\n 6 files changed, 45 insertions(+), 24 deletions(-)\n\ndiff --git a/t/lib-httpd.sh b/t/lib-httpd.sh\nindex 608949ea80b..b8b1d044e8b 100644\n--- a/t/lib-httpd.sh\n+++ b/t/lib-httpd.sh\n@@ -217,8 +217,12 @@ test_http_push_nonff () {\n \t\tgit commit -a -m path2 --amend &&\n \n \t\ttest_must_fail git push -v origin >output 2>&1 &&\n-\t\t(cd \"$REMOTE_REPO\" &&\n-\t\t test $HEAD = $(git rev-parse --verify HEAD))\n+\t\t(\n+\t\t\tcd \"$REMOTE_REPO\" &&\n+\t\t\techo \"$HEAD\" >expect &&\n+\t\t\tgit rev-parse --verify HEAD >actual &&\n+\t\t\ttest_cmp expect actual\n+\t\t)\n \t'\n \n \ttest_expect_success 'non-fast-forward push show ref status' '\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 2d31fcfda1f..d7c2b670b4a 100644\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -168,20 +168,16 @@ replace_gitfile_with_git_dir () {\n # Note that this only supports submodules at the root level of the\n # superproject, with the default name, i.e. same as its path.\n test_git_directory_is_unchanged () {\n-\t(\n-\t\tcd \".git/modules/$1\" &&\n-\t\t# does core.worktree point at the right place?\n-\t\ttest \"$(git config core.worktree)\" = \"../../../$1\" &&\n-\t\t# remove it temporarily before comparing, as\n-\t\t# \"$1/.git/config\" lacks it...\n-\t\tgit config --unset core.worktree\n-\t) &&\n+\t# does core.worktree point at the right place?\n+\techo \"../../../$1\" >expect &&\n+\tgit -C \".git/modules/$1\" config core.worktree >actual &&\n+\ttest_cmp expect actual &&\n+\t# remove it temporarily before comparing, as\n+\t# \"$1/.git/config\" lacks it...\n+\tgit -C \".git/modules/$1\" config --unset core.worktree &&\n \tdiff -r \".git/modules/$1\" \"$1/.git\" &&\n-\t(\n-\t\t# ... and then restore.\n-\t\tcd \".git/modules/$1\" &&\n-\t\tgit config core.worktree \"../../../$1\"\n-\t)\n+\t# ... and then restore.\n+\tgit -C \".git/modules/$1\" config core.worktree \"../../../$1\"\n }\n \n test_git_directory_exists () {\ndiff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh\nindex 68e29c904a6..dcc78fb6a7b 100755\n--- a/t/t0060-path-utils.sh\n+++ b/t/t0060-path-utils.sh\n@@ -255,7 +255,10 @@ test_expect_success 'prefix_path rejects absolute path to dir with same beginnin\n test_expect_success SYMLINKS 'prefix_path works with absolute path to a symlink to work tree having  same beginning as work tree' '\n \tgit init repo &&\n \tln -s repo repolink &&\n-\ttest \"a\" = \"$(cd repo && test-tool path-utils prefix_path prefix \"$(pwd)/../repolink/a\")\"\n+\techo \"a\" >expect &&\n+\trepo_path=\"$(cd repo && pwd)\" &&\n+\ttest-tool -C repo path-utils prefix_path prefix \"$repo_path/../repolink/a\" >actual &&\n+\ttest_cmp expect actual\n '\n \n relative_path /foo/a/b/c/\t/foo/a/b/\tc/\ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex 5a169b68d6a..5a8a48287c1 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -245,9 +245,13 @@ test_expect_success 'git branch -M baz bam should succeed within a worktree in w\n \t(\n \t\tcd bazdir &&\n \t\tgit branch -M baz bam &&\n-\t\ttest $(git rev-parse --abbrev-ref HEAD) = bam\n+\t\techo bam >expect &&\n+\t\tgit rev-parse --abbrev-ref HEAD >actual &&\n+\t\ttest_cmp expect actual\n \t) &&\n-\ttest $(git rev-parse --abbrev-ref HEAD) = bam &&\n+\techo bam >expect &&\n+\tgit rev-parse --abbrev-ref HEAD >actual &&\n+\ttest_cmp expect actual &&\n \trm -r bazdir &&\n \tgit worktree prune\n '\ndiff --git a/t/t5605-clone-local.sh b/t/t5605-clone-local.sh\nindex 38b850c10ef..1d7b1abda1a 100755\n--- a/t/t5605-clone-local.sh\n+++ b/t/t5605-clone-local.sh\n@@ -15,8 +15,12 @@ test_expect_success 'preparing origin repository' '\n \t: >file && git add . && git commit -m1 &&\n \tgit clone --bare . a.git &&\n \tgit clone --bare . x &&\n-\ttest \"$(cd a.git && git config --bool core.bare)\" = true &&\n-\ttest \"$(cd x && git config --bool core.bare)\" = true &&\n+\techo true >expect &&\n+\tgit -C a.git config --bool core.bare >actual &&\n+\ttest_cmp expect actual &&\n+\techo true >expect &&\n+\tgit -C x config --bool core.bare >actual &&\n+\ttest_cmp expect actual &&\n \tgit bundle create b1.bundle --all &&\n \tgit bundle create b2.bundle main &&\n \tmkdir dir &&\n@@ -29,7 +33,9 @@ test_expect_success 'preparing origin repository' '\n test_expect_success 'local clone without .git suffix' '\n \tgit clone -l -s a b &&\n \t(cd b &&\n-\ttest \"$(git config --bool core.bare)\" = false &&\n+\techo false >expect &&\n+\tgit config --bool core.bare >actual &&\n+\ttest_cmp expect actual &&\n \tgit fetch)\n '\n \ndiff --git a/t/t7402-submodule-rebase.sh b/t/t7402-submodule-rebase.sh\nindex ebeca12a711..1927a862839 100755\n--- a/t/t7402-submodule-rebase.sh\n+++ b/t/t7402-submodule-rebase.sh\n@@ -82,11 +82,19 @@ test_expect_success 'stash with a dirty submodule' '\n \tCURRENT=$(cd submodule && git rev-parse HEAD) &&\n \tgit stash &&\n \ttest new != $(cat file) &&\n-\ttest submodule = $(git diff --name-only) &&\n-\ttest $CURRENT = $(cd submodule && git rev-parse HEAD) &&\n+\techo submodule >expect &&\n+\tgit diff --name-only >actual &&\n+\ttest_cmp expect actual &&\n+\n+\techo \"$CURRENT\" >expect &&\n+\tgit -C submodule rev-parse HEAD >actual &&\n+\ttest_cmp expect actual &&\n+\n \tgit stash apply &&\n \ttest new = $(cat file) &&\n-\ttest $CURRENT = $(cd submodule && git rev-parse HEAD)\n+\techo \"$CURRENT\" >expect &&\n+\tgit -C submodule rev-parse HEAD >actual &&\n+\ttest_cmp expect actual\n \n '\n \n-- \n2.39.1.1425.gac85d95d48c\n\n"},{"id":"471627","messageId":"patch-v5-5.6-55abdbef49f-20230206T224200Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v5-0.6-00000000000-20230206T224200Z-avarab@gmail.com","subject":"[PATCH v5 5/6] tests: don't lose \"git\" exit codes in \"! ( git ... | grep )\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2023-02-06T22:44:32Z","receivedAt":"2023-02-06T22:45:02Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change tests that would lose the \"git\" exit code via a negation\npattern to:\n\n- In the case of \"t0055-beyond-symlinks.sh\" compare against the\n  expected output instead.\n\n  We could use the same pattern as in the \"t3700-add.sh\" below, doing\n  so would have the advantage that if we added an earlier test we\n  wouldn't need to adjust the \"expect\" output.\n\n  But as \"t0055-beyond-symlinks.sh\" is a small and focused test (less\n  than 40 lines in total) let's use \"test_cmp\" instead.\n\n- For \"t3700-add.sh\" use \"sed -n\" to print the expected \"bad\" part,\n  and use \"test_must_be_empty\" to assert that it's not there. If we used\n  \"grep\" we'd get a non-zero exit code.\n\n  We could use \"test_expect_code 1 grep\", but this is more consistent\n  with existing patterns in the test suite.\n\n  We can also remove a repeated invocation of \"git ls-files\" for the\n  last test that's being modified in that file, and search the\n  existing \"files\" output instead.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t0055-beyond-symlinks.sh | 14 ++++++++++++--\n t/t3700-add.sh             | 18 +++++++++++++-----\n 2 files changed, 25 insertions(+), 7 deletions(-)\n\ndiff --git a/t/t0055-beyond-symlinks.sh b/t/t0055-beyond-symlinks.sh\nindex 6bada370225..c3eb1158ef9 100755\n--- a/t/t0055-beyond-symlinks.sh\n+++ b/t/t0055-beyond-symlinks.sh\n@@ -15,12 +15,22 @@ test_expect_success SYMLINKS setup '\n \n test_expect_success SYMLINKS 'update-index --add beyond symlinks' '\n \ttest_must_fail git update-index --add c/d &&\n-\t! ( git ls-files | grep c/d )\n+\tcat >expect <<-\\EOF &&\n+\ta\n+\tb/d\n+\tEOF\n+\tgit ls-files >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success SYMLINKS 'add beyond symlinks' '\n \ttest_must_fail git add c/d &&\n-\t! ( git ls-files | grep c/d )\n+\tcat >expect <<-\\EOF &&\n+\ta\n+\tb/d\n+\tEOF\n+\tgit ls-files >actual &&\n+\ttest_cmp expect actual\n '\n \n test_done\ndiff --git a/t/t3700-add.sh b/t/t3700-add.sh\nindex 51afbd7b24a..82dd768944f 100755\n--- a/t/t3700-add.sh\n+++ b/t/t3700-add.sh\n@@ -106,24 +106,32 @@ test_expect_success '.gitignore test setup' '\n \n test_expect_success '.gitignore is honored' '\n \tgit add . &&\n-\t! (git ls-files | grep \"\\\\.ig\")\n+\tgit ls-files >files &&\n+\tsed -n \"/\\\\.ig/p\" <files >actual &&\n+\ttest_must_be_empty actual\n '\n \n test_expect_success 'error out when attempting to add ignored ones without -f' '\n \ttest_must_fail git add a.?? &&\n-\t! (git ls-files | grep \"\\\\.ig\")\n+\tgit ls-files >files &&\n+\tsed -n \"/\\\\.ig/p\" <files >actual &&\n+\ttest_must_be_empty actual\n '\n \n test_expect_success 'error out when attempting to add ignored ones without -f' '\n \ttest_must_fail git add d.?? &&\n-\t! (git ls-files | grep \"\\\\.ig\")\n+\tgit ls-files >files &&\n+\tsed -n \"/\\\\.ig/p\" <files >actual &&\n+\ttest_must_be_empty actual\n '\n \n test_expect_success 'error out when attempting to add ignored ones but add others' '\n \ttouch a.if &&\n \ttest_must_fail git add a.?? &&\n-\t! (git ls-files | grep \"\\\\.ig\") &&\n-\t(git ls-files | grep a.if)\n+\tgit ls-files >files &&\n+\tsed -n \"/\\\\.ig/p\" <files >actual &&\n+\ttest_must_be_empty actual &&\n+\tgrep a.if files\n '\n \n test_expect_success 'add ignored ones with -f' '\n-- \n2.39.1.1425.gac85d95d48c\n\n"},{"id":"471628","messageId":"patch-v5-4.6-e6f56478b65-20230206T224200Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v5-0.6-00000000000-20230206T224200Z-avarab@gmail.com","subject":"[PATCH v5 4/6] tests: don't lose exit status with \"test <op> $(git ...)\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2023-02-06T22:44:31Z","receivedAt":"2023-02-06T22:45:04Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As with the preceding commit, rewrite tests that ran \"git\" inside\ncommand substitution and lost the exit status of \"git\" so that we\nnotice the failing \"git\". This time around we're converting cases that\ndidn't involve a containing sub-shell around the command substitution.\n\nIn the case of \"t0060-path-utils.sh\" and\n\"t2005-checkout-index-symlinks.sh\" convert the relevant code to using\nthe modern style of indentation and newline wrapping while having to\nchange it.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/lib-submodule-update.sh          |   4 +-\n t/t0001-init.sh                    |   9 ++-\n t/t0002-gitfile.sh                 |   4 +-\n t/t0060-path-utils.sh              | 103 +++++++++++++++++++++--------\n t/t0100-previous.sh                |   8 ++-\n t/t1504-ceiling-dirs.sh            |   8 ++-\n t/t2005-checkout-index-symlinks.sh |   8 ++-\n t/t5522-pull-symlink.sh            |   4 +-\n t/t7402-submodule-rebase.sh        |   9 ++-\n t/t7504-commit-msg-hook.sh         |   4 +-\n t/t7810-grep.sh                    |   4 +-\n 11 files changed, 120 insertions(+), 45 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex d7c2b670b4a..dee14992c52 100644\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -185,7 +185,9 @@ test_git_directory_exists () {\n \tif test -f sub1/.git\n \tthen\n \t\t# does core.worktree point at the right place?\n-\t\ttest \"$(git -C .git/modules/$1 config core.worktree)\" = \"../../../$1\"\n+\t\techo \"../../../$1\" >expect &&\n+\t\tgit -C \".git/modules/$1\" config core.worktree >actual &&\n+\t\ttest_cmp expect actual\n \tfi\n }\n \ndiff --git a/t/t0001-init.sh b/t/t0001-init.sh\nindex d479303efa0..30a6edca1d2 100755\n--- a/t/t0001-init.sh\n+++ b/t/t0001-init.sh\n@@ -598,9 +598,14 @@ test_expect_success 'invalid default branch name' '\n test_expect_success 'branch -m with the initial branch' '\n \tgit init rename-initial &&\n \tgit -C rename-initial branch -m renamed &&\n-\ttest renamed = $(git -C rename-initial symbolic-ref --short HEAD) &&\n+\techo renamed >expect &&\n+\tgit -C rename-initial symbolic-ref --short HEAD >actual &&\n+\ttest_cmp expect actual &&\n+\n \tgit -C rename-initial branch -m renamed again &&\n-\ttest again = $(git -C rename-initial symbolic-ref --short HEAD)\n+\techo again >expect &&\n+\tgit -C rename-initial symbolic-ref --short HEAD >actual &&\n+\ttest_cmp expect actual\n '\n \n test_done\ndiff --git a/t/t0002-gitfile.sh b/t/t0002-gitfile.sh\nindex 26eaca095a2..e013d38f485 100755\n--- a/t/t0002-gitfile.sh\n+++ b/t/t0002-gitfile.sh\n@@ -33,7 +33,9 @@ test_expect_success 'bad setup: invalid .git file path' '\n \n test_expect_success 'final setup + check rev-parse --git-dir' '\n \techo \"gitdir: $REAL\" >.git &&\n-\ttest \"$REAL\" = \"$(git rev-parse --git-dir)\"\n+\techo \"$REAL\" >expect &&\n+\tgit rev-parse --git-dir >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'check hash-object' '\ndiff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh\nindex dcc78fb6a7b..0afa3d0d312 100755\n--- a/t/t0060-path-utils.sh\n+++ b/t/t0060-path-utils.sh\n@@ -10,20 +10,27 @@ TEST_PASSES_SANITIZE_LEAK=true\n \n norm_path() {\n \texpected=$(test-tool path-utils print_path \"$2\")\n-\ttest_expect_success $3 \"normalize path: $1 => $2\" \\\n-\t\"test \\\"\\$(test-tool path-utils normalize_path_copy '$1')\\\" = '$expected'\"\n+\ttest_expect_success $3 \"normalize path: $1 => $2\" \"\n+\t\techo '$expected' >expect &&\n+\t\ttest-tool path-utils normalize_path_copy '$1' >actual &&\n+\t\ttest_cmp expect actual\n+\t\"\n }\n \n relative_path() {\n \texpected=$(test-tool path-utils print_path \"$3\")\n-\ttest_expect_success $4 \"relative path: $1 $2 => $3\" \\\n-\t\"test \\\"\\$(test-tool path-utils relative_path '$1' '$2')\\\" = '$expected'\"\n+\ttest_expect_success $4 \"relative path: $1 $2 => $3\" \"\n+\t\techo '$expected' >expect &&\n+\t\ttest-tool path-utils relative_path '$1' '$2' >actual &&\n+\t\ttest_cmp expect actual\n+\t\"\n }\n \n test_submodule_relative_url() {\n \ttest_expect_success \"test_submodule_relative_url: $1 $2 $3 => $4\" \"\n-\t\tactual=\\$(test-tool submodule resolve-relative-url '$1' '$2' '$3') &&\n-\t\ttest \\\"\\$actual\\\" = '$4'\n+\t\techo '$4' >expect &&\n+\t\ttest-tool submodule resolve-relative-url '$1' '$2' '$3' >actual &&\n+\t\ttest_cmp expect actual\n \t\"\n }\n \n@@ -64,9 +71,11 @@ ancestor() {\n \t\texpected=$(($expected-$rootslash+$rootoff))\n \t\t;;\n \tesac\n-\ttest_expect_success $4 \"longest ancestor: $1 $2 => $expected\" \\\n-\t\"actual=\\$(test-tool path-utils longest_ancestor_length '$1' '$2') &&\n-\t test \\\"\\$actual\\\" = '$expected'\"\n+\ttest_expect_success $4 \"longest ancestor: $1 $2 => $expected\" \"\n+\t\techo '$expected' >expect &&\n+\t\ttest-tool path-utils longest_ancestor_length '$1' '$2' >actual &&\n+\t\ttest_cmp expect actual\n+\t\"\n }\n \n # Some absolute path tests should be skipped on Windows due to path mangling\n@@ -166,8 +175,10 @@ ancestor D:/Users/me C:/ -1 MINGW\n ancestor //server/share/my-directory //server/share/ 14 MINGW\n \n test_expect_success 'strip_path_suffix' '\n-\ttest c:/msysgit = $(test-tool path-utils strip_path_suffix \\\n-\t\tc:/msysgit/libexec//git-core libexec/git-core)\n+\techo c:/msysgit >expect &&\n+\ttest-tool path-utils strip_path_suffix \\\n+\t\tc:/msysgit/libexec//git-core libexec/git-core >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'absolute path rejects the empty string' '\n@@ -188,35 +199,61 @@ test_expect_success 'real path rejects the empty string' '\n '\n \n test_expect_success POSIX 'real path works on absolute paths 1' '\n+\techo / >expect &&\n+\ttest-tool path-utils real_path \"/\" >actual &&\n+\ttest_cmp expect actual &&\n+\n \tnopath=\"hopefully-absent-path\" &&\n-\ttest \"/\" = \"$(test-tool path-utils real_path \"/\")\" &&\n-\ttest \"/$nopath\" = \"$(test-tool path-utils real_path \"/$nopath\")\"\n+\techo \"/$nopath\" >expect &&\n+\ttest-tool path-utils real_path \"/$nopath\" >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'real path works on absolute paths 2' '\n-\tnopath=\"hopefully-absent-path\" &&\n \t# Find an existing top-level directory for the remaining tests:\n \td=$(pwd -P | sed -e \"s|^\\([^/]*/[^/]*\\)/.*|\\1|\") &&\n-\ttest \"$d\" = \"$(test-tool path-utils real_path \"$d\")\" &&\n-\ttest \"$d/$nopath\" = \"$(test-tool path-utils real_path \"$d/$nopath\")\"\n+\techo \"$d\" >expect &&\n+\ttest-tool path-utils real_path \"$d\" >actual &&\n+\ttest_cmp expect actual &&\n+\n+\tnopath=\"hopefully-absent-path\" &&\n+\techo \"$d/$nopath\" >expect &&\n+\ttest-tool path-utils real_path \"$d/$nopath\" >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success POSIX 'real path removes extra leading slashes' '\n+\techo \"/\" >expect &&\n+\ttest-tool path-utils real_path \"///\" >actual &&\n+\ttest_cmp expect actual &&\n+\n \tnopath=\"hopefully-absent-path\" &&\n-\ttest \"/\" = \"$(test-tool path-utils real_path \"///\")\" &&\n-\ttest \"/$nopath\" = \"$(test-tool path-utils real_path \"///$nopath\")\" &&\n+\techo \"/$nopath\" >expect &&\n+\ttest-tool path-utils real_path \"///$nopath\" >actual &&\n+\ttest_cmp expect actual &&\n+\n \t# Find an existing top-level directory for the remaining tests:\n \td=$(pwd -P | sed -e \"s|^\\([^/]*/[^/]*\\)/.*|\\1|\") &&\n-\ttest \"$d\" = \"$(test-tool path-utils real_path \"//$d\")\" &&\n-\ttest \"$d/$nopath\" = \"$(test-tool path-utils real_path \"//$d/$nopath\")\"\n+\techo \"$d\" >expect &&\n+\ttest-tool path-utils real_path \"//$d\" >actual &&\n+\ttest_cmp expect actual &&\n+\n+\techo \"$d/$nopath\" >expect &&\n+\ttest-tool path-utils real_path \"//$d/$nopath\" >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'real path removes other extra slashes' '\n-\tnopath=\"hopefully-absent-path\" &&\n \t# Find an existing top-level directory for the remaining tests:\n \td=$(pwd -P | sed -e \"s|^\\([^/]*/[^/]*\\)/.*|\\1|\") &&\n-\ttest \"$d\" = \"$(test-tool path-utils real_path \"$d///\")\" &&\n-\ttest \"$d/$nopath\" = \"$(test-tool path-utils real_path \"$d///$nopath\")\"\n+\techo \"$d\" >expect &&\n+\ttest-tool path-utils real_path \"$d///\" >actual &&\n+\ttest_cmp expect actual &&\n+\n+\tnopath=\"hopefully-absent-path\" &&\n+\techo \"$d/$nopath\" >expect &&\n+\ttest-tool path-utils real_path \"$d///$nopath\" >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success SYMLINKS 'real path works on symlinks' '\n@@ -227,19 +264,29 @@ test_expect_success SYMLINKS 'real path works on symlinks' '\n \tmkdir third &&\n \tdir=\"$(cd .git && pwd -P)\" &&\n \tdir2=third/../second/other/.git &&\n-\ttest \"$dir\" = \"$(test-tool path-utils real_path $dir2)\" &&\n+\techo \"$dir\" >expect &&\n+\ttest-tool path-utils real_path $dir2 >actual &&\n+\ttest_cmp expect actual &&\n \tfile=\"$dir\"/index &&\n-\ttest \"$file\" = \"$(test-tool path-utils real_path $dir2/index)\" &&\n+\techo \"$file\" >expect &&\n+\ttest-tool path-utils real_path $dir2/index >actual &&\n+\ttest_cmp expect actual &&\n \tbasename=blub &&\n-\ttest \"$dir/$basename\" = \"$(cd .git && test-tool path-utils real_path \"$basename\")\" &&\n+\techo \"$dir/$basename\" >expect &&\n+\ttest-tool -C .git path-utils real_path \"$basename\" >actual &&\n+\ttest_cmp expect actual &&\n \tln -s ../first/file .git/syml &&\n \tsym=\"$(cd first && pwd -P)\"/file &&\n-\ttest \"$sym\" = \"$(test-tool path-utils real_path \"$dir2/syml\")\"\n+\techo \"$sym\" >expect &&\n+\ttest-tool path-utils real_path \"$dir2/syml\" >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success SYMLINKS 'prefix_path works with absolute paths to work tree symlinks' '\n \tln -s target symlink &&\n-\ttest \"$(test-tool path-utils prefix_path prefix \"$(pwd)/symlink\")\" = \"symlink\"\n+\techo \"symlink\" >expect &&\n+\ttest-tool path-utils prefix_path prefix \"$(pwd)/symlink\" >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'prefix_path works with only absolute path to work tree' '\ndiff --git a/t/t0100-previous.sh b/t/t0100-previous.sh\nindex a16cc3d2983..70a3223f219 100755\n--- a/t/t0100-previous.sh\n+++ b/t/t0100-previous.sh\n@@ -12,7 +12,9 @@ test_expect_success 'branch -d @{-1}' '\n \ttest_commit A &&\n \tgit checkout -b junk &&\n \tgit checkout - &&\n-\ttest \"$(git symbolic-ref HEAD)\" = refs/heads/main &&\n+\techo refs/heads/main >expect &&\n+\tgit symbolic-ref HEAD >actual &&\n+\ttest_cmp expect actual &&\n \tgit branch -d @{-1} &&\n \ttest_must_fail git rev-parse --verify refs/heads/junk\n '\n@@ -21,7 +23,9 @@ test_expect_success 'branch -d @{-12} when there is not enough switches yet' '\n \tgit reflog expire --expire=now &&\n \tgit checkout -b junk2 &&\n \tgit checkout - &&\n-\ttest \"$(git symbolic-ref HEAD)\" = refs/heads/main &&\n+\techo refs/heads/main >expect &&\n+\tgit symbolic-ref HEAD >actual &&\n+\ttest_cmp expect actual &&\n \ttest_must_fail git branch -d @{-12} &&\n \tgit rev-parse --verify refs/heads/main\n '\ndiff --git a/t/t1504-ceiling-dirs.sh b/t/t1504-ceiling-dirs.sh\nindex 0fafcf9dde3..c1679e31d8a 100755\n--- a/t/t1504-ceiling-dirs.sh\n+++ b/t/t1504-ceiling-dirs.sh\n@@ -6,8 +6,12 @@ TEST_PASSES_SANITIZE_LEAK=true\n . ./test-lib.sh\n \n test_prefix() {\n-\ttest_expect_success \"$1\" \\\n-\t\"test '$2' = \\\"\\$(git rev-parse --show-prefix)\\\"\"\n+\tlocal expect=\"$2\" &&\n+\ttest_expect_success \"$1: git rev-parse --show-prefix is '$2'\" '\n+\t\techo \"$expect\" >expect &&\n+\t\tgit rev-parse --show-prefix >actual &&\n+\t\ttest_cmp expect actual\n+\t'\n }\n \n test_fail() {\ndiff --git a/t/t2005-checkout-index-symlinks.sh b/t/t2005-checkout-index-symlinks.sh\nindex 112682a45a1..67d18cfa104 100755\n--- a/t/t2005-checkout-index-symlinks.sh\n+++ b/t/t2005-checkout-index-symlinks.sh\n@@ -22,8 +22,10 @@ test_expect_success \\\n git checkout-index symlink &&\n test -f symlink'\n \n-test_expect_success \\\n-'the file must be the blob we added during the setup' '\n-test \"$(git hash-object -t blob symlink)\" = $l'\n+test_expect_success 'the file must be the blob we added during the setup' '\n+\techo \"$l\" >expect &&\n+\tgit hash-object -t blob symlink >actual &&\n+\ttest_cmp expect actual\n+'\n \n test_done\ndiff --git a/t/t5522-pull-symlink.sh b/t/t5522-pull-symlink.sh\nindex bcff460d0a2..9fb73a8c3eb 100755\n--- a/t/t5522-pull-symlink.sh\n+++ b/t/t5522-pull-symlink.sh\n@@ -78,7 +78,9 @@ test_expect_success SYMLINKS 'pushing from symlinked subdir' '\n \t\tgit commit -m push ./file &&\n \t\tgit push\n \t) &&\n-\ttest push = $(git show HEAD:subdir/file)\n+\techo push >expect &&\n+\tgit show HEAD:subdir/file >actual &&\n+\ttest_cmp expect actual\n '\n \n test_done\ndiff --git a/t/t7402-submodule-rebase.sh b/t/t7402-submodule-rebase.sh\nindex 1927a862839..c74798e8d24 100755\n--- a/t/t7402-submodule-rebase.sh\n+++ b/t/t7402-submodule-rebase.sh\n@@ -55,12 +55,15 @@ chmod a+x fake-editor.sh\n \n test_expect_success 'interactive rebase with a dirty submodule' '\n \n-\ttest submodule = $(git diff --name-only) &&\n+\techo submodule >expect &&\n+\tgit diff --name-only >actual &&\n+\ttest_cmp expect actual &&\n \tHEAD=$(git rev-parse HEAD) &&\n \tGIT_EDITOR=\"\\\"$(pwd)/fake-editor.sh\\\"\" EDITOR_TEXT=\"pick $HEAD\" \\\n \t\tgit rebase -i HEAD^ &&\n-\ttest submodule = $(git diff --name-only)\n-\n+\techo submodule >expect &&\n+\tgit diff --name-only >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'rebase with dirty file and submodule fails' '\ndiff --git a/t/t7504-commit-msg-hook.sh b/t/t7504-commit-msg-hook.sh\nindex 07ca46fb0d5..d1255228d5f 100755\n--- a/t/t7504-commit-msg-hook.sh\n+++ b/t/t7504-commit-msg-hook.sh\n@@ -102,7 +102,9 @@ test_expect_success 'setup: commit-msg hook that always fails' '\n '\n \n commit_msg_is () {\n-\ttest \"$(git log --pretty=format:%s%b -1)\" = \"$1\"\n+\tprintf \"%s\" \"$1\" >expect &&\n+\tgit log --pretty=format:%s%b -1 >actual &&\n+\ttest_cmp expect actual\n }\n \n test_expect_success 'with failing hook' '\ndiff --git a/t/t7810-grep.sh b/t/t7810-grep.sh\nindex 8eded6ab274..39d6d713ecb 100755\n--- a/t/t7810-grep.sh\n+++ b/t/t7810-grep.sh\n@@ -1001,7 +1001,9 @@ test_expect_success 'log --committer does not search in timestamp' '\n test_expect_success 'grep with CE_VALID file' '\n \tgit update-index --assume-unchanged t/t &&\n \trm t/t &&\n-\ttest \"$(git grep test)\" = \"t/t:test\" &&\n+\techo \"t/t:test\" >expect &&\n+\tgit grep test >actual &&\n+\ttest_cmp expect actual &&\n \tgit update-index --no-assume-unchanged t/t &&\n \tgit checkout t/t\n '\n-- \n2.39.1.1425.gac85d95d48c\n\n"},{"id":"471629","messageId":"patch-v5-6.6-e7f10c0641a-20230206T224200Z-avarab@gmail.com","threadId":"58200","inReplyTo":"cover-v5-0.6-00000000000-20230206T224200Z-avarab@gmail.com","subject":"[PATCH v5 6/6] tests: don't lose misc \"git\" exit codes","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2023-02-06T22:44:33Z","receivedAt":"2023-02-06T22:45:06Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Fix a few miscellaneous cases where:\n\n- We lost the \"git\" exit code via \"git ... | grep\"\n- Likewise by having a $(git) argument to git itself\n- Used \"test -z\" to check that a command emitted no output, we can use\n  \"test_must_be_empty\" and &&-chaining instead.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t1401-symbolic-ref.sh    | 3 ++-\n t/t3701-add-interactive.sh | 8 +++++---\n t/t7516-commit-races.sh    | 3 ++-\n 3 files changed, 9 insertions(+), 5 deletions(-)\n\ndiff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh\nindex d708acdb819..5e36899d207 100755\n--- a/t/t1401-symbolic-ref.sh\n+++ b/t/t1401-symbolic-ref.sh\n@@ -33,7 +33,8 @@ test_expect_success 'symbolic-ref refuses non-ref for HEAD' '\n reset_to_sane\n \n test_expect_success 'symbolic-ref refuses bare sha1' '\n-\ttest_must_fail git symbolic-ref HEAD $(git rev-parse HEAD)\n+\trev=$(git rev-parse HEAD) &&\n+\ttest_must_fail git symbolic-ref HEAD \"$rev\"\n '\n \n reset_to_sane\ndiff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh\nindex 5841f280fb2..f1fe5d60677 100755\n--- a/t/t3701-add-interactive.sh\n+++ b/t/t3701-add-interactive.sh\n@@ -296,9 +296,11 @@ test_expect_success FILEMODE 'stage mode and hunk' '\n \techo content >>file &&\n \tchmod +x file &&\n \tprintf \"y\\\\ny\\\\n\" | git add -p &&\n-\tgit diff --cached file | grep \"new mode\" &&\n-\tgit diff --cached file | grep \"+content\" &&\n-\ttest -z \"$(git diff file)\"\n+\tgit diff --cached file >out &&\n+\tgrep \"new mode\" out &&\n+\tgrep \"+content\" out &&\n+\tgit diff file >out &&\n+\ttest_must_be_empty out\n '\n \n # end of tests disabled when filemode is not usable\ndiff --git a/t/t7516-commit-races.sh b/t/t7516-commit-races.sh\nindex f2ce14e9071..2d38a16480e 100755\n--- a/t/t7516-commit-races.sh\n+++ b/t/t7516-commit-races.sh\n@@ -10,7 +10,8 @@ test_expect_success 'race to create orphan commit' '\n \ttest_must_fail env EDITOR=./hare-editor git commit --allow-empty -m tortoise -e &&\n \tgit show -s --pretty=format:%s >subject &&\n \tgrep hare subject &&\n-\ttest -z \"$(git show -s --pretty=format:%P)\"\n+\tgit show -s --pretty=format:%P >out &&\n+\ttest_must_be_empty out\n '\n \n test_expect_success 'race to create non-orphan commit' '\n-- \n2.39.1.1425.gac85d95d48c\n\n"},{"id":"471662","messageId":"xmqq7cwu2wta.fsf@gitster.g","threadId":"58200","inReplyTo":"cover-v5-0.6-00000000000-20230206T224200Z-avarab@gmail.com","subject":"Re: [PATCH v5 0/6] tests: fix ignored & hidden exit codes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-02-06T23:33:53Z","receivedAt":"2023-02-06T23:34:16Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Ævar Arnfjörð Bjarmason (6):\n>   auto-crlf tests: don't lose exit code in loops and outside tests\n>   t/lib-patch-mode.sh: fix ignored exit codes\n>   tests: don't lose exit status with \"(cd ...; test <op> $(git ...))\"\n>   tests: don't lose exit status with \"test <op> $(git ...)\"\n>   tests: don't lose \"git\" exit codes in \"! ( git ... | grep )\"\n>   tests: don't lose misc \"git\" exit codes\n\nThe changes relative to the previous round look OK.  Will queue.\n\nThanks.\n"}]}