Anonymous committed aecbf91

git-diff: resurrect the traditional empty "diff --git" behaviour

The warning message to suggest "Consider running git-status" from
"git-diff" that we experimented with during the 1.5.3 cycle turns
out to be a bad idea. It robbed cache-dirty information from people
who valued it, while still asking users to run "update-index --refresh".
It was hoped that the new behaviour would at least have some educational
value, but not showing the cache-dirty paths like before meant that the
user would not even know easily which paths were cache-dirty, and it
made the need to refresh the index look like even more unnecessary chore.

This commit reinstates the traditional behaviour, but with a twist.

By default, the empty "diff --git" output is totally squelched out
from "git diff" output. At the end of the command, it automatically
runs "update-index --refresh" as needed, without even bothering the
user. In other words, people who do not care about the cache-dirtyness
do not even have to see the warning.

The traditional behaviour to see the stat-dirty output and to bypassing
the overhead of content comparison can be specified by setting the
configuration variable diff.autorefreshindex to false.

Signed-off-by: Junio C Hamano <>

Comments (0)

Files changed (4)


 	Specify a file to use as the template for new commit messages.
+	When using `git diff` to compare with work tree
+	files, do not consider stat-only change as changed.
+	Instead, silently run `git update-index --refresh` to
+	update the cached stat information for paths whose
+	contents in the work tree match the contents in the
+	index.  This option defaults to true.  Note that this
+	affects only `git diff` Porcelain, and not lower level
+	`diff` commands, such as `git diff-files`.
 	The number of files to consider when performing the copy/rename
 	detection; equivalent to the git diff option '-l'.
 	add_pending_object(revs, obj, "HEAD");
+static void refresh_index_quietly(void)
+	struct lock_file *lock_file;
+	int fd;
+	lock_file = xcalloc(1, sizeof(struct lock_file));
+	fd = hold_locked_index(lock_file, 0);
+	if (fd < 0)
+		return;
+	discard_cache();
+	read_cache();
+	if (active_cache_changed) {
+		if (write_cache(fd, active_cache, active_nr) ||
+		    close(fd) ||
+		    commit_locked_index(lock_file))
+			; /*
+			   * silently ignore it -- we haven't mucked
+			   * with the real index.
+			   */
+	}
+	rollback_lock_file(lock_file);
 int cmd_diff(int argc, const char **argv, const char *prefix)
 	int i;
 	prefix = setup_git_directory_gently(&nongit);
 	init_revisions(&rev, prefix);
-	rev.diffopt.skip_stat_unmatch = 1;
+	rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index;
 	if (!setup_diff_no_index(&rev, argc, argv, nongit, prefix))
 		argc = 0;
 	if (rev.diffopt.exit_with_status)
 		result = rev.diffopt.has_changes;
-	if ((rev.diffopt.output_format & DIFF_FORMAT_PATCH)
-	    && (1 < rev.diffopt.skip_stat_unmatch))
-		printf("Warning: %d path%s touched but unmodified. "
-		       "Consider running git-status.\n",
-		       rev.diffopt.skip_stat_unmatch - 1,
-		       rev.diffopt.skip_stat_unmatch == 2 ? "" : "s");
+	if (1 < rev.diffopt.skip_stat_unmatch)
+		refresh_index_quietly();
 	return result;
 extern char *convert_to_working_tree(const char *path, const char *src, unsigned long *sizep);
 extern void *convert_sha1_file(const char *path, const unsigned char *sha1, unsigned int mode, enum object_type *type, unsigned long *size);
+/* diff.c */
+extern int diff_auto_refresh_index;
 /* match-trees.c */
 void shift_tree(const unsigned char *, const unsigned char *, unsigned char *, int);
 static int diff_detect_rename_default;
 static int diff_rename_limit_default = -1;
 static int diff_use_color_default;
+int diff_auto_refresh_index = 1;
 static char diff_colors[][COLOR_MAXLEN] = {
 	"\033[m",	/* reset */
 			diff_detect_rename_default = DIFF_DETECT_RENAME;
 		return 0;
+	if (!strcmp(var, "diff.autorefreshindex")) {
+		diff_auto_refresh_index = git_config_bool(var, value);
+		return 0;
+	}
 	if (!prefixcmp(var, "diff.")) {
 		const char *ep = strrchr(var, '.');