summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtin/merge-base.c81
-rw-r--r--commit.c81
-rw-r--r--commit.h2
3 files changed, 89 insertions, 75 deletions
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index 08d91b1..790ceae 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -110,54 +110,12 @@ static int handle_is_ancestor(int argc, const char **argv)
return 1;
}
-struct rev_collect {
- struct commit **commit;
- int nr;
- int alloc;
- unsigned int initial : 1;
-};
-
-static void add_one_commit(struct object_id *oid, struct rev_collect *revs)
-{
- struct commit *commit;
-
- if (is_null_oid(oid))
- return;
-
- commit = lookup_commit(the_repository, oid);
- if (!commit ||
- (commit->object.flags & TMP_MARK) ||
- parse_commit(commit))
- return;
-
- ALLOC_GROW(revs->commit, revs->nr + 1, revs->alloc);
- revs->commit[revs->nr++] = commit;
- commit->object.flags |= TMP_MARK;
-}
-
-static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid,
- const char *ident, timestamp_t timestamp,
- int tz, const char *message, void *cbdata)
-{
- struct rev_collect *revs = cbdata;
-
- if (revs->initial) {
- revs->initial = 0;
- add_one_commit(ooid, revs);
- }
- add_one_commit(noid, revs);
- return 0;
-}
-
static int handle_fork_point(int argc, const char **argv)
{
struct object_id oid;
char *refname;
+ struct commit *derived, *fork_point;
const char *commitname;
- struct rev_collect revs;
- struct commit *derived;
- struct commit_list *bases;
- int i, ret = 0;
switch (dwim_ref(argv[0], strlen(argv[0]), &oid, &refname)) {
case 0:
@@ -173,41 +131,14 @@ static int handle_fork_point(int argc, const char **argv)
die("Not a valid object name: '%s'", commitname);
derived = lookup_commit_reference(the_repository, &oid);
- memset(&revs, 0, sizeof(revs));
- revs.initial = 1;
- for_each_reflog_ent(refname, collect_one_reflog_ent, &revs);
- if (!revs.nr && !get_oid(refname, &oid))
- add_one_commit(&oid, &revs);
+ fork_point = get_fork_point(refname, derived);
- for (i = 0; i < revs.nr; i++)
- revs.commit[i]->object.flags &= ~TMP_MARK;
-
- bases = get_merge_bases_many_dirty(derived, revs.nr, revs.commit);
-
- /*
- * There should be one and only one merge base, when we found
- * a common ancestor among reflog entries.
- */
- if (!bases || bases->next) {
- ret = 1;
- 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 */
- goto cleanup_return;
- }
-
- printf("%s\n", oid_to_hex(&bases->item->object.oid));
+ if (!fork_point)
+ return 1;
-cleanup_return:
- free_commit_list(bases);
- return ret;
+ printf("%s\n", oid_to_hex(&fork_point->object.oid));
+ return 0;
}
int cmd_merge_base(int argc, const char **argv, const char *prefix)
diff --git a/commit.c b/commit.c
index 30d1af2..a3fc77a 100644
--- a/commit.c
+++ b/commit.c
@@ -17,6 +17,7 @@
#include "sha1-lookup.h"
#include "wt-status.h"
#include "advice.h"
+#include "refs.h"
static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
@@ -958,6 +959,86 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co
return result;
}
+struct rev_collect {
+ struct commit **commit;
+ int nr;
+ int alloc;
+ unsigned int initial : 1;
+};
+
+static void add_one_commit(struct object_id *oid, struct rev_collect *revs)
+{
+ struct commit *commit;
+
+ if (is_null_oid(oid))
+ return;
+
+ commit = lookup_commit(the_repository, oid);
+ if (!commit ||
+ (commit->object.flags & TMP_MARK) ||
+ parse_commit(commit))
+ return;
+
+ ALLOC_GROW(revs->commit, revs->nr + 1, revs->alloc);
+ revs->commit[revs->nr++] = commit;
+ commit->object.flags |= TMP_MARK;
+}
+
+static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid,
+ const char *ident, timestamp_t timestamp,
+ int tz, const char *message, void *cbdata)
+{
+ struct rev_collect *revs = cbdata;
+
+ if (revs->initial) {
+ revs->initial = 0;
+ add_one_commit(ooid, revs);
+ }
+ add_one_commit(noid, revs);
+ return 0;
+}
+
+struct commit *get_fork_point(const char *refname, struct commit *commit)
+{
+ struct object_id oid;
+ struct rev_collect revs;
+ struct commit_list *bases;
+ int i;
+ struct commit *ret = NULL;
+
+ memset(&revs, 0, sizeof(revs));
+ revs.initial = 1;
+ for_each_reflog_ent(refname, collect_one_reflog_ent, &revs);
+
+ if (!revs.nr && !get_oid(refname, &oid))
+ add_one_commit(&oid, &revs);
+
+ for (i = 0; i < revs.nr; i++)
+ revs.commit[i]->object.flags &= ~TMP_MARK;
+
+ bases = get_merge_bases_many(commit, revs.nr, revs.commit);
+
+ /*
+ * There should be one and only one merge base, when we found
+ * a common ancestor among reflog entries.
+ */
+ 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)
+ goto cleanup_return;
+
+ ret = bases->item;
+
+cleanup_return:
+ free_commit_list(bases);
+ return ret;
+}
+
struct commit_list *get_octopus_merge_bases(struct commit_list *in)
{
struct commit_list *i, *j, *k, *ret = NULL;
diff --git a/commit.h b/commit.h
index da0db36..b342400 100644
--- a/commit.h
+++ b/commit.h
@@ -211,6 +211,8 @@ extern struct commit_list *get_octopus_merge_bases(struct commit_list *in);
/* To be used only when object flags after this call no longer matter */
extern struct commit_list *get_merge_bases_many_dirty(struct commit *one, int n, struct commit **twos);
+struct commit *get_fork_point(const char *refname, struct commit *commit);
+
/* largest positive number a signed 32-bit integer can contain */
#define INFINITE_DEPTH 0x7fffffff