diff --git a/builtin/diff.c b/builtin/diff.c index 9a89e25a982abb..28d44138091209 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -25,6 +25,7 @@ #include "setup.h" #include "oid-array.h" #include "tree.h" +#include "hex.h" #define DIFF_NO_INDEX_EXPLICIT 1 #define DIFF_NO_INDEX_IMPLICIT 2 @@ -170,14 +171,23 @@ static void builtin_diff_index(struct rev_info *revs, run_diff_index(revs, option); } +struct symdiff { + struct bitmap *skip; + int warn; + const char *base, *left, *right; + struct object_array_entry *ent0, *ent1; +}; + static void builtin_diff_tree(struct rev_info *revs, int argc, const char **argv, - struct object_array_entry *ent0, - struct object_array_entry *ent1) + struct object_array_entry *ent0, // I would rather encapsulate this with original object + struct object_array_entry *ent1, + struct symdiff *sdiff) { const struct object_id *(oid[2]); struct object_id mb_oid; int merge_base = 0; + const struct object_id *(r[2]); // oid closest to rev_info - tag/commit if known - corresponding to oid[] while (1 < argc) { const char *arg = argv[1]; @@ -192,6 +202,8 @@ static void builtin_diff_tree(struct rev_info *revs, diff_get_merge_base(revs, &mb_oid); oid[0] = &mb_oid; oid[1] = &revs->pending.objects[1].item->oid; + r[0] = oid[0]; + r[1] = oid[1]; } else { int swap = 0; @@ -203,9 +215,29 @@ static void builtin_diff_tree(struct rev_info *revs, swap = 1; oid[swap] = &ent0->item->oid; oid[1 - swap] = &ent1->item->oid; + + if (sdiff->skip) { // XXX symmetric diff will have 3+ revs; it's simplest to reuse the symdiff result + r[swap] = &sdiff->ent0->item->oid; + r[1 - swap] = &sdiff->ent1->item->oid; + } else { + // XXX assuming 2 revs, reach back up to commits + if (revs->pending.nr != 2) + BUG("unexpected revs->pending.nr: %d", revs->pending.nr); + r[swap] = &revs->pending.objects[0].item->oid; + r[1 - swap] = &revs->pending.objects[1].item->oid; + } } + + revs->diffopt.why.mode = "diff_tree"; + revs->diffopt.why.oid[0] = r[0]; + revs->diffopt.why.oid[1] = r[1]; + diff_tree_oid(oid[0], oid[1], "", &revs->diffopt); log_tree_diff_flush(revs); + + revs->diffopt.why.mode = NULL; + revs->diffopt.why.oid[0] = NULL; + revs->diffopt.why.oid[1] = NULL; } static void builtin_diff_combined(struct rev_info *revs, @@ -289,12 +321,6 @@ static void builtin_diff_files(struct rev_info *revs, int argc, const char **arg run_diff_files(revs, options); } -struct symdiff { - struct bitmap *skip; - int warn; - const char *base, *left, *right; -}; - /* * Check for symmetric-difference arguments, and if present, arrange * everything we need to know to handle them correctly. As a bonus, @@ -389,6 +415,8 @@ static void symdiff_prepare(struct rev_info *rev, struct symdiff *sym) bitmap_unset(map, basepos); /* unmark the base we want */ sym->warn = basecount > 1; sym->skip = map; + sym->ent0 = &rev->pending.objects[basepos]; + sym->ent1 = &rev->pending.objects[rpos]; } static void symdiff_release(struct symdiff *sdiff) @@ -621,7 +649,7 @@ int cmd_diff(int argc, warning(_("%s...%s: multiple merge bases, using %s"), sdiff.left, sdiff.right, sdiff.base); builtin_diff_tree(&rev, argc, argv, - &ent.objects[0], &ent.objects[1]); + &ent.objects[0], &ent.objects[1], &sdiff); } else builtin_diff_combined(&rev, argc, argv, ent.objects, ent.nr, diff --git a/diff.c b/diff.c index dca87e164fb615..2ac3bc6995125a 100644 --- a/diff.c +++ b/diff.c @@ -46,6 +46,7 @@ #include "setup.h" #include "strmap.h" #include "ws.h" +#include "hash.h" #ifdef NO_FAST_WORKING_DIRECTORY #define FAST_WORKING_DIRECTORY 0 @@ -4427,7 +4428,7 @@ static void run_external_diff(const struct external_diff *pgm, if (other) { strvec_push(&cmd.args, other); if (xfrm_msg) - strvec_push(&cmd.args, xfrm_msg); + strvec_push(&cmd.args, xfrm_msg); // XXX does this provide useful metadata? } } @@ -4435,6 +4436,16 @@ static void run_external_diff(const struct external_diff *pgm, ++o->diff_path_counter); strvec_pushf(&cmd.env, "GIT_DIFF_PATH_TOTAL=%d", q->nr); + if (o->why.oid[0] && o->why.oid[1]) { + strvec_pushf(&cmd.env, "GIT_DIFF_MODE=%s", o->why.mode); + + strvec_pushf(&cmd.env, "GIT_DIFF_REV_ONE=%s", oid_to_hex(o->why.oid[0])); + strvec_pushf(&cmd.env, "GIT_DIFF_REV_TWO=%s", oid_to_hex(o->why.oid[1])); + + strvec_pushf(&cmd.env, "GIT_DIFF_FILESPEC_PATH_ONE=%s", one->path); + strvec_pushf(&cmd.env, "GIT_DIFF_FILESPEC_PATH_TWO=%s", two->path); + } + diff_free_filespec_data(one); diff_free_filespec_data(two); cmd.use_shell = 1; diff --git a/diff.h b/diff.h index 62e5768a9a379e..2b25178b366022 100644 --- a/diff.h +++ b/diff.h @@ -404,6 +404,11 @@ struct diff_options { struct strmap *additional_path_headers; int no_free; + + struct why { + const char *mode; + const struct object_id *oid[2]; + } why; }; unsigned diff_filter_bit(char status);