summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2014-10-30 12:50:03 -0700
committerJunio C Hamano <gitster@pobox.com>2014-10-30 12:51:10 -0700
commit21912d8f23aca75ef9b6a5a3f5d937ef96ea7c68 (patch)
tree66663db9c89d5c5f872aee7c4f66827751a9a308
parent2ce406ccb85c4546b6d19309a6101b37c7bd952e (diff)
downloadgit-jc/first-parent-merge-bases.tar.gz
-rw-r--r--builtin/merge-base.c16
-rw-r--r--commit.c36
-rw-r--r--commit.h1
3 files changed, 35 insertions, 18 deletions
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index fdebef6fa1..19f77f4943 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -6,7 +6,8 @@
#include "revision.h"
#include "parse-options.h"
-static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
+static int show_merge_base(struct commit **rev, int rev_nr,
+ int show_all, int first_parent_only)
{
struct commit_list *result;
@@ -208,10 +209,13 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix)
struct commit **rev;
int rev_nr = 0;
int show_all = 0;
+ int first_parent_only = 0;
int cmdmode = 0;
struct option options[] = {
OPT_BOOL('a', "all", &show_all, N_("output all common ancestors")),
+ OPT_BOOL(0, "first-parent", &first_parent_only,
+ N_("traverse first-parent chain only")),
OPT_CMDMODE(0, "octopus", &cmdmode,
N_("find ancestors for a single n-way merge"), 'o'),
OPT_CMDMODE(0, "independent", &cmdmode,
@@ -234,8 +238,12 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix)
return handle_is_ancestor(argc, argv);
}
- if (cmdmode == 'r' && show_all)
- die("--independent cannot be used with --all");
+ if (cmdmode == 'r' && (show_all | first_parent_only))
+ die("--independent cannot be used with --all or --first-parent");
+ if (cmdmode == 'f' && (show_all | first_parent_only))
+ die("--fork-point cannot be used with --all or --first-parent");
+ if (cmdmode == 'o' && first_parent_only)
+ die("--octopus cannot be used with --first-parent");
if (cmdmode == 'o')
return handle_octopus(argc, argv, show_all);
@@ -255,5 +263,5 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix)
rev = xmalloc(argc * sizeof(*rev));
while (argc-- > 0)
rev[rev_nr++] = get_commit_reference(*argv++);
- return show_merge_base(rev, rev_nr, show_all);
+ return show_merge_base(rev, rev_nr, show_all, first_parent_only);
}
diff --git a/commit.c b/commit.c
index 8f9f37e3e6..abfd473795 100644
--- a/commit.c
+++ b/commit.c
@@ -783,7 +783,7 @@ static struct commit *interesting(struct commit_list *list)
}
/* all input commits in one and twos[] must have been parsed! */
-static struct commit_list *paint_down_to_common(struct commit *one, int n, struct commit **twos)
+static struct commit_list *paint_down_to_common(struct commit *one, int n, struct commit **twos, int first_parent_only)
{
struct commit_list *list = NULL;
struct commit_list *result = NULL;
@@ -821,7 +821,7 @@ static struct commit_list *paint_down_to_common(struct commit *one, int n, struc
parents = commit->parents;
while (parents) {
struct commit *p = parents->item;
- parents = parents->next;
+ parents = first_parent_only ? NULL : parents->next;
if ((p->object.flags & flags) == flags)
continue;
if (parse_commit(p))
@@ -835,7 +835,7 @@ static struct commit_list *paint_down_to_common(struct commit *one, int n, struc
return result;
}
-static struct commit_list *merge_bases_many(struct commit *one, int n, struct commit **twos)
+static struct commit_list *merge_bases_many(struct commit *one, int n, struct commit **twos, int first_parent_only)
{
struct commit_list *list = NULL;
struct commit_list *result = NULL;
@@ -857,7 +857,7 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co
return NULL;
}
- list = paint_down_to_common(one, n, twos);
+ list = paint_down_to_common(one, n, twos, first_parent_only);
while (list) {
struct commit_list *next = list->next;
@@ -896,7 +896,7 @@ struct commit_list *get_octopus_merge_bases(struct commit_list *in)
return ret;
}
-static int remove_redundant(struct commit **array, int cnt)
+static int remove_redundant(struct commit **array, int cnt, int first_parent_only)
{
/*
* Some commit in the array may be an ancestor of
@@ -926,7 +926,7 @@ static int remove_redundant(struct commit **array, int cnt)
filled_index[filled] = j;
work[filled++] = array[j];
}
- common = paint_down_to_common(array[i], filled, work);
+ common = paint_down_to_common(array[i], filled, work, first_parent_only);
if (array[i]->object.flags & PARENT2)
redundant[i] = 1;
for (j = 0; j < filled; j++)
@@ -955,14 +955,15 @@ static int remove_redundant(struct commit **array, int cnt)
static struct commit_list *get_merge_bases_many_0(struct commit *one,
int n,
struct commit **twos,
- int cleanup)
+ int cleanup,
+ int first_parent_only)
{
struct commit_list *list;
struct commit **rslt;
struct commit_list *result;
int cnt, i;
- result = merge_bases_many(one, n, twos);
+ result = merge_bases_many(one, n, twos, first_parent_only);
for (i = 0; i < n; i++) {
if (one == twos[i])
return result;
@@ -990,7 +991,7 @@ static struct commit_list *get_merge_bases_many_0(struct commit *one,
clear_commit_marks(one, all_flags);
clear_commit_marks_many(n, twos, all_flags);
- cnt = remove_redundant(rslt, cnt);
+ cnt = remove_redundant(rslt, cnt, first_parent_only);
result = NULL;
for (i = 0; i < cnt; i++)
commit_list_insert_by_date(rslt[i], &result);
@@ -1002,19 +1003,26 @@ struct commit_list *get_merge_bases_many(struct commit *one,
int n,
struct commit **twos)
{
- return get_merge_bases_many_0(one, n, twos, 1);
+ return get_merge_bases_many_0(one, n, twos, 1, 0);
}
struct commit_list *get_merge_bases_many_dirty(struct commit *one,
int n,
struct commit **twos)
{
- return get_merge_bases_many_0(one, n, twos, 0);
+ return get_merge_bases_many_0(one, n, twos, 0, 0);
+}
+
+struct commit_list *get_first_parent_merge_bases_many_dirty(struct commit *one,
+ int n,
+ struct commit **twos)
+{
+ return get_merge_bases_many_0(one, n, twos, 0, 1);
}
struct commit_list *get_merge_bases(struct commit *one, struct commit *two)
{
- return get_merge_bases_many_0(one, 1, &two, 1);
+ return get_merge_bases_many_0(one, 1, &two, 1, 0);
}
/*
@@ -1049,7 +1057,7 @@ int in_merge_bases_many(struct commit *commit, int nr_reference, struct commit *
if (parse_commit(reference[i]))
return ret;
- bases = paint_down_to_common(commit, nr_reference, reference);
+ bases = paint_down_to_common(commit, nr_reference, reference, 0);
if (commit->object.flags & PARENT2)
ret = 1;
clear_commit_marks(commit, all_flags);
@@ -1092,7 +1100,7 @@ struct commit_list *reduce_heads(struct commit_list *heads)
p->item->object.flags &= ~STALE;
}
}
- num_head = remove_redundant(array, num_head);
+ num_head = remove_redundant(array, num_head, 0);
for (i = 0; i < num_head; i++)
tail = &commit_list_insert(array[i], tail)->next;
return result;
diff --git a/commit.h b/commit.h
index 7cd4503581..169d8c070b 100644
--- a/commit.h
+++ b/commit.h
@@ -229,6 +229,7 @@ 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);
+extern struct commit_list *get_first_parent_merge_bases_many_dirty(struct commit *one, int n, struct commit **twos);
/* largest positive number a signed 32-bit integer can contain */
#define INFINITE_DEPTH 0x7fffffff