#include "diff.h"
#include "diffcore.h"
#include "revision.h"
+#include "cache-tree.h"
/*
* diff-files
continue;
if (ce_stage(ce)) {
- struct {
- struct combine_diff_path p;
- struct combine_diff_parent filler[5];
- } combine;
+ struct combine_diff_path *dpath;
int num_compare_stages = 0;
+ size_t path_len;
- combine.p.next = NULL;
- combine.p.len = ce_namelen(ce);
- combine.p.path = xmalloc(combine.p.len + 1);
- memcpy(combine.p.path, ce->name, combine.p.len);
- combine.p.path[combine.p.len] = 0;
- combine.p.mode = 0;
- memset(combine.p.sha1, 0, 20);
- memset(&combine.p.parent[0], 0,
- sizeof(combine.filler));
+ path_len = ce_namelen(ce);
+
+ 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);
while (i < entries) {
struct cache_entry *nce = active_cache[i];
if (2 <= stage) {
int mode = ntohl(nce->ce_mode);
num_compare_stages++;
- memcpy(combine.p.parent[stage-2].sha1,
- nce->sha1, 20);
- combine.p.parent[stage-2].mode =
+ hashcpy(dpath->parent[stage-2].sha1, nce->sha1);
+ dpath->parent[stage-2].mode =
canon_mode(mode);
- combine.p.parent[stage-2].status =
+ dpath->parent[stage-2].status =
DIFF_STATUS_MODIFIED;
}
i--;
if (revs->combine_merges && num_compare_stages == 2) {
- show_combined_diff(&combine.p, 2,
+ show_combined_diff(dpath, 2,
revs->dense_combined_merges,
revs);
- free(combine.p.path);
+ free(dpath);
continue;
}
- free(combine.p.path);
+ free(dpath);
+ dpath = NULL;
/*
* 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;
}
}
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;
}
}
return -1;
}
+ if (revs->combine_merges && !cached &&
+ (hashcmp(sha1, old->sha1) || hashcmp(old->sha1, new->sha1))) {
+ struct combine_diff_path *p;
+ int pathlen = ce_namelen(new);
+
+ p = xmalloc(combine_diff_path_size(2, pathlen));
+ p->path = (char *) &p->parent[2];
+ p->next = NULL;
+ p->len = pathlen;
+ memcpy(p->path, new->name, pathlen);
+ p->path[pathlen] = 0;
+ p->mode = ntohl(mode);
+ hashclr(p->sha1);
+ memset(p->parent, 0, 2 * sizeof(struct combine_diff_parent));
+ p->parent[0].status = DIFF_STATUS_MODIFIED;
+ p->parent[0].mode = ntohl(new->ce_mode);
+ hashcpy(p->parent[0].sha1, new->sha1);
+ p->parent[1].status = DIFF_STATUS_MODIFIED;
+ p->parent[1].mode = ntohl(old->ce_mode);
+ hashcpy(p->parent[1].sha1, old->sha1);
+ show_combined_diff(p, 2, revs->dense_combined_merges, revs);
+ free(p);
+ return 0;
+ }
+
oldmode = old->ce_mode;
- if (mode == oldmode && !memcmp(sha1, old->sha1, 20) &&
+ if (mode == oldmode && !hashcmp(sha1, old->sha1) &&
!revs->diffopt.find_copies_harder)
return 0;
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:
!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:
}
mark_merge_entries();
- ent = revs->pending_objects->item;
- tree_name = revs->pending_objects->name;
+ ent = revs->pending.objects[0].item;
+ tree_name = revs->pending.objects[0].name;
tree = parse_tree_indirect(ent->sha1);
if (!tree)
return error("bad tree object %s", tree_name);
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);
+}