diff options
Diffstat (limited to 'diff-lib.c')
-rw-r--r-- | diff-lib.c | 104 |
1 files changed, 90 insertions, 14 deletions
diff --git a/diff-lib.c b/diff-lib.c index 50521e2093..d18a118249 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -13,6 +13,7 @@ #include "submodule.h" #include "dir.h" #include "fsmonitor.h" +#include "commit-reach.h" /* * diff-files @@ -177,9 +178,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option) i--; if (revs->combine_merges && num_compare_stages == 2) { - show_combined_diff(dpath, 2, - revs->dense_combined_merges, - revs); + show_combined_diff(dpath, 2, revs); free(dpath); continue; } @@ -361,7 +360,7 @@ static int show_modified(struct rev_info *revs, p->parent[1].status = DIFF_STATUS_MODIFIED; p->parent[1].mode = old_entry->ce_mode; oidcpy(&p->parent[1].oid, &old_entry->oid); - show_combined_diff(p, 2, revs->dense_combined_merges, revs); + show_combined_diff(p, 2, revs); free(p); return 0; } @@ -405,14 +404,8 @@ static void do_oneway_diff(struct unpack_trees_options *o, /* if the entry is not checked out, don't examine work tree */ cached = o->index_only || (idx && ((idx->ce_flags & CE_VALID) || ce_skip_worktree(idx))); - /* - * Backward compatibility wart - "diff-index -m" does - * not mean "do not ignore merges", but "match_missing". - * - * But with the revision flag parsing, that's found in - * "!revs->ignore_merges". - */ - match_missing = !revs->ignore_merges; + + match_missing = revs->match_missing; if (cached && idx && ce_stage(idx)) { struct diff_filepair *pair; @@ -518,16 +511,74 @@ static int diff_cache(struct rev_info *revs, return unpack_trees(1, &t, &opts); } -int run_diff_index(struct rev_info *revs, int cached) +void diff_get_merge_base(const struct rev_info *revs, struct object_id *mb) +{ + int i; + struct commit *mb_child[2] = {0}; + struct commit_list *merge_bases; + + for (i = 0; i < revs->pending.nr; i++) { + struct object *obj = revs->pending.objects[i].item; + if (obj->flags) + die(_("--merge-base does not work with ranges")); + if (obj->type != OBJ_COMMIT) + die(_("--merge-base only works with commits")); + } + + /* + * This check must go after the for loop above because A...B + * ranges produce three pending commits, resulting in a + * misleading error message. + */ + if (revs->pending.nr < 1 || revs->pending.nr > 2) + BUG("unexpected revs->pending.nr: %d", revs->pending.nr); + + for (i = 0; i < revs->pending.nr; i++) + mb_child[i] = lookup_commit_reference(the_repository, &revs->pending.objects[i].item->oid); + if (revs->pending.nr == 1) { + struct object_id oid; + + if (get_oid("HEAD", &oid)) + die(_("unable to get HEAD")); + + mb_child[1] = lookup_commit_reference(the_repository, &oid); + } + + merge_bases = repo_get_merge_bases(the_repository, mb_child[0], mb_child[1]); + if (!merge_bases) + die(_("no merge base found")); + if (merge_bases->next) + die(_("multiple merge bases found")); + + oidcpy(mb, &merge_bases->item->object.oid); + + free_commit_list(merge_bases); +} + +int run_diff_index(struct rev_info *revs, unsigned int option) { struct object_array_entry *ent; + int cached = !!(option & DIFF_INDEX_CACHED); + int merge_base = !!(option & DIFF_INDEX_MERGE_BASE); + struct object_id oid; + const char *name; + char merge_base_hex[GIT_MAX_HEXSZ + 1]; if (revs->pending.nr != 1) BUG("run_diff_index must be passed exactly one tree"); trace_performance_enter(); ent = revs->pending.objects; - if (diff_cache(revs, &ent->item->oid, ent->name, cached)) + + if (merge_base) { + diff_get_merge_base(revs, &oid); + name = oid_to_hex_r(merge_base_hex, &oid); + } else { + oidcpy(&oid, &ent->item->oid); + name = ent->name; + } + + if (diff_cache(revs, &oid, name, cached)) exit(128); diff_set_mnemonic_prefix(&revs->diffopt, "c/", cached ? "i/" : "w/"); @@ -571,3 +622,28 @@ int index_differs_from(struct repository *r, object_array_clear(&rev.pending); return (rev.diffopt.flags.has_changes != 0); } + +static struct strbuf *idiff_prefix_cb(struct diff_options *opt, void *data) +{ + return data; +} + +void show_interdiff(const struct object_id *oid1, const struct object_id *oid2, + int indent, struct diff_options *diffopt) +{ + struct diff_options opts; + struct strbuf prefix = STRBUF_INIT; + + memcpy(&opts, diffopt, sizeof(opts)); + opts.output_format = DIFF_FORMAT_PATCH; + opts.output_prefix = idiff_prefix_cb; + strbuf_addchars(&prefix, ' ', indent); + opts.output_prefix_data = &prefix; + diff_setup_done(&opts); + + diff_tree_oid(oid1, oid2, "", &opts); + diffcore_std(&opts); + diff_flush(&opts); + + strbuf_release(&prefix); +} |