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

Re: [PATCH] Add --show-touched option to show "diff --git" line when contents are unchanged

From
Junio C Hamano <gitster@pobox.com>
Date
Aug 3, 2007, 20:33 UTC
Message-ID
<7vir7wmk84.fsf@assigned-by-dhcp.cox.net>
In-Reply-To
<Pine.LNX.4.64.0708031121000.14781@racer.site>
Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> But I'd really think that what should be done (if anything has to be done 
> at all) is to introduce a config variable which triggers the same logic in 
> git-diff as was introduced in 2b5f9a8c0cff511f2bb0833b1ee02645b79323f4.

Sorry, I don't follow at all. The diff toolchain works all inside core without having to write a temporary index out, which was the issue the commit you are quoting was about.

In any case, enough discussion. Here is an updated patch, which I _could_ be pursuaded to consider for inclusion after v1.5.3 happens, if there are enough agreements and Acks.

-- >8 -- git-diff: --stat-unmatch

Traditionally, git-diff with the working tree files showed files whose lstat(2) information did not match with what were recorded in the index, even if the actual contents did not have any differences. This squelches such output from git-diff by default.

A new option, --stat-unmatch, is introduced to restore the traditional behaviour. This is useful to see if you want to know you have too many files you only touch(1)ed without modifying. Having many such paths hurts performance, and you can run "git-update-index --refresh" to update the lstat(2) information recorded in the index in such a case.

The low level git-diff-files command is not affected.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 Documentation/git-diff.txt |   13 ++++++++++
 builtin-diff.c             |   13 ++++++++++
 diff.c                     |   54 ++++++++++++++++++++++++++++++++++++++++++++
 diff.h                     |    1 +
 4 files changed, 81 insertions(+), 0 deletions(-)
diff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt
index b36e705..efdc65b 100644
--- a/Documentation/git-diff.txt
+++ b/Documentation/git-diff.txt
@@ -59,6 +59,19 @@ OPTIONS
 -------
 include::diff-options.txt[]
 
+--stat-unmatch::
+	Traditionally, `git-diff` with the working tree files
+	showed files whose `lstat(2)` information did not match
+	with what were recorded in the index, even if the actual
+	contents did not have any differences, but recent git
+	squelches such output.  This option can be used to
+	restore the traditional behaviour.  This is useful to
+	see if you want to know you have too many files you only
+	`touch(1)`ed without modifying.  Having many such paths
+	hurts performance, and you can run `git-update-index
+	--refresh` to update the `lstat(2)` information recorded
+	in the index in such a case.
+
 <path>...::
 	The <paths> parameters, when given, are used to limit
 	the diff to the named paths (you can give directory
diff --git a/builtin-diff.c b/builtin-diff.c
index b48121e..c8e137d 100644
--- a/builtin-diff.c
+++ b/builtin-diff.c
@@ -222,6 +222,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
 	prefix = setup_git_directory_gently(&nongit);
 	git_config(git_diff_ui_config);
 	init_revisions(&rev, prefix);
+	rev.diffopt.skip_stat_unmatch = 1;
 
 	if (!setup_diff_no_index(&rev, argc, argv, nongit, prefix))
 		argc = 0;
@@ -338,5 +339,17 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
 					     ent, ents);
 	if (rev.diffopt.exit_with_status)
 		result = rev.diffopt.has_changes;
+
+	/*
+	 * We do not actually do this here because 99% of the time
+	 * the pager is in effect and this will not be shown, but
+	 * you could if you wanted to.
+	 *
+	 * if (1 < rev.diffopt.skip_stat_unmatch)
+	 *	fprintf(stderr,
+	 *		"Squelched %d stat-only differences.\n",
+	 *		rev.diffopt.skip_stat_unmatch - 1);
+	 *
+	 */
 	return result;
 }
diff --git a/diff.c b/diff.c
index a5fc56b..8c26e4d 100644
--- a/diff.c
+++ b/diff.c
@@ -2261,6 +2261,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
 	else if (!strcmp(arg, "--shortstat")) {
 		options->output_format |= DIFF_FORMAT_SHORTSTAT;
 	}
+	else if (!strcmp(arg, "--stat-unmatch"))
+		options->skip_stat_unmatch = 0;
 	else if (!prefixcmp(arg, "--stat")) {
 		char *end;
 		int width = options->stat_width;
@@ -3143,11 +3145,63 @@ static void diffcore_apply_filter(const char *filter)
 	*q = outq;
 }
 
+static void diffcore_skip_stat_unmatch(struct diff_options *diffopt)
+{
+	int i;
+	struct diff_queue_struct *q = &diff_queued_diff;
+	struct diff_queue_struct outq;
+	outq.queue = NULL;
+	outq.nr = outq.alloc = 0;
+
+	for (i = 0; i < q->nr; i++) {
+		struct diff_filepair *p = q->queue[i];
+
+		/*
+		 * 1. Entries that come from stat info dirtyness
+		 *    always have both sides (iow, not create/delete),
+		 *    one side of the object name is unknown, with
+		 *    the same mode and size.  Keep the ones that
+		 *    do not match these criteria.  They have real
+		 *    differences.
+		 *
+		 * 2. At this point, the file is known to be modified,
+		 *    with the same mode and size, and the object
+		 *    name of one side is unknown.  Need to inspect
+		 *    the identical contents.
+		 */
+		if (!DIFF_FILE_VALID(p->one) || /* (1) */
+		    !DIFF_FILE_VALID(p->two) ||
+		    (p->one->sha1_valid && p->two->sha1_valid) ||
+		    (p->one->mode != p->two->mode) ||
+		    diff_populate_filespec(p->one, 1) ||
+		    diff_populate_filespec(p->two, 1) ||
+		    (p->one->size != p->two->size) ||
+
+		    diff_populate_filespec(p->one, 0) || /* (2) */
+		    diff_populate_filespec(p->two, 0) ||
+		    memcmp(p->one->data, p->two->data, p->one->size))
+			diff_q(&outq, p);
+		else {
+			/*
+			 * The caller can subtract 1 from skip_stat_unmatch
+			 * to determine how many paths were dirty only
+			 * due to stat info mismatch.
+			 */
+			diffopt->skip_stat_unmatch++;
+			diff_free_filepair(p);
+		}
+	}
+	free(q->queue);
+	*q = outq;
+}
+
 void diffcore_std(struct diff_options *options)
 {
 	if (options->quiet)
 		return;
 
+	if (options->skip_stat_unmatch && !options->find_copies_harder)
+		diffcore_skip_stat_unmatch(options);
 	if (options->break_opt != -1)
 		diffcore_break(options->break_opt);
 	if (options->detect_rename)
diff --git a/diff.h b/diff.h
index 9fd6d44..de21f8e 100644
--- a/diff.h
+++ b/diff.h
@@ -65,6 +65,7 @@ struct diff_options {
 	int context;
 	int break_opt;
 	int detect_rename;
+	int skip_stat_unmatch;
 	int line_termination;
 	int output_format;
 	int pickaxe_opts;
Previous: Johannes SchindelinNext: Matthieu Moy
Message 19 of 75 in “git-diff on touched files: bug or feature?”
  1. Matthieu MoyAug 1, 2007
  2. Junio C HamanoAug 1, 2007
  3. Alexandre JulliardAug 1, 2007
  4. Junio C HamanoAug 1, 2007
  5. Alexandre JulliardAug 1, 2007
  6. Matthieu MoyAug 2, 2007
  7. Johannes SchindelinAug 2, 2007
  8. Matthieu MoyAug 2, 2007
  9. Johannes SchindelinAug 2, 2007
  10. Jean-François VeilletteAug 2, 2007
  11. Johannes SchindelinAug 2, 2007
  12. Steven GrimmAug 2, 2007
  13. Johannes SchindelinAug 2, 2007
  14. Matthieu MoyAug 2, 2007
  15. J. Bruce FieldsAug 2, 2007
  16. Add --show-touched option to show "diff --git" line when contents are unchangedSteven Grimm, Aug 3, 2007
  17. Junio C HamanoAug 3, 2007
  18. Johannes SchindelinAug 3, 2007
  19. Junio C HamanoAug 3, 2007
  20. Matthieu MoyAug 3, 2007
  21. Junio C HamanoAug 3, 2007
  22. Matthieu MoyAug 3, 2007
  23. Junio C HamanoAug 3, 2007
  24. Matthieu MoyAug 5, 2007
  25. Johannes SchindelinAug 5, 2007
  26. Matthieu MoyAug 5, 2007
  27. Matthias LederhoferAug 6, 2007
  28. David KastrupAug 6, 2007
  29. David KastrupAug 6, 2007
  30. Matthieu MoyAug 6, 2007
  31. Junio C HamanoAug 6, 2007
  32. David KastrupAug 7, 2007
  33. J. Bruce FieldsAug 7, 2007
  34. Linus TorvaldsAug 7, 2007
  35. Junio C HamanoAug 7, 2007
  36. David KastrupAug 7, 2007
  37. Linus TorvaldsAug 8, 2007
  38. Junio C HamanoAug 8, 2007
  39. Johannes SchindelinAug 8, 2007
  40. Junio C HamanoAug 8, 2007
  41. David KastrupAug 8, 2007
  42. Johannes SchindelinAug 8, 2007
  43. Jakub NarebskiAug 8, 2007
  44. Steven GrimmAug 7, 2007
  45. Add a note about the index being updated by git-status in some casesSteven Grimm, Aug 7, 2007
  46. git-diff: Output a warning about stale files in the indexSteven Grimm, Aug 7, 2007
  47. Junio C HamanoAug 7, 2007
  48. git-diff: Output a warning about stale files in the indexSteven Grimm, Aug 7, 2007
  49. Junio C HamanoAug 7, 2007
  50. Steven GrimmAug 7, 2007
  51. Jakub NarebskiAug 7, 2007
  52. Junio C HamanoAug 11, 2007
  53. Linus TorvaldsAug 8, 2007
  54. Steven GrimmAug 7, 2007
  55. Matthieu MoyAug 7, 2007
  56. Junio C HamanoAug 2, 2007
  57. Junio C HamanoAug 2, 2007
  58. Junio C HamanoAug 2, 2007
  59. Matthieu MoyAug 2, 2007
  60. Johannes SchindelinAug 2, 2007
  61. Junio C HamanoAug 2, 2007
  62. Jeff KingAug 3, 2007
  63. Junio C HamanoAug 3, 2007
  64. Jeff KingAug 3, 2007
  65. Junio C HamanoAug 3, 2007
  66. Shawn O. PearceAug 3, 2007
  67. Junio C HamanoAug 3, 2007
  68. Matthieu MoyAug 2, 2007
  69. Johannes SchindelinAug 2, 2007
  70. Matthieu MoyAug 2, 2007
  71. Johannes SchindelinAug 2, 2007
  72. Matthieu MoyAug 2, 2007
  73. Johannes SchindelinAug 2, 2007
  74. Joel ReedAug 2, 2007
  75. Johannes SchindelinAug 2, 2007

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.