Skip to contentSkip to conversation

t9832,t2200: avoid using pipes in git related commands

PATCH Superseded Amanda Shafack via GitGitGadget 4 participants 14 messages Oct 17, 2020 – Oct 18, 2020

lore
Share & tools
lore
#0 lore raw

cover t9832,t2200: avoid using pipes in git related commands

When the upstream of a pipe throws an error, the downstream still executes normally. This happens because the exit code of the upstream in a pipe is ignored. This behavior can make debugging very hard in case a test fails. Also, pipes are prone to deadlocks. If the upstream gets full, the commands downstream will never start.

Write out the output of the git command to a file, so as to test the exit codes of both commands.

Commit c6f44e1da5 (t9813: avoid using pipes, 2017-01-04) noticed that the exit code of upstream in the pipe is ignored, thus using pipes should be avoided.

Amanda Shafack (1):
t2200: modify code syntax

Amanda Shafack (1):
t9832,t2200: avoid using pipes in git commands

 t/t2200-add-update.sh | 3 ++-
 t/t9832-unshelve.sh   | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

base-commit: a5fa49ff0a8f3252c6bff49f92b85e7683868f8a
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-885%2Flkmandy%2Favoid-pipes-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-885/lkmandy/avoid-pipes-v1
Pull-Request: https://github.com/git/git/pull/885

Signature · 1 line
gitgitgadget
#1 lore raw

PATCH 1/2 t9832,t2200: avoid using pipes in git commands

From: Amanda Shafack <[email protected]>

When the upstream of a pipe throws an error, the downstream still executes normally. This happens because the exit code of the upstream in a pipe is ignored. This behavior can make debugging very hard incase a test fails. Also, pipes are prone to deadlocks. If the upstream gets full, the commands downstream will never start.

Write out the output of the git command to a file, so as to test the exit codes of both commands.

Commit c6f44e1da5 (t9813: avoid using pipes, 2017-01-04) noticed that the exit code of upstream in the pipe is ignored, thus using pipes should be avoided.

---
 t/t2200-add-update.sh | 5 ++++-
 t/t9832-unshelve.sh   | 3 ++-
 2 files changed, 6 insertions(+), 2 deletions(-)
t/t2200-add-update.sh +4 -1
index f764b7e3f5..2d850bb372 100755
@@ -179,7 +179,10 @@ test_expect_success 'add -u resolves unmerged paths' '
 
 test_expect_success '"add -u non-existent" should fail' '
 	test_must_fail git add -u non-existent &&
-	! (git ls-files | grep "non-existent")
+	! (
+		git ls-files >actual &&
+		grep "non-existent" actual
+	)
 '
 
 test_done
t/t9832-unshelve.sh +2 -1
index 7194fb2855..6b3cb0414a 100755
@@ -68,7 +68,8 @@ EOF
 		cd "$git" &&
 		change=$(last_shelved_change) &&
 		git p4 unshelve $change &&
-		git show refs/remotes/p4-unshelved/$change | grep -q "Further description" &&
+		git show refs/remotes/p4-unshelved/$change >actual &&
+		grep -q "Further description" actual &&
 		git cherry-pick refs/remotes/p4-unshelved/$change &&
 		test_path_is_file file2 &&
 		test_cmp file1 "$cli"/file1 &&
Signature · 1 line
gitgitgadget
#2 lore raw

Re: [PATCH 1/2] t9832,t2200: avoid using pipes in git commands

Quoted 4 lines · Amanda Shafack via GitGitGadget

When the upstream of a pipe throws an error, the downstream still executes normally. This happens because the exit code of the upstream in a pipe is ignored. This behavior can make debugging very hard incase a test fails.

To be more precise, we're not worried about difficulty of debugging when a Git command is upstream in a pipe. What we are more concerned with is that an unexpected failure of the Git command will go unnoticed (unless it also happens to produce wrong output which is later caught somewhere downstream). By avoiding placing Git upstream in a pipe, we can actively catch a failure of the Git command. The commit message should focus on that reason instead.

Quoted 2 lines

Also, pipes are prone to deadlocks. If the
upstream gets full, the commands downstream will never start.

I don't think this is ever an issue in Git tests, so talking about it here probably only muddies the waters, thus makes the commit message less precise and more hand-wavy. Dropping this sentence is recommended.

Quoted 3 lines

Commit c6f44e1da5 (t9813: avoid using pipes, 2017-01-04) noticed that the exit code of upstream in the pipe is ignored, thus using pipes should be avoided.

There are a lot of commits in the project history which perform this sort of transformation, so it's not clear to the reader why this particular commit is called out as being important. If it's not, then I'd recommend dropping this sentence, as well.

t/t2200-add-update.sh test_expect_success 'add -u resolves unmerged paths' ' · line 186

Quoted 9 lines
t/t2200-add-update.sh +4 -1
 test_expect_success '"add -u non-existent" should fail' '
        test_must_fail git add -u non-existent &&
-       ! (git ls-files | grep "non-existent")
+       ! (
+               git ls-files >actual &&
+               grep "non-existent" actual
+       )
 '

This transformation appears to be incorrect. See my review of patch [2/2] for details.

t/t9832-unshelve.sh EOF · line 69

Quoted 5 lines
t/t9832-unshelve.sh +2 -1
@@ -68,7 +68,8 @@ EOF
-               git show refs/remotes/p4-unshelved/$change | grep -q "Further description" &&
+               git show refs/remotes/p4-unshelved/$change >actual &&
+               grep -q "Further description" actual &&

This transformation looks fine.

#3 lore raw

Re: [PATCH 1/2] t9832,t2200: avoid using pipes in git commands

Thanks for your feedback, I now have a better understanding. I have made the changes you requested.

Quoted 53 lines · Eric Sunshine
Quoted 4 lines · Amanda Shafack via GitGitGadget

When the upstream of a pipe throws an error, the downstream still executes normally. This happens because the exit code of the upstream in a pipe is ignored. This behavior can make debugging very hard incase a test fails.

To be more precise, we're not worried about difficulty of debugging when a Git command is upstream in a pipe. What we are more concerned with is that an unexpected failure of the Git command will go unnoticed (unless it also happens to produce wrong output which is later caught somewhere downstream). By avoiding placing Git upstream in a pipe, we can actively catch a failure of the Git command. The commit message should focus on that reason instead.

Quoted 2 lines

Also, pipes are prone to deadlocks. If the
upstream gets full, the commands downstream will never start.

I don't think this is ever an issue in Git tests, so talking about it here probably only muddies the waters, thus makes the commit message less precise and more hand-wavy. Dropping this sentence is recommended.

Quoted 3 lines

Commit c6f44e1da5 (t9813: avoid using pipes, 2017-01-04) noticed that the exit code of upstream in the pipe is ignored, thus using pipes should be avoided.

There are a lot of commits in the project history which perform this sort of transformation, so it's not clear to the reader why this particular commit is called out as being important. If it's not, then I'd recommend dropping this sentence, as well.

t/t2200-add-update.sh test_expect_success 'add -u resolves unmerged paths' ' · line 186

Quoted 9 lines
t/t2200-add-update.sh +4 -1
 test_expect_success '"add -u non-existent" should fail' '
        test_must_fail git add -u non-existent &&
-       ! (git ls-files | grep "non-existent")
+       ! (
+               git ls-files >actual &&
+               grep "non-existent" actual
+       )
 '

This transformation appears to be incorrect. See my review of patch [2/2] for details.

t/t9832-unshelve.sh EOF · line 69

Quoted 5 lines
t/t9832-unshelve.sh +2 -1
@@ -68,7 +68,8 @@ EOF
-               git show refs/remotes/p4-unshelved/$change | grep -q "Further description" &&
+               git show refs/remotes/p4-unshelved/$change >actual &&
+               grep -q "Further description" actual &&

This transformation looks fine.

Signature · 3 lines
Cheers!

Amanda  Shafack
#4 lore raw

PATCH 2/2 t2200: modify code syntax

In reply to Amanda Shafack via GitGitGadget

From: Amanda Shafack <[email protected]>

Using the logical not operator on both the git and grep command is redundant, since the main check is done at the level of the grep command.

Apply the logical not operator only to the grep command.

---
 t/t2200-add-update.sh | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)
t/t2200-add-update.sh +2 -4
index 2d850bb372..7cb7a70382 100755
@@ -179,10 +179,8 @@ test_expect_success 'add -u resolves unmerged paths' '
 
 test_expect_success '"add -u non-existent" should fail' '
 	test_must_fail git add -u non-existent &&
-	! (
-		git ls-files >actual &&
-		grep "non-existent" actual
-	)
+	git ls-files >actual &&
+	! grep "non-existent" actual
 '
 
 test_done
Signature · 1 line
gitgitgadget
#5 lore raw

Re: [PATCH 2/2] t2200: modify code syntax

Quoted 8 lines · Amanda Shafack via GitGitGadget

Using the logical not operator on both the git and grep command is redundant, since the main check is done at the level of the grep command.

Apply the logical not operator only to the grep command.
---

t/t2200-add-update.sh test_expect_success 'add -u resolves unmerged paths' ' · line 180

Quoted 6 lines
t/t2200-add-update.sh +2 -4
@@ -179,10 +179,8 @@ test_expect_success 'add -u resolves unmerged paths' '
-       ! (
-               git ls-files >actual &&
-               grep "non-existent" actual
-       )
+       git ls-files >actual &&
+       ! grep "non-existent" actual

The commit message talks only about redundancy of applying the logical NOT operator to the combined subshell content, but what it misses is that transformation of:

! (git ls-files | grep "non-existent")

in patch [1/2] into:

    ! (
        git ls-files >actual &&
        grep "non-existent" actual
    )

is actively wrong. In particular, if git ls-files itself fails, then the grep will never get run, and the subshell will exit with a failure, however, the NOT then turns that failure into a success, which is quite undesirable. The test should fail if either git ls-files fails or if the grep expectation is not met; it should not succeed when git ls-files fails.

So, the correct thing to do is to merge [1/2] and [2/2] into a single patch which directly transforms:

! (git ls-files | grep "non-existent")

into:

git ls-files >actual &&
! grep "non-existent" actual

#6 lore raw

Re: [PATCH 2/2] t2200: modify code syntax

I agree with you. I have made these changes as well. Thanks

Quoted 47 lines · Eric Sunshine
Quoted 8 lines · Amanda Shafack via GitGitGadget

Using the logical not operator on both the git and grep command is redundant, since the main check is done at the level of the grep command.

Apply the logical not operator only to the grep command.
---

t/t2200-add-update.sh test_expect_success 'add -u resolves unmerged paths' ' · line 180

Quoted 6 lines
t/t2200-add-update.sh +2 -4
@@ -179,10 +179,8 @@ test_expect_success 'add -u resolves unmerged paths' '
-       ! (
-               git ls-files >actual &&
-               grep "non-existent" actual
-       )
+       git ls-files >actual &&
+       ! grep "non-existent" actual

The commit message talks only about redundancy of applying the logical NOT operator to the combined subshell content, but what it misses is that transformation of:

! (git ls-files | grep "non-existent")

in patch [1/2] into:

    ! (
        git ls-files >actual &&
        grep "non-existent" actual
    )

is actively wrong. In particular, if git ls-files itself fails, then the grep will never get run, and the subshell will exit with a failure, however, the NOT then turns that failure into a success, which is quite undesirable. The test should fail if either git ls-files fails or if the grep expectation is not met; it should not succeed when git ls-files fails.

So, the correct thing to do is to merge [1/2] and [2/2] into a single patch which directly transforms:

! (git ls-files | grep "non-existent")

into:

git ls-files >actual &&
! grep "non-existent" actual

Signature · 3 lines
Cheers!

Amanda  Shafack
#7 lore raw

PATCH v2 1/1 t9832,t2200: avoid using pipes in git commands

In reply to Amanda Shafack via GitGitGadget

From: Amanda Shafack <[email protected]>

When a git command is upstream in a pipe, an unexpected failure of the git command will go unnoticed.

Write out the output of the git command to a file, so as to actively catch a failure of the git command.

---
[Outreachy][Patch v2] t9832,t2200: avoid using pipes in git related commands

Changes since v1:

* Merged patch [1/2] and [2/2] into a single patch
* Revised commit message

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-885%2Flkmandy%2Favoid-pipes-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-885/lkmandy/avoid-pipes-v2
Pull-Request: https://github.com/git/git/pull/885

Range-diff vs v1:

1: fc2da014a6 ! 1: bca393e69a t9832,t2200: avoid using pipes in git commands
@@ Metadata
## Commit message ##
t9832,t2200: avoid using pipes in git commands

- When the upstream of a pipe throws an error, the downstream still
- executes normally. This happens because the exit code of the upstream
- in a pipe is ignored. This behavior can make debugging very hard
- incase a test fails. Also, pipes are prone to deadlocks. If the
- upstream gets full, the commands downstream will never start.
+ When a git command is upstream in a pipe, an unexpected failure of
+ the git command will go unnoticed.

- Write out the output of the git command to a file, so as to test the
- exit codes of both commands.
-
- Commit c6f44e1da5 (t9813: avoid using pipes, 2017-01-04) noticed that
- the exit code of upstream in the pipe is ignored, thus using pipes
- should be avoided.
+ Write out the output of the git command to a file, so as to actively
+ catch a failure of the git command.

@@ t/t2200-add-update.sh: test_expect_success 'add -u resolves unmerged paths' '
test_expect_success '"add -u non-existent" should fail' '
test_must_fail git add -u non-existent &&
- ! (git ls-files | grep "non-existent")
-+ ! (
-+ git ls-files >actual &&
-+ grep "non-existent" actual
-+ )
++ git ls-files >actual &&
++ ! grep "non-existent" actual
'

test_done
2: 0a1550cb22 < -: ---------- t2200: modify code syntax

 t/t2200-add-update.sh | 3 ++-
 t/t9832-unshelve.sh   | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)
t/t2200-add-update.sh +2 -1
index f764b7e3f5..7cb7a70382 100755
@@ -179,7 +179,8 @@ test_expect_success 'add -u resolves unmerged paths' '
 
 test_expect_success '"add -u non-existent" should fail' '
 	test_must_fail git add -u non-existent &&
-	! (git ls-files | grep "non-existent")
+	git ls-files >actual &&
+	! grep "non-existent" actual
 '
 
 test_done
t/t9832-unshelve.sh +2 -1
index 7194fb2855..6b3cb0414a 100755
@@ -68,7 +68,8 @@ EOF
 		cd "$git" &&
 		change=$(last_shelved_change) &&
 		git p4 unshelve $change &&
-		git show refs/remotes/p4-unshelved/$change | grep -q "Further description" &&
+		git show refs/remotes/p4-unshelved/$change >actual &&
+		grep -q "Further description" actual &&
 		git cherry-pick refs/remotes/p4-unshelved/$change &&
 		test_path_is_file file2 &&
 		test_cmp file1 "$cli"/file1 &&

base-commit: a5fa49ff0a8f3252c6bff49f92b85e7683868f8a

Signature · 1 line
gitgitgadget
#8 lore raw

Re: [PATCH v2] t9832,t2200: avoid using pipes in git commands

Quoted 1 line · Amanda Shafack via GitGitGadget

t9832,t2200: avoid using pipes in git commands

The subject is a bit confusing since pipes aren't used in Git commands; instead, Git commands may be components of pipes. However, even that is too imprecise. The issue this patch is addressing is that we want to avoid Git commands _upstream_ in a pipe. It's perfectly acceptable for the Git command to be the final element of a pipe since the pipe returns the exit code of the final command. So, to be more precise, the subject could say:

t2200,t9832: avoid using git upstream in a pipe

Nit: It's subjective, but it feels a bit more natural to list the test numbers in ascending order rather than descending order, which is why I swapped them around in the example above.

Quoted 5 lines

When a git command is upstream in a pipe, an unexpected failure of the git command will go unnoticed.

Write out the output of the git command to a file, so as to actively catch a failure of the git command.

It's easy to see from the patch itself that the output of the Git command is now written to a file, so it's not necessary to say so in the commit message. Therefore, the entire body of the commit message could be written more succinctly, perhaps like this:

Avoid placing git upstream in a pipe since doing so throws away its exit code, thus an unexpected failure may go unnoticed.

The actual patch itself looks fine, and these comments about the commit message are quite minor, thus there probably is no need to re-roll (though feel free to do so if you think the bit of extra polishing of the commit message is worthwhile).

Thanks.

#9 lore raw

Re: [PATCH v2] t9832,t2200: avoid using pipes in git commands

Quoted 7 lines · Eric Sunshine

precise, the subject could say:

t2200,t9832: avoid using git upstream in a pipe

Nit: It's subjective, but it feels a bit more natural to list the test numbers in ascending order rather than descending order, which is why I swapped them around in the example above.

;-)

Quoted 6 lines
Quoted 5 lines

When a git command is upstream in a pipe, an unexpected failure of the git command will go unnoticed.

Write out the output of the git command to a file, so as to actively catch a failure of the git command.

Quoted 7 lines

It's easy to see from the patch itself that the output of the Git command is now written to a file, so it's not necessary to say so in the commit message. Therefore, the entire body of the commit message could be written more succinctly, perhaps like this:

Avoid placing git upstream in a pipe since doing so throws away its exit code, thus an unexpected failure may go unnoticed.

Yup.

Quoted 4 lines

The actual patch itself looks fine, and these comments about the commit message are quite minor, thus there probably is no need to re-roll (though feel free to do so if you think the bit of extra polishing of the commit message is worthwhile).

IIUC, the microproject experience aims new contributors to get used to the style of communication that happens during review cycles of a typical topic, using a trivial dip-the-toes-in-the-water problem as an example. I'd rather not to see contributors get into the habit of leaving loose ends and have somebody else clean after them.

Thanks.

#10 lore raw

Re: [PATCH v2] t9832,t2200: avoid using pipes in git commands

Quoted 34 lines · Junio C Hamano
Quoted 7 lines · Eric Sunshine

precise, the subject could say:

t2200,t9832: avoid using git upstream in a pipe

Nit: It's subjective, but it feels a bit more natural to list the test numbers in ascending order rather than descending order, which is why I swapped them around in the example above.

;-)

Quoted 6 lines
Quoted 5 lines

When a git command is upstream in a pipe, an unexpected failure of the git command will go unnoticed.

Write out the output of the git command to a file, so as to actively catch a failure of the git command.

Quoted 7 lines

It's easy to see from the patch itself that the output of the Git command is now written to a file, so it's not necessary to say so in the commit message. Therefore, the entire body of the commit message could be written more succinctly, perhaps like this:

Avoid placing git upstream in a pipe since doing so throws away its exit code, thus an unexpected failure may go unnoticed.

Yup.

Quoted 4 lines

The actual patch itself looks fine, and these comments about the commit message are quite minor, thus there probably is no need to re-roll (though feel free to do so if you think the bit of extra polishing of the commit message is worthwhile).

Quoted 5 lines

IIUC, the microproject experience aims new contributors to get used to the style of communication that happens during review cycles of a typical topic, using a trivial dip-the-toes-in-the-water problem as an example. I'd rather not to see contributors get into the habit of leaving loose ends and have somebody else clean after them.

Taken very seriously

Quoted 1 line

Thanks.

Signature · 3 lines
Cheers!

Amanda  Shafack
#11 lore raw

Re: [PATCH v2] t9832,t2200: avoid using pipes in git commands

In reply to Eric Sunshine
Quoted 13 lines · Eric Sunshine
Quoted 1 line · Amanda Shafack via GitGitGadget

t9832,t2200: avoid using pipes in git commands

The subject is a bit confusing since pipes aren't used in Git commands; instead, Git commands may be components of pipes. However, even that is too imprecise. The issue this patch is addressing is that we want to avoid Git commands _upstream_ in a pipe. It's perfectly acceptable for the Git command to be the final element of a pipe since the pipe returns the exit code of the final command. So, to be more precise, the subject could say:

Quoted 6 lines

t2200,t9832: avoid using git upstream in a pipe

Nit: It's subjective, but it feels a bit more natural to list the test numbers in ascending order rather than descending order, which is why I swapped them around in the example above.

I agree it looks more appropriate.

Quoted 11 lines
Quoted 5 lines

When a git command is upstream in a pipe, an unexpected failure of the git command will go unnoticed.

Write out the output of the git command to a file, so as to actively catch a failure of the git command.

It's easy to see from the patch itself that the output of the Git command is now written to a file, so it's not necessary to say so in the commit message. Therefore, the entire body of the commit message could be written more succinctly, perhaps like this:

Quoted 7 lines

Avoid placing git upstream in a pipe since doing so throws away its exit code, thus an unexpected failure may go unnoticed.

The actual patch itself looks fine, and these comments about the commit message are quite minor, thus there probably is no need to re-roll (though feel free to do so if you think the bit of extra polishing of the commit message is worthwhile).

I believe it's best practice to optimize one's work as much as possible, so I have included these changes.
Thanks for the detailed explanation.

Quoted 1 line

Thanks.

Signature · 3 lines
Cheers!

Amanda  Shafack
#12 lore raw

PATCH v3 1/1 t2200,t9832: avoid using 'git' upstream in a pipe

In reply to Amanda Shafack via GitGitGadget

From: Amanda Shafack <[email protected]>

Avoid placing git upstream in a pipe since doing so throws away its exit code, thus an unexpected failure may go unnoticed.

---
[Outreachy][Patch v3] t2200,t9832: avoid using 'git' upstream in a pipe

Changes since v2:

* Optimized commit message

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-885%2Flkmandy%2Favoid-pipes-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-885/lkmandy/avoid-pipes-v3
Pull-Request: https://github.com/git/git/pull/885

Range-diff vs v2:

1: bca393e69a ! 1: d5f508b055 t9832,t2200: avoid using pipes in git commands
@@ Metadata
Author: Amanda Shafack <[email protected]>

## Commit message ##
- t9832,t2200: avoid using pipes in git commands
+ t2200,t9832: avoid using 'git' upstream in a pipe

- When a git command is upstream in a pipe, an unexpected failure of
- the git command will go unnoticed.
-
- Write out the output of the git command to a file, so as to actively
- catch a failure of the git command.
+ Avoid placing git upstream in a pipe since doing so throws away
+ its exit code, thus an unexpected failure may go unnoticed.

 t/t2200-add-update.sh | 3 ++-
 t/t9832-unshelve.sh   | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)
t/t2200-add-update.sh +2 -1
index f764b7e3f5..7cb7a70382 100755
@@ -179,7 +179,8 @@ test_expect_success 'add -u resolves unmerged paths' '
 
 test_expect_success '"add -u non-existent" should fail' '
 	test_must_fail git add -u non-existent &&
-	! (git ls-files | grep "non-existent")
+	git ls-files >actual &&
+	! grep "non-existent" actual
 '
 
 test_done
t/t9832-unshelve.sh +2 -1
index 7194fb2855..6b3cb0414a 100755
@@ -68,7 +68,8 @@ EOF
 		cd "$git" &&
 		change=$(last_shelved_change) &&
 		git p4 unshelve $change &&
-		git show refs/remotes/p4-unshelved/$change | grep -q "Further description" &&
+		git show refs/remotes/p4-unshelved/$change >actual &&
+		grep -q "Further description" actual &&
 		git cherry-pick refs/remotes/p4-unshelved/$change &&
 		test_path_is_file file2 &&
 		test_cmp file1 "$cli"/file1 &&

base-commit: a5fa49ff0a8f3252c6bff49f92b85e7683868f8a

Signature · 1 line
gitgitgadget
#13 lore raw

Re: [PATCH v3] t2200,t9832: avoid using 'git' upstream in a pipe

Quoted 4 lines · Amanda Shafack via GitGitGadget

From: Amanda Shafack <[email protected]>

Avoid placing git upstream in a pipe since doing so throws away its exit code, thus an unexpected failure may go unnoticed.

Well explained.

Quoted 10 lines

---

t/t2200-add-update.sh +0 -0
index f764b7e3f5..7cb7a70382 100755

t/t2200-add-update.sh test_expect_success 'add -u resolves unmerged paths' ' · line 184

Quoted 7 lines
t/t2200-add-update.sh +2 -1
@@ -179,7 +179,8 @@ test_expect_success 'add -u resolves unmerged paths' '
 
 test_expect_success '"add -u non-existent" should fail' '
 	test_must_fail git add -u non-existent &&
-	! (git ls-files | grep "non-existent")
+	git ls-files >actual &&
+	! grep "non-existent" actual
 '

In the scope of this patch, the above change is a good rewrite. Let's stop the iteration here---you've demonstrated through the microproject that you can now comfortably be involved in the review discussion.

In a larger scope of "can we write this particular line better?", however, the above may not be the _best_ answer. For example,

	test_must_fail git ls-files --error-unmatch non-existent

would be another and a more direct way to ensure that the named path does not appear in the index.

Thanks.