Finally implement "git log --follow"
[gitweb.git] / diff-lib.c
index 5c5b05bfe32bc90484b5bd6a9c171e0f9b04fbd6..7fb19c7b87fc39cc4515628e8623ccb92fbaa60e 100644 (file)
@@ -142,18 +142,34 @@ static int queue_diff(struct diff_options *o,
        }
 }
 
+/*
+ * Does the path name a blob in the working tree, or a directory
+ * in the working tree?
+ */
 static int is_in_index(const char *path)
 {
-       int len = strlen(path);
-       int pos = cache_name_pos(path, len);
-       char c;
-
-       if (pos < 0)
-               return 0;
-       if (strncmp(active_cache[pos]->name, path, len))
-               return 0;
-       c = active_cache[pos]->name[len];
-       return c == '\0' || c == '/';
+       int len, pos;
+       struct cache_entry *ce;
+
+       len = strlen(path);
+       while (path[len-1] == '/')
+               len--;
+       if (!len)
+               return 1; /* "." */
+       pos = cache_name_pos(path, len);
+       if (0 <= pos)
+               return 1;
+       pos = -1 - pos;
+       while (pos < active_nr) {
+               ce = active_cache[pos++];
+               if (ce_namelen(ce) <= len ||
+                   strncmp(ce->name, path, len) ||
+                   (ce->name[len] > '/'))
+                       break; /* path cannot be a prefix */
+               if (ce->name[len] == '/')
+                       return 1;
+       }
+       return 0;
 }
 
 static int handle_diff_files_args(struct rev_info *revs,
@@ -357,7 +373,7 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed)
                                        continue;
                        }
                        else
-                               dpath->mode = canon_mode(st.st_mode);
+                               dpath->mode = ntohl(ce_mode_from_stat(ce, st.st_mode));
 
                        while (i < entries) {
                                struct cache_entry *nce = active_cache[i];
@@ -374,8 +390,7 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed)
                                        int mode = ntohl(nce->ce_mode);
                                        num_compare_stages++;
                                        hashcpy(dpath->parent[stage-2].sha1, nce->sha1);
-                                       dpath->parent[stage-2].mode =
-                                               canon_mode(mode);
+                                       dpath->parent[stage-2].mode = ntohl(ce_mode_from_stat(nce, mode));
                                        dpath->parent[stage-2].status =
                                                DIFF_STATUS_MODIFIED;
                                }
@@ -424,15 +439,7 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed)
                if (!changed && !revs->diffopt.find_copies_harder)
                        continue;
                oldmode = ntohl(ce->ce_mode);
-
-               newmode = canon_mode(st.st_mode);
-               if (!trust_executable_bit &&
-                   S_ISREG(newmode) && S_ISREG(oldmode) &&
-                   ((newmode ^ oldmode) == 0111))
-                       newmode = oldmode;
-               else if (!has_symlinks &&
-                   S_ISREG(newmode) && S_ISLNK(oldmode))
-                       newmode = oldmode;
+               newmode = ntohl(ce_mode_from_stat(ce, st.st_mode));
                diff_change(&revs->diffopt, oldmode, newmode,
                            ce->sha1, (changed ? null_sha1 : ce->sha1),
                            ce->name, NULL);
@@ -657,7 +664,7 @@ int run_diff_index(struct rev_info *revs, int cached)
        const char *tree_name;
        int match_missing = 0;
 
-       /* 
+       /*
         * Backward compatibility wart - "diff-index -m" does
         * not mean "do not ignore merges", but totally different.
         */