git-diff: resurrect the traditional empty "diff --git" behaviour
authorJunio C Hamano <gitster@pobox.com>
Fri, 31 Aug 2007 20:13:42 +0000 (13:13 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sat, 1 Sep 2007 06:30:14 +0000 (23:30 -0700)
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 <gitster@pobox.com>
Documentation/config.txt
builtin-diff.c
cache.h
diff.c

index 903610fecf9ca084306e6080c86e69315f9b300b..cf7617a5b19520d28fb196cb1927019057e061c4 100644 (file)
@@ -396,6 +396,16 @@ color.status.<slot>::
 commit.template::
        Specify a file to use as the template for new commit messages.
 
+diff.autorefreshindex::
+       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`.
+
 diff.renameLimit::
        The number of files to consider when performing the copy/rename
        detection; equivalent to the git diff option '-l'.
index 6ed7b6842ec533902427f2d47790d57aa5082365..f77352b40decdc4cf8d2db29102703cb1193b49c 100644 (file)
@@ -188,6 +188,30 @@ void add_head(struct rev_info *revs)
        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();
+       refresh_cache(REFRESH_QUIET|REFRESH_UNMERGED);
+       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;
@@ -222,7 +246,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;
+       rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index;
 
        if (!setup_diff_no_index(&rev, argc, argv, nongit, prefix))
                argc = 0;
@@ -346,11 +370,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
        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;
 }
diff --git a/cache.h b/cache.h
index c7e00e7b0528d640af9e70a2d84455e7cf727993..70abbd59bf8d3ca118836605099b0b5dc66a27b7 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -594,6 +594,9 @@ extern char *convert_to_git(const char *path, const char *src, unsigned long *si
 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);
 
diff --git a/diff.c b/diff.c
index a7e76719d12a9083c465d60eee333aa880b5a1c2..0d30d05263f631c2c88ebb1b8af7e96bb2cfd56a 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -19,6 +19,7 @@
 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 */
@@ -166,6 +167,10 @@ int git_diff_ui_config(const char *var, const char *value)
                        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, '.');