Avoid accessing a slow working copy during diffcore operations.
[gitweb.git] / diff.c
diff --git a/diff.c b/diff.c
index 33153787b8117396cf906e69e656849ac04f3257..77ba641aa48974a7601875bd0a6a351baa30e726 100644 (file)
--- a/diff.c
+++ b/diff.c
 #include "xdiff-interface.h"
 #include "color.h"
 
+#ifdef NO_FAST_WORKING_DIRECTORY
+#define FAST_WORKING_DIRECTORY 0
+#else
+#define FAST_WORKING_DIRECTORY 1
+#endif
+
 static int use_size_cache;
 
 static int diff_detect_rename_default;
@@ -60,7 +66,7 @@ int git_diff_ui_config(const char *var, const char *value)
                diff_rename_limit_default = git_config_int(var, value);
                return 0;
        }
-       if (!strcmp(var, "diff.color")) {
+       if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) {
                diff_use_color_default = git_config_colorbool(var, value);
                return 0;
        }
@@ -74,7 +80,7 @@ int git_diff_ui_config(const char *var, const char *value)
                        diff_detect_rename_default = DIFF_DETECT_RENAME;
                return 0;
        }
-       if (!strncmp(var, "diff.color.", 11)) {
+       if (!strncmp(var, "diff.color.", 11) || !strncmp(var, "color.diff.", 11)) {
                int slot = parse_diff_color_slot(var, 11);
                color_parse(value, var, diff_colors[slot]);
                return 0;
@@ -802,7 +808,10 @@ static void show_numstat(struct diffstat_t* data, struct diff_options *options)
        for (i = 0; i < data->nr; i++) {
                struct diffstat_file *file = data->files[i];
 
-               printf("%d\t%d\t", file->added, file->deleted);
+               if (file->is_binary)
+                       printf("-\t-\t");
+               else
+                       printf("%d\t%d\t", file->added, file->deleted);
                if (options->line_termination &&
                    quote_c_style(file->name, NULL, NULL, 0))
                        quote_c_style(file->name, NULL, stdout, 0);
@@ -1155,7 +1164,7 @@ void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1,
  * the work tree has that object contents, return true, so that
  * prepare_temp_file() does not have to inflate and extract.
  */
-static int work_tree_matches(const char *name, const unsigned char *sha1)
+static int reuse_worktree_file(const char *name, const unsigned char *sha1, int want_file)
 {
        struct cache_entry *ce;
        struct stat st;
@@ -1176,6 +1185,18 @@ static int work_tree_matches(const char *name, const unsigned char *sha1)
        if (!active_cache)
                return 0;
 
+       /* We want to avoid the working directory if our caller
+        * doesn't need the data in a normal file, this system
+        * is rather slow with its stat/open/mmap/close syscalls,
+        * and the object is contained in a pack file.  The pack
+        * is probably already open and will be faster to obtain
+        * the data through than the working directory.  Loose
+        * objects however would tend to be slower as they need
+        * to be individually opened and inflated.
+        */
+       if (FAST_WORKING_DIRECTORY && !want_file && has_sha1_pack(sha1, NULL))
+               return 0;
+
        len = strlen(name);
        pos = cache_name_pos(name, len);
        if (pos < 0)
@@ -1262,7 +1283,7 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
        if (s->data)
                return err;
        if (!s->sha1_valid ||
-           work_tree_matches(s->path, s->sha1)) {
+           reuse_worktree_file(s->path, s->sha1, 0)) {
                struct stat st;
                int fd;
                if (lstat(s->path, &st) < 0) {
@@ -1369,7 +1390,7 @@ static void prepare_temp_file(const char *name,
        }
 
        if (!one->sha1_valid ||
-           work_tree_matches(name, one->sha1)) {
+           reuse_worktree_file(name, one->sha1, 1)) {
                struct stat st;
                if (lstat(name, &st) < 0) {
                        if (errno == ENOENT)