{"thread":{"id":"64827","subject":"[PATCH v1] t2203: avoid masking exit codes in git status","startedAt":"2026-01-17T17:59:09Z","lastAt":"2026-01-18T04:37:04Z","messageCount":4,"participants":["Tian Yuchen","Junio C Hamano","Yushin Tian"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"534122","messageId":"20260117175847.334666-1-a3205153416@gmail.com","threadId":"64827","inReplyTo":null,"subject":"[PATCH v1] t2203: avoid masking exit codes in git status","fromName":"Tian Yuchen","fromEmail":"a3205153416@gmail.com","sentAt":"2026-01-17T17:58:47Z","receivedAt":"2026-01-17T17:59:09Z","isPatch":true,"sender":{"key":"cat@malon.dev","avatar":"https://avatars.githubusercontent.com/u/232002048?v=4"},"body":"The test script t2203-add-intent.sh uses the pattern `git status | grep\n-v` in multiple places. This pipeline masks the exit code of `git status`.\nIf `git status` crashes, `grep -v` will successfully filter nothing\nand return 0, causing the test to pass incorrectly.\n\nUpdate the tests to use an intermediate file, ensuring that the exit\ncodecof `git status` is checked and any crash is caught immediately.\n\nIn one instance, we also need to update the grep pattern to ignore the\ntemporary file it self, to avoid causing a regression in the test output\ncomparison.\n\nSigned-off-by: Tian Yuchen <a3205153416@gmail.com>\n---\n t/t2203-add-intent.sh | 24 ++++++++++++++++--------\n 1 file changed, 16 insertions(+), 8 deletions(-)\n\ndiff --git a/t/t2203-add-intent.sh b/t/t2203-add-intent.sh\nindex 192ad14b5f..ac8bafa680 100755\n--- a/t/t2203-add-intent.sh\n+++ b/t/t2203-add-intent.sh\n@@ -16,7 +16,8 @@ test_expect_success 'intent to add' '\n '\n \n test_expect_success 'git status' '\n-\tgit status --porcelain | grep -v actual >actual &&\n+\tgit status --porcelain >tmp &&\n+\tgrep -v -e actual -e tmp tmp >actual &&\n \tcat >expect <<-\\EOF &&\n \tDA 1.t\n \tA  elif\n@@ -26,7 +27,8 @@ test_expect_success 'git status' '\n '\n \n test_expect_success 'git status with porcelain v2' '\n-\tgit status --porcelain=v2 | grep -v \"^?\" >actual &&\n+\tgit status --porcelain=v2 >tmp &&\n+\tgrep -v \"^?\" tmp >actual &&\n \tnam1=$(echo 1 | git hash-object --stdin) &&\n \tnam2=$(git hash-object elif) &&\n \tcat >expect <<-EOF &&\n@@ -171,17 +173,20 @@ test_expect_success 'rename detection finds the right names' '\n \t\tmv first third &&\n \t\tgit add -N third &&\n \n-\t\tgit status | grep -v \"^?\" >actual.1 &&\n+\t\tgit status >tmp &&\n+\t\tgrep -v \"^?\" tmp >actual.1 &&\n \t\ttest_grep \"renamed: *first -> third\" actual.1 &&\n \n-\t\tgit status --porcelain | grep -v \"^?\" >actual.2 &&\n+\t\tgit status --porcelain >tmp &&\n+\t\tgrep -v \"^?\" tmp >actual.2 &&\n \t\tcat >expected.2 <<-\\EOF &&\n \t\t R first -> third\n \t\tEOF\n \t\ttest_cmp expected.2 actual.2 &&\n \n \t\thash=$(git hash-object third) &&\n-\t\tgit status --porcelain=v2 | grep -v \"^?\" >actual.3 &&\n+\t\tgit status --porcelain=v2 >tmp &&\n+\t\tgrep -v \"^?\" tmp >actual.3 &&\n \t\tcat >expected.3 <<-EOF &&\n \t\t2 .R N... 100644 100644 100644 $hash $hash R100 third\tfirst\n \t\tEOF\n@@ -211,11 +216,13 @@ test_expect_success 'double rename detection in status' '\n \t\tmv second third &&\n \t\tgit add -N third &&\n \n-\t\tgit status | grep -v \"^?\" >actual.1 &&\n+\t\tgit status >tmp &&\n+\t\tgrep -v \"^?\" tmp >actual.1 &&\n \t\ttest_grep \"renamed: *first -> second\" actual.1 &&\n \t\ttest_grep \"renamed: *second -> third\" actual.1 &&\n \n-\t\tgit status --porcelain | grep -v \"^?\" >actual.2 &&\n+\t\tgit status --porcelain >tmp &&\n+\t\tgrep -v \"^?\" tmp >actual.2 &&\n \t\tcat >expected.2 <<-\\EOF &&\n \t\tR  first -> second\n \t\t R second -> third\n@@ -223,7 +230,8 @@ test_expect_success 'double rename detection in status' '\n \t\ttest_cmp expected.2 actual.2 &&\n \n \t\thash=$(git hash-object third) &&\n-\t\tgit status --porcelain=v2 | grep -v \"^?\" >actual.3 &&\n+\t\tgit status --porcelain=v2 >tmp &&\n+\t\tgrep -v \"^?\" tmp >actual.3 &&\n \t\tcat >expected.3 <<-EOF &&\n \t\t2 R. N... 100644 100644 100644 $hash $hash R100 second\tfirst\n \t\t2 .R N... 100644 100644 100644 $hash $hash R100 third\tsecond\n\nbase-commit: 7264e61d87e58b9d0f5e6424c47c11e9657dfb75\n-- \n2.43.0\n\n"},{"id":"534123","messageId":"xmqqy0lw5cmq.fsf@gitster.g","threadId":"64827","inReplyTo":"20260117175847.334666-1-a3205153416@gmail.com","subject":"Re: [PATCH v1] t2203: avoid masking exit codes in git status","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-01-17T18:15:41Z","receivedAt":"2026-01-17T18:15:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Tian Yuchen <a3205153416@gmail.com> writes:\n\n>  test_expect_success 'git status' '\n> -\tgit status --porcelain | grep -v actual >actual &&\n> +\tgit status --porcelain >tmp &&\n> +\tgrep -v -e actual -e tmp tmp >actual &&\n\nLooking at other parts of this patch makes me wonder if we can get\naway by filtering lines that match \"^?\" out, instead of explicitly\nnaming 'actual' and 'tmp'.  It seems that the entire t2203 file does\nnot care about untraacked files at all (in other words, there is no\n\"expect\" file that expects a line with '^?' in it), so rewriting the\nabove (and everything that this patch touches) to use something like\n\n\tgit status --porcelain -uno >actual\n\nmakes the intent clear (i.e., we do not care about untracked files)\nand simpler (i.e., we do not need \"grep -v\" to filter), wouldn't it?\n\n>  \tcat >expect <<-\\EOF &&\n>  \tDA 1.t\n>  \tA  elif\n> @@ -26,7 +27,8 @@ test_expect_success 'git status' '\n>  '\n>  \n>  test_expect_success 'git status with porcelain v2' '\n> -\tgit status --porcelain=v2 | grep -v \"^?\" >actual &&\n> +\tgit status --porcelain=v2 >tmp &&\n> +\tgrep -v \"^?\" tmp >actual &&\n>  \tnam1=$(echo 1 | git hash-object --stdin) &&\n>  \tnam2=$(git hash-object elif) &&\n>  \tcat >expect <<-EOF &&\n> @@ -171,17 +173,20 @@ test_expect_success 'rename detection finds the right names' '\n>  \t\tmv first third &&\n>  \t\tgit add -N third &&\n>  \n> -\t\tgit status | grep -v \"^?\" >actual.1 &&\n> +\t\tgit status >tmp &&\n> +\t\tgrep -v \"^?\" tmp >actual.1 &&\n>  \t\ttest_grep \"renamed: *first -> third\" actual.1 &&\n>  \n> -\t\tgit status --porcelain | grep -v \"^?\" >actual.2 &&\n> +\t\tgit status --porcelain >tmp &&\n> +\t\tgrep -v \"^?\" tmp >actual.2 &&\n>  \t\tcat >expected.2 <<-\\EOF &&\n>  \t\t R first -> third\n>  \t\tEOF\n>  \t\ttest_cmp expected.2 actual.2 &&\n>  \n>  \t\thash=$(git hash-object third) &&\n> -\t\tgit status --porcelain=v2 | grep -v \"^?\" >actual.3 &&\n> +\t\tgit status --porcelain=v2 >tmp &&\n> +\t\tgrep -v \"^?\" tmp >actual.3 &&\n>  \t\tcat >expected.3 <<-EOF &&\n>  \t\t2 .R N... 100644 100644 100644 $hash $hash R100 third\tfirst\n>  \t\tEOF\n> @@ -211,11 +216,13 @@ test_expect_success 'double rename detection in status' '\n>  \t\tmv second third &&\n>  \t\tgit add -N third &&\n>  \n> -\t\tgit status | grep -v \"^?\" >actual.1 &&\n> +\t\tgit status >tmp &&\n> +\t\tgrep -v \"^?\" tmp >actual.1 &&\n>  \t\ttest_grep \"renamed: *first -> second\" actual.1 &&\n>  \t\ttest_grep \"renamed: *second -> third\" actual.1 &&\n>  \n> -\t\tgit status --porcelain | grep -v \"^?\" >actual.2 &&\n> +\t\tgit status --porcelain >tmp &&\n> +\t\tgrep -v \"^?\" tmp >actual.2 &&\n>  \t\tcat >expected.2 <<-\\EOF &&\n>  \t\tR  first -> second\n>  \t\t R second -> third\n> @@ -223,7 +230,8 @@ test_expect_success 'double rename detection in status' '\n>  \t\ttest_cmp expected.2 actual.2 &&\n>  \n>  \t\thash=$(git hash-object third) &&\n> -\t\tgit status --porcelain=v2 | grep -v \"^?\" >actual.3 &&\n> +\t\tgit status --porcelain=v2 >tmp &&\n> +\t\tgrep -v \"^?\" tmp >actual.3 &&\n>  \t\tcat >expected.3 <<-EOF &&\n>  \t\t2 R. N... 100644 100644 100644 $hash $hash R100 second\tfirst\n>  \t\t2 .R N... 100644 100644 100644 $hash $hash R100 third\tsecond\n>\n> base-commit: 7264e61d87e58b9d0f5e6424c47c11e9657dfb75\n"},{"id":"534135","messageId":"CA+rU_o4TYi-9dTgReP6=+15SZ--gyZg7OK2rn=Rqji5sQ5P-bg@mail.gmail.com","threadId":"64827","inReplyTo":"xmqqy0lw5cmq.fsf@gitster.g","subject":"Re: [PATCH v1] t2203: avoid masking exit codes in git status","fromName":"Yushin Tian","fromEmail":"a3205153416@gmail.com","sentAt":"2026-01-18T04:16:20Z","receivedAt":"2026-01-18T04:16:35Z","isPatch":true,"sender":{"key":"cat@malon.dev","avatar":"https://avatars.githubusercontent.com/u/232002048?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n>Looking at other parts of this patch makes me wonder if we can get\n>away by filtering lines that match \"^?\" out, instead of explicitly\n>naming 'actual' and 'tmp'.  It seems that the entire t2203 file does\n>not care about untraacked files at all (in other words, there is no\n>\"expect\" file that expects a line with '^?' in it), so rewriting the\n>above (and everything that this patch touches) to use something like\n>\n>       git status --porcelain -uno >actual\n>\n>makes the intent clear (i.e., we do not care about untracked files)\n>and simpler (i.e., we do not need \"grep -v\" to filter), wouldn't it?\n\nYou are right. Using `-uno` is much simpler and semantically closer to\nwhat the tests are checking (changes in the index, not untracked files).\nIt also naturally avoids the exit code masking issue since the pipe is removed.\n\nI have checked t2203 and confirmed that no test cases expect untracked\nfiles in their output.\n\nI will send a v2 patch shortly with this change, and I'll also add the [gsoc]\nprefix which I missed in the first iteration.\n\nThanks for you suggestion!\n\n>\n> Tian Yuchen <a3205153416@gmail.com> writes:\n>\n> >  test_expect_success 'git status' '\n> > -     git status --porcelain | grep -v actual >actual &&\n> > +     git status --porcelain >tmp &&\n> > +     grep -v -e actual -e tmp tmp >actual &&\n>\n> Looking at other parts of this patch makes me wonder if we can get\n> away by filtering lines that match \"^?\" out, instead of explicitly\n> naming 'actual' and 'tmp'.  It seems that the entire t2203 file does\n> not care about untraacked files at all (in other words, there is no\n> \"expect\" file that expects a line with '^?' in it), so rewriting the\n> above (and everything that this patch touches) to use something like\n>\n>         git status --porcelain -uno >actual\n>\n> makes the intent clear (i.e., we do not care about untracked files)\n> and simpler (i.e., we do not need \"grep -v\" to filter), wouldn't it?\n>\n> >       cat >expect <<-\\EOF &&\n> >       DA 1.t\n> >       A  elif\n> > @@ -26,7 +27,8 @@ test_expect_success 'git status' '\n> >  '\n> >\n> >  test_expect_success 'git status with porcelain v2' '\n> > -     git status --porcelain=v2 | grep -v \"^?\" >actual &&\n> > +     git status --porcelain=v2 >tmp &&\n> > +     grep -v \"^?\" tmp >actual &&\n> >       nam1=$(echo 1 | git hash-object --stdin) &&\n> >       nam2=$(git hash-object elif) &&\n> >       cat >expect <<-EOF &&\n> > @@ -171,17 +173,20 @@ test_expect_success 'rename detection finds the right names' '\n> >               mv first third &&\n> >               git add -N third &&\n> >\n> > -             git status | grep -v \"^?\" >actual.1 &&\n> > +             git status >tmp &&\n> > +             grep -v \"^?\" tmp >actual.1 &&\n> >               test_grep \"renamed: *first -> third\" actual.1 &&\n> >\n> > -             git status --porcelain | grep -v \"^?\" >actual.2 &&\n> > +             git status --porcelain >tmp &&\n> > +             grep -v \"^?\" tmp >actual.2 &&\n> >               cat >expected.2 <<-\\EOF &&\n> >                R first -> third\n> >               EOF\n> >               test_cmp expected.2 actual.2 &&\n> >\n> >               hash=$(git hash-object third) &&\n> > -             git status --porcelain=v2 | grep -v \"^?\" >actual.3 &&\n> > +             git status --porcelain=v2 >tmp &&\n> > +             grep -v \"^?\" tmp >actual.3 &&\n> >               cat >expected.3 <<-EOF &&\n> >               2 .R N... 100644 100644 100644 $hash $hash R100 third   first\n> >               EOF\n> > @@ -211,11 +216,13 @@ test_expect_success 'double rename detection in status' '\n> >               mv second third &&\n> >               git add -N third &&\n> >\n> > -             git status | grep -v \"^?\" >actual.1 &&\n> > +             git status >tmp &&\n> > +             grep -v \"^?\" tmp >actual.1 &&\n> >               test_grep \"renamed: *first -> second\" actual.1 &&\n> >               test_grep \"renamed: *second -> third\" actual.1 &&\n> >\n> > -             git status --porcelain | grep -v \"^?\" >actual.2 &&\n> > +             git status --porcelain >tmp &&\n> > +             grep -v \"^?\" tmp >actual.2 &&\n> >               cat >expected.2 <<-\\EOF &&\n> >               R  first -> second\n> >                R second -> third\n> > @@ -223,7 +230,8 @@ test_expect_success 'double rename detection in status' '\n> >               test_cmp expected.2 actual.2 &&\n> >\n> >               hash=$(git hash-object third) &&\n> > -             git status --porcelain=v2 | grep -v \"^?\" >actual.3 &&\n> > +             git status --porcelain=v2 >tmp &&\n> > +             grep -v \"^?\" tmp >actual.3 &&\n> >               cat >expected.3 <<-EOF &&\n> >               2 R. N... 100644 100644 100644 $hash $hash R100 second  first\n> >               2 .R N... 100644 100644 100644 $hash $hash R100 third   second\n> >\n> > base-commit: 7264e61d87e58b9d0f5e6424c47c11e9657dfb75\n"},{"id":"534136","messageId":"20260118043537.338769-1-a3205153416@gmail.com","threadId":"64827","inReplyTo":"20260117175847.334666-1-a3205153416@gmail.com","subject":"[PATCH GSoC v2] t2203: avoid masking exit codes in git status","fromName":"Tian Yuchen","fromEmail":"a3205153416@gmail.com","sentAt":"2026-01-18T04:35:37Z","receivedAt":"2026-01-18T04:37:04Z","isPatch":true,"sender":{"key":"cat@malon.dev","avatar":"https://avatars.githubusercontent.com/u/232002048?v=4"},"body":"The test script t2203-add-intent.sh uses the pattern\n`git status | grep -v` in multiple places. This pipeline\nmasks the exit code of `git status`.\n\nUpdate the tests to use `git status -uno >actual`.\nThis excludes untracked files from the output entirely,\nremoving the need for filtering with `grep` and allowing us\nto drop the pipeline, ensuring any crash in `git status`\nis caught immediately.\n\nSigned-off-by: Tian Yuchen <a3205153416@gmail.com>\n---\n t/t2203-add-intent.sh | 16 ++++++++--------\n 1 file changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/t/t2203-add-intent.sh b/t/t2203-add-intent.sh\nindex 192ad14b5f..5bdd12c91f 100755\n--- a/t/t2203-add-intent.sh\n+++ b/t/t2203-add-intent.sh\n@@ -16,7 +16,7 @@ test_expect_success 'intent to add' '\n '\n \n test_expect_success 'git status' '\n-\tgit status --porcelain | grep -v actual >actual &&\n+\tgit status --porcelain -uno >actual &&\n \tcat >expect <<-\\EOF &&\n \tDA 1.t\n \tA  elif\n@@ -26,7 +26,7 @@ test_expect_success 'git status' '\n '\n \n test_expect_success 'git status with porcelain v2' '\n-\tgit status --porcelain=v2 | grep -v \"^?\" >actual &&\n+\tgit status --porcelain=v2 -uno >actual &&\n \tnam1=$(echo 1 | git hash-object --stdin) &&\n \tnam2=$(git hash-object elif) &&\n \tcat >expect <<-EOF &&\n@@ -171,17 +171,17 @@ test_expect_success 'rename detection finds the right names' '\n \t\tmv first third &&\n \t\tgit add -N third &&\n \n-\t\tgit status | grep -v \"^?\" >actual.1 &&\n+\t\tgit status -uno >actual.1 &&\n \t\ttest_grep \"renamed: *first -> third\" actual.1 &&\n \n-\t\tgit status --porcelain | grep -v \"^?\" >actual.2 &&\n+\t\tgit status --porcelain -uno >actual.2 &&\n \t\tcat >expected.2 <<-\\EOF &&\n \t\t R first -> third\n \t\tEOF\n \t\ttest_cmp expected.2 actual.2 &&\n \n \t\thash=$(git hash-object third) &&\n-\t\tgit status --porcelain=v2 | grep -v \"^?\" >actual.3 &&\n+\t\tgit status --porcelain=v2 -uno >actual.3 &&\n \t\tcat >expected.3 <<-EOF &&\n \t\t2 .R N... 100644 100644 100644 $hash $hash R100 third\tfirst\n \t\tEOF\n@@ -211,11 +211,11 @@ test_expect_success 'double rename detection in status' '\n \t\tmv second third &&\n \t\tgit add -N third &&\n \n-\t\tgit status | grep -v \"^?\" >actual.1 &&\n+\t\tgit status -uno >actual.1 &&\n \t\ttest_grep \"renamed: *first -> second\" actual.1 &&\n \t\ttest_grep \"renamed: *second -> third\" actual.1 &&\n \n-\t\tgit status --porcelain | grep -v \"^?\" >actual.2 &&\n+\t\tgit status --porcelain -uno >actual.2 &&\n \t\tcat >expected.2 <<-\\EOF &&\n \t\tR  first -> second\n \t\t R second -> third\n@@ -223,7 +223,7 @@ test_expect_success 'double rename detection in status' '\n \t\ttest_cmp expected.2 actual.2 &&\n \n \t\thash=$(git hash-object third) &&\n-\t\tgit status --porcelain=v2 | grep -v \"^?\" >actual.3 &&\n+\t\tgit status --porcelain=v2 -uno >actual.3 &&\n \t\tcat >expected.3 <<-EOF &&\n \t\t2 R. N... 100644 100644 100644 $hash $hash R100 second\tfirst\n \t\t2 .R N... 100644 100644 100644 $hash $hash R100 third\tsecond\n\nbase-commit: 7264e61d87e58b9d0f5e6424c47c11e9657dfb75\n-- \n2.43.0\n\n"}]}