THIS PATCH SERIES IS NOT CODE-COMPLETE OR FULLY TESTED. See code comments beginning TODO for work remaining. Separate function handle_fork_point into one part that deals with command line arguments, printing error messages and exiting the process, and a second part that contains only the algorithm. The later part can be re-used elsewhere. Signed-off-by: Stephen Robin <stephen.robin@xxxxxxxxx> --- builtin.h | 2 ++ builtin/merge-base.c | 64 ++++++++++++++++++++++++++++++++-------------------- 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/builtin.h b/builtin.h index b87df70..d8e0e5a 100644 --- a/builtin.h +++ b/builtin.h @@ -27,6 +27,8 @@ extern int fmt_merge_msg(struct strbuf *in, struct strbuf *out, extern int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, int sha1_valid, char **buf, unsigned long *buf_size); +extern const unsigned char *get_fork_point(const char *refname, const unsigned char *derived_sha1); + extern int is_builtin(const char *s); extern int cmd_add(int argc, const char **argv, const char *prefix); diff --git a/builtin/merge-base.c b/builtin/merge-base.c index 08a8217..7a22cf1 100644 --- a/builtin/merge-base.c +++ b/builtin/merge-base.c @@ -145,30 +145,19 @@ static int collect_one_reflog_ent(unsigned char *osha1, unsigned char *nsha1, return 0; } -static int handle_fork_point(int argc, const char **argv) +const unsigned char *get_fork_point(const char *refname, const unsigned char *derived_sha1) { - unsigned char sha1[20]; - char *refname; - const char *commitname; + /* + * TODO I dislike exporting this function via builtin.h. I would prefer to + * move it to libgit if possible. + */ + unsigned const char *fork_point_sha1 = null_sha1; struct rev_collect revs; struct commit *derived; struct commit_list *bases; - int i, ret = 0; - - switch (dwim_ref(argv[0], strlen(argv[0]), sha1, &refname)) { - case 0: - die("No such ref: '%s'", argv[0]); - case 1: - break; /* good */ - default: - die("Ambiguous refname: '%s'", argv[0]); - } - - commitname = (argc == 2) ? argv[1] : "HEAD"; - if (get_sha1(commitname, sha1)) - die("Not a valid object name: '%s'", commitname); + int i; - derived = lookup_commit_reference(sha1); + derived = lookup_commit_reference(derived_sha1); memset(&revs, 0, sizeof(revs)); revs.initial = 1; for_each_reflog_ent(refname, collect_one_reflog_ent, &revs); @@ -182,25 +171,50 @@ static int handle_fork_point(int argc, const char **argv) * There should be one and only one merge base, when we found * a common ancestor among reflog entries. */ - if (!bases || bases->next) { - ret = 1; + if (!bases || bases->next) goto cleanup_return; - } /* And the found one must be one of the reflog entries */ for (i = 0; i < revs.nr; i++) if (&bases->item->object == &revs.commit[i]->object) break; /* found */ if (revs.nr <= i) { - ret = 1; /* not found */ + /* not found */ goto cleanup_return; } - printf("%s\n", sha1_to_hex(bases->item->object.sha1)); + fork_point_sha1 = bases->item->object.sha1; cleanup_return: free_commit_list(bases); - return ret; + return fork_point_sha1; +} + +static int handle_fork_point(int argc, const char **argv) +{ + unsigned char sha1[20]; + char *refname; + const char *commitname; + const unsigned char *fork_point_sha1; + + switch (dwim_ref(argv[0], strlen(argv[0]), sha1, &refname)) { + case 0: + die("No such ref: '%s'", argv[0]); + case 1: + break; /* good */ + default: + die("Ambiguous refname: '%s'", argv[0]); + } + + commitname = (argc == 2) ? argv[1] : "HEAD"; + if (get_sha1(commitname, sha1)) + die("Not a valid object name: '%s'", commitname); + + fork_point_sha1 = get_fork_point(refname, sha1); + if (!is_null_sha1(fork_point_sha1)) + printf("%s\n", sha1_to_hex(fork_point_sha1)); + + return is_null_sha1(fork_point_sha1); } int cmd_merge_base(int argc, const char **argv, const char *prefix) -- 2.4.0.7.gf20f26f -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html