unpack-trees: do not muck with attributes when we are not checking out
[gitweb.git] / diff.c
diff --git a/diff.c b/diff.c
index 75d9fab8f87033ba86f687fbc92c5d4ee4c68d7b..3ac71686ebef3d3f9c8b0b72adf612e9535031a5 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -62,6 +62,15 @@ static int parse_diff_color_slot(const char *var, int ofs)
        die("bad config variable '%s'", var);
 }
 
+static int git_config_rename(const char *var, const char *value)
+{
+       if (!value)
+               return DIFF_DETECT_RENAME;
+       if (!strcasecmp(value, "copies") || !strcasecmp(value, "copy"))
+               return  DIFF_DETECT_COPY;
+       return git_config_bool(var,value) ? DIFF_DETECT_RENAME : 0;
+}
+
 /*
  * These are to give UI layer defaults.
  * The core-level commands such as git-diff-files should
@@ -75,13 +84,7 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
                return 0;
        }
        if (!strcmp(var, "diff.renames")) {
-               if (!value)
-                       diff_detect_rename_default = DIFF_DETECT_RENAME;
-               else if (!strcasecmp(value, "copies") ||
-                        !strcasecmp(value, "copy"))
-                       diff_detect_rename_default = DIFF_DETECT_COPY;
-               else if (git_config_bool(var,value))
-                       diff_detect_rename_default = DIFF_DETECT_RENAME;
+               diff_detect_rename_default = git_config_rename(var, value);
                return 0;
        }
        if (!strcmp(var, "diff.autorefreshindex")) {
@@ -1757,7 +1760,8 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int
        struct stat st;
        int pos, len;
 
-       /* We do not read the cache ourselves here, because the
+       /*
+        * We do not read the cache ourselves here, because the
         * benchmark with my previous version that always reads cache
         * shows that it makes things worse for diff-tree comparing
         * two linux-2.6 kernel trees in an already checked out work
@@ -1797,6 +1801,13 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int
        if (hashcmp(sha1, ce->sha1) || !S_ISREG(ce->ce_mode))
                return 0;
 
+       /*
+        * If ce is marked as "assume unchanged", there is no
+        * guarantee that work tree matches what we are looking for.
+        */
+       if (ce->ce_flags & CE_VALID)
+               return 0;
+
        /*
         * If ce matches the file in the work tree, we can reuse it.
         */
@@ -1946,17 +1957,23 @@ void diff_free_filespec_data(struct diff_filespec *s)
        s->cnt_data = NULL;
 }
 
-static void prep_temp_blob(struct diff_tempfile *temp,
+static void prep_temp_blob(const char *path, struct diff_tempfile *temp,
                           void *blob,
                           unsigned long size,
                           const unsigned char *sha1,
                           int mode)
 {
        int fd;
+       struct strbuf buf = STRBUF_INIT;
 
        fd = git_mkstemp(temp->tmp_path, PATH_MAX, ".diff_XXXXXX");
        if (fd < 0)
                die("unable to create temp-file: %s", strerror(errno));
+       if (convert_to_working_tree(path,
+                       (const char *)blob, (size_t)size, &buf)) {
+               blob = buf.buf;
+               size = buf.len;
+       }
        if (write_in_full(fd, blob, size) != size)
                die("unable to write temp-file");
        close(fd);
@@ -1964,6 +1981,7 @@ static void prep_temp_blob(struct diff_tempfile *temp,
        strcpy(temp->hex, sha1_to_hex(sha1));
        temp->hex[40] = 0;
        sprintf(temp->mode, "%06o", mode);
+       strbuf_release(&buf);
 }
 
 static struct diff_tempfile *prepare_temp_file(const char *name,
@@ -2004,7 +2022,7 @@ static struct diff_tempfile *prepare_temp_file(const char *name,
                                die("readlink(%s)", name);
                        if (ret == sizeof(buf))
                                die("symlink too long: %s", name);
-                       prep_temp_blob(temp, buf, ret,
+                       prep_temp_blob(name, temp, buf, ret,
                                       (one->sha1_valid ?
                                        one->sha1 : null_sha1),
                                       (one->sha1_valid ?
@@ -2030,7 +2048,7 @@ static struct diff_tempfile *prepare_temp_file(const char *name,
        else {
                if (diff_populate_filespec(one, 0))
                        die("cannot read data blob for %s", one->path);
-               prep_temp_blob(temp, one->data, one->size,
+               prep_temp_blob(name, temp, one->data, one->size,
                               one->sha1, one->mode);
        }
        return temp;