fix typo in git-am manpage
[gitweb.git] / diff-lib.c
index fc69fb92a50c3dff67da76fedf1bf1df561c6065..60c0fa6488eda7ae382500b70041aac4202a59c0 100644 (file)
@@ -7,6 +7,7 @@
 #include "diff.h"
 #include "diffcore.h"
 #include "revision.h"
+#include "cache-tree.h"
 
 /*
  * diff-files
@@ -40,17 +41,27 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed)
 
                        path_len = ce_namelen(ce);
 
-                       dpath = xmalloc (combine_diff_path_size (5, path_len));
+                       dpath = xmalloc(combine_diff_path_size(5, path_len));
                        dpath->path = (char *) &(dpath->parent[5]);
 
                        dpath->next = NULL;
                        dpath->len = path_len;
                        memcpy(dpath->path, ce->name, path_len);
                        dpath->path[path_len] = '\0';
-                       dpath->mode = 0;
                        hashclr(dpath->sha1);
                        memset(&(dpath->parent[0]), 0,
-                                       sizeof(struct combine_diff_parent)*5);
+                              sizeof(struct combine_diff_parent)*5);
+
+                       if (lstat(ce->name, &st) < 0) {
+                               if (errno != ENOENT && errno != ENOTDIR) {
+                                       perror(ce->name);
+                                       continue;
+                               }
+                               if (silent_on_removed)
+                                       continue;
+                       }
+                       else
+                               dpath->mode = canon_mode(st.st_mode);
 
                        while (i < entries) {
                                struct cache_entry *nce = active_cache[i];
@@ -97,7 +108,7 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed)
                         * Show the diff for the 'ce' if we found the one
                         * from the desired stage.
                         */
-                       diff_unmerge(&revs->diffopt, ce->name);
+                       diff_unmerge(&revs->diffopt, ce->name, 0, null_sha1);
                        if (ce_stage(ce) != diff_unmerged_stage)
                                continue;
                }
@@ -169,9 +180,7 @@ static int get_stat_data(struct cache_entry *ce,
                }
                changed = ce_match_stat(ce, &st, 0);
                if (changed) {
-                       mode = create_ce_mode(st.st_mode);
-                       if (!trust_executable_bit && S_ISREG(st.st_mode))
-                               mode = ce->ce_mode;
+                       mode = ce_mode_from_stat(ce, st.st_mode);
                        sha1 = no_sha1;
                }
        }
@@ -271,7 +280,7 @@ static int diff_cache(struct rev_info *revs,
                                break;
                        }
                        /* Show difference between old and new */
-                       show_modified(revs,ac[1], ce, 1,
+                       show_modified(revs, ac[1], ce, 1,
                                      cached, match_missing);
                        break;
                case 1:
@@ -297,9 +306,12 @@ static int diff_cache(struct rev_info *revs,
                            !show_modified(revs, ce, ac[1], 0,
                                           cached, match_missing))
                                break;
-                       /* fallthru */
+                       diff_unmerge(&revs->diffopt, ce->name,
+                                    ntohl(ce->ce_mode), ce->sha1);
+                       break;
                case 3:
-                       diff_unmerge(&revs->diffopt, ce->name);
+                       diff_unmerge(&revs->diffopt, ce->name,
+                                    0, null_sha1);
                        break;
 
                default:
@@ -369,3 +381,44 @@ int run_diff_index(struct rev_info *revs, int cached)
        diff_flush(&revs->diffopt);
        return ret;
 }
+
+int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)
+{
+       struct tree *tree;
+       struct rev_info revs;
+       int i;
+       struct cache_entry **dst;
+       struct cache_entry *last = NULL;
+
+       /*
+        * This is used by git-blame to run diff-cache internally;
+        * it potentially needs to repeatedly run this, so we will
+        * start by removing the higher order entries the last round
+        * left behind.
+        */
+       dst = active_cache;
+       for (i = 0; i < active_nr; i++) {
+               struct cache_entry *ce = active_cache[i];
+               if (ce_stage(ce)) {
+                       if (last && !strcmp(ce->name, last->name))
+                               continue;
+                       cache_tree_invalidate_path(active_cache_tree,
+                                                  ce->name);
+                       last = ce;
+                       ce->ce_mode = 0;
+                       ce->ce_flags &= ~htons(CE_STAGEMASK);
+               }
+               *dst++ = ce;
+       }
+       active_nr = dst - active_cache;
+
+       init_revisions(&revs, NULL);
+       revs.prune_data = opt->paths;
+       tree = parse_tree_indirect(tree_sha1);
+       if (!tree)
+               die("bad tree object %s", sha1_to_hex(tree_sha1));
+       if (read_tree(tree, 1, opt->paths))
+               return error("unable to read tree %s", sha1_to_hex(tree_sha1));
+       return diff_cache(&revs, active_cache, active_nr, revs.prune_data,
+                         1, 0);
+}