Hi Thomas, On Fri, Sep 18, 2020 at 07:32:56AM -0400, Thomas Guyot-Sionnest wrote: > A very handy way to pass data to applications is to use the <() process > substitution syntax in bash variants. It allow comparing files streamed > from a remote server or doing on-the-fly stream processing to alter the > diff. These are usually implemented as a symlink that points to a bogus > name (ex "pipe:[209326419]") but opens as a pipe. This is true in bash, but sh does not support process substitution with <(). > Git normally tracks symlinks targets. This patch makes it detect such > pipes in --no-index mode and read the file normally like it would do for > stdin ("-"), so they can be compared directly. > > Signed-off-by: Thomas Guyot-Sionnest <tguyot@xxxxxxxxx> > --- > diff-no-index.c | 56 ++++++++++-- > t/t4053-diff-no-index.sh | 189 +++++++++++++++++++++++++++++++++++++++ > 2 files changed, 238 insertions(+), 7 deletions(-) > > diff --git a/diff-no-index.c b/diff-no-index.c > index 7814eabfe0..779c686d23 100644 > --- a/diff-no-index.c > +++ b/diff-no-index.c > @@ -41,6 +41,33 @@ static int read_directory_contents(const char *path, struct string_list *list) > */ > static const char file_from_standard_input[] = "-"; > > +/* Check that file is - (STDIN) or unnamed pipe - explicitly > + * avoid on-disk named pipes which could block > + */ > +static int ispipe(const char *name) > +{ > + struct stat st; > + > + if (name == file_from_standard_input) > + return 1; /* STDIN */ > + > + if (!lstat(name, &st)) { > + if (S_ISLNK(st.st_mode)) { I had to read this a few times to make sure that I got it; you want to stat the link itself, and then check that it links to a pipe. I'm not sure why, though. Do you want to avoid handling named FIFOs in the code below? Your comment that they "could block" makes me think you do, but I don't know why that would be a problem. > + /* symlink - read it and check it doesn't exists > + * as a file yet link to a pipe */ > + struct strbuf sb = STRBUF_INIT; > + strbuf_realpath(&sb, name, 0); > + /* We're abusing strbuf_realpath here, it may append > + * pipe:[NNNNNNNNN] to an abs path */ > + if (!stat(sb.buf, &st)) Statting sb.buf is confusing to me (especially when followed up by another stat right below. Could you explain? > +test_expect_success 'diff --no-index can diff piped subshells' ' > + echo 1 >non/git/c && > + test_expect_code 0 git diff --no-index non/git/b <(cat non/git/c) && > + test_expect_code 0 git diff --no-index <(cat non/git/b) non/git/c && > + test_expect_code 0 git diff --no-index <(cat non/git/b) <(cat non/git/c) && > + test_expect_code 0 cat non/git/b | git diff --no-index - non/git/c && > + test_expect_code 0 cat non/git/c | git diff --no-index non/git/b - && > + test_expect_code 0 cat non/git/b | git diff --no-index - <(cat non/git/c) && > + test_expect_code 0 cat non/git/c | git diff --no-index <(cat non/git/b) - > +' Indeed this test fails (Git thinks that the HERE-DOC is broken, but I suspect it's just getting confused by the '<()'). This test (like almost all other tests in Git) use /bin/sh as its shebang. Does your /bin/sh actually point to bash? If you did want to test something like this, you'd need to source t/lib-bash.sh instead of t/test-lib.sh. Unrelated to the above comment, but there are a few small style nits that I notice: - There is no need to run with 'test_expect_code 0' since the test is marked as 'test_expect_success' and the commands are all in an '&&' chain. (This does appear to be common style for others in t4053, so you may just be matching it--which is fine--but an additional clean-up on top to modernize would be appreciated, too). - The cat pipe is unnecessary, and is also violating a rule that we don't place 'git' on the right-hand side of a pipe (can you redirect the file at the end instead?). Documentation/CodingGuidelines is a great place to look if you are ever curious about whether something is in good style. > +test_expect_success 'diff --no-index finds diff in piped subshells' ' > + ( > + set -- <(cat /dev/null) <(cat /dev/null) Why is this necessary? > + cat <<-EOF >expect > + diff --git a$1 b$2 > + --- a$1 > + +++ b$2 > + @@ -1 +1 @@ > + -1 > + +2 > + EOF > + ) && > + test_expect_code 1 \ > + git diff --no-index <(cat non/git/b) <(sed s/1/2/ non/git/c) >actual && > + test_cmp expect actual > +' Thanks, Taylor