In a future commit, we will be using this function to implement --merge-base functionality in various diff commands. Signed-off-by: Denton Liu <liu.denton@xxxxxxxxx> --- diff-lib.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ diff.h | 2 ++ 2 files changed, 50 insertions(+) diff --git a/diff-lib.c b/diff-lib.c index 0a0e69113c..e01c3f0612 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 @@ -518,6 +519,53 @@ static int diff_cache(struct rev_info *revs, return unpack_trees(1, &t, &opts); } +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 > ARRAY_SIZE(mb_child)) + die(_("--merge-base does not work with more than two commits")); + + 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 < ARRAY_SIZE(mb_child)) { + struct object_id oid; + + if (revs->pending.nr != 1) + BUG("unexpected revs->pending.nr: %d", revs->pending.nr); + + 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; diff --git a/diff.h b/diff.h index 0cc874f2d5..ae2bb7001a 100644 --- a/diff.h +++ b/diff.h @@ -580,6 +580,8 @@ void diff_warn_rename_limit(const char *varname, int needed, int degraded_cc); */ const char *diff_aligned_abbrev(const struct object_id *sha1, int); +void diff_get_merge_base(const struct rev_info *revs, struct object_id *mb); + /* do not report anything on removed paths */ #define DIFF_SILENT_ON_REMOVED 01 /* report racily-clean paths as modified */ -- 2.28.0.618.gf4bc123cb7