git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: git diff --quiet exits with 1 on clean tree with CRLF conversions

From
Mike Crowe <mac@mcrowe.com>
Date
Feb 20, 2017, 15:33 UTC
Message-ID
<20170220153322.GA8352@mcrowe.com>
In-Reply-To
<20170217221958.GA12163@mcrowe.com>
On Friday 17 February 2017 at 22:19:58 +0000, Mike Crowe wrote:
Show 37 quoted lines
> On Friday 17 February 2017 at 14:05:17 -0800, Junio C Hamano wrote:
> > Mike Crowe <mac@mcrowe.com> writes:
> > 
> > > If "git diff --quiet" finds it necessary to compare actual file contents,
> > > and a file requires CRLF conversion, then it incorrectly exits with an exit
> > > code of 1 even if there have been no changes.
> > >
> > > The patch below adds a test file that shows the problem.
> > 
> > If "git diff" does not show any output and "git diff --exit-code" or
> > "git diff --quiet" says there are differences, then it is a bug.
> > 
> > I would however have expected that any culprit would involve a code
> > that says "under QUICK option, we do not have to bother doing
> > this".  The part you quoted:
> > 
> > > 	if (!DIFF_FILE_VALID(p->one) || /* (1) */
> > > 	    !DIFF_FILE_VALID(p->two) ||
> > > 	    (p->one->oid_valid && p->two->oid_valid) ||
> > > 	    (p->one->mode != p->two->mode) ||
> > > 	    diff_populate_filespec(p->one, CHECK_SIZE_ONLY) ||
> > > 	    diff_populate_filespec(p->two, CHECK_SIZE_ONLY) ||
> > > 	    (p->one->size != p->two->size) ||
> > > 	    !diff_filespec_is_identical(p->one, p->two)) /* (2) */
> > > 		p->skip_stat_unmatch_result = 1;
> > 
> > is used by "git diff" with and without "--quiet", afacr, so I
> > suspect that the bug lies somewhere else.
> 
> I can't say that I really understand the code fully, but it appears that
> the first pass generates a queue of files that contain differences. The
> result of the quiet diff comes from the size of that queue,
> diff_queued_diff.nr, being non-zero in diffcore_std. I'm assuming that the
> result of the noisy diff comes from actually comparing the files.
> 
> But, I've only spent a short while looking so I may have got the wrong end
> of the stick.

Tricking Git into checking the actual file contents (by passing --ignore-space-change for example) is sufficient to ensure that the exit status is never 1 when it should be zero. (Of course that option has other unwanted effects in this case.)

I think that if there's a risk that file contents will undergo conversion then this should force the diff to check the file contents. Something like:

diff --git a/diff.c b/diff.c
index 051761b..bee1662 100644
--- a/diff.c
+++ b/diff.c
@@ -3413,13 +3413,14 @@ void diff_setup_done(struct diff_options *options)
 	/*
 	 * Most of the time we can say "there are changes"
 	 * only by checking if there are changed paths, but
-	 * --ignore-whitespace* options force us to look
-	 * inside contents.
+	 * --ignore-whitespace* options or text conversion
+	 * force us to look inside contents.
 	 */
 
 	if (DIFF_XDL_TST(options, IGNORE_WHITESPACE) ||
 	    DIFF_XDL_TST(options, IGNORE_WHITESPACE_CHANGE) ||
-	    DIFF_XDL_TST(options, IGNORE_WHITESPACE_AT_EOL))
+	    DIFF_XDL_TST(options, IGNORE_WHITESPACE_AT_EOL) ||
+	    DIFF_OPT_TST(options, ALLOW_TEXTCONV))
 		DIFF_OPT_SET(options, DIFF_FROM_CONTENTS);
 	else
 		DIFF_OPT_CLR(options, DIFF_FROM_CONTENTS);

This solves the problem for me and my test case now passes. Unfortunately
it breaks the 'removing and adding subproject' test case in
t3040-subprojects-basic at the line:

 test_expect_code 1 git diff -M --name-status --exit-code HEAD^ HEAD

presumably because after the rename has been detected the file contents are
identical. :( A rename of a single file appears to still be handled
correctly.

Mike.
Previous: Mike CroweNext: Junio C Hamano
Message 4 of 29 in “git diff --quiet exits with 1 on clean tree with CRLF conversions”
  1. Mike CroweFeb 17, 2017
  2. Junio C HamanoFeb 17, 2017
  3. Mike CroweFeb 17, 2017
  4. Mike CroweFeb 20, 2017
  5. Junio C HamanoFeb 20, 2017
  6. Mike CroweFeb 25, 2017
  7. Junio C HamanoFeb 27, 2017
  8. Torsten BögershausenFeb 28, 2017
  9. Junio C HamanoFeb 28, 2017
  10. 1/1 git diff --quiet exits with 1 on clean tree with CRLF conversionstboegi@web.de, Mar 1, 2017
  11. Junio C HamanoMar 1, 2017
  12. Junio C HamanoMar 1, 2017
  13. Jeff KingMar 2, 2017
  14. Junio C HamanoMar 2, 2017
  15. Jeff KingMar 2, 2017
  16. diff: do not short-cut CHECK_SIZE_ONLY check in diff_populate_filespec()Junio C Hamano, Mar 2, 2017
  17. Mike CroweMar 2, 2017
  18. Junio C HamanoMar 2, 2017
  19. Mike CroweMar 2, 2017
  20. Torsten BögershausenMar 3, 2017
  21. Junio C HamanoMar 3, 2017
  22. Torsten BögershausenMar 4, 2017
  23. Junio C HamanoMar 4, 2017
  24. Torsten BögershausenMar 2, 2017
  25. Mike CroweMar 1, 2017
  26. Junio C HamanoMar 1, 2017
  27. Torsten BögershausenMar 2, 2017
  28. Mike CroweMar 3, 2017
  29. git status reports file modified when only line-endings have changed (was git diff --quiet exits with 1 on clean tree with CRLF conversions)Mike Crowe, Mar 2, 2017

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.