Skip to content

Commit

Permalink
merge-base --octopus to mimic show-branch --merge-base
Browse files Browse the repository at this point in the history
While show-branch --merge-base does not support more than MAX_REVS
revs, git supports more with a different algorithm
(v1.6.0-rc0~51^2~13, Introduce get_octopus_merge_bases() in commit.c,
2008-06-27).  Expose that functionality.

This should help scripts to catch up with builtin merge in supporting
dodecapus.

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Jonathan Nieder authored and Junio C Hamano committed Aug 18, 2010
1 parent 1846e9e commit aa8f98c
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 10 deletions.
19 changes: 12 additions & 7 deletions Documentation/git-merge-base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ git-merge-base - Find as good common ancestors as possible for a merge

SYNOPSIS
--------
'git merge-base' [-a|--all] <commit> <commit>...
'git merge-base' [-a|--all] [--octopus] <commit> <commit>...

DESCRIPTION
-----------
Expand All @@ -20,12 +20,12 @@ that does not have any better common ancestor is a 'best common
ancestor', i.e. a 'merge base'. Note that there can be more than one
merge base for a pair of commits.

Among the two commits to compute the merge base from, one is specified by
the first commit argument on the command line; the other commit is a
(possibly hypothetical) commit that is a merge across all the remaining
commits on the command line. As the most common special case, specifying only
two commits on the command line means computing the merge base between
the given two commits.
Unless `--octopus` is given, among the two commits to compute the merge
base from, one is specified by the first commit argument on the command
line; the other commit is a (possibly hypothetical) commit that is a merge
across all the remaining commits on the command line. As the most common
special case, specifying only two commits on the command line means
computing the merge base between the given two commits.

As a consequence, the 'merge base' is not necessarily contained in each of the
commit arguments if more than two commits are specified. This is different
Expand All @@ -37,6 +37,11 @@ OPTIONS
--all::
Output all merge bases for the commits, instead of just one.

--octopus::
Compute the best common ancestors of all supplied commits,
in preparation for an n-way merge. This mimics the behavior
of 'git show-branch --merge-base'.

DISCUSSION
----------

Expand Down
35 changes: 32 additions & 3 deletions builtin/merge-base.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
}

static const char * const merge_base_usage[] = {
"git merge-base [-a|--all] <commit> <commit>...",
"git merge-base [-a|--all] [--octopus] <commit> <commit>...",
NULL
};

Expand All @@ -41,21 +41,50 @@ static struct commit *get_commit_reference(const char *arg)
return r;
}

static int show_octopus_merge_bases(int count, const char **args, int show_all)
{
struct commit_list *revs = NULL;
struct commit_list *result;
int i;

for (i = count - 1; i >= 0; i++)
commit_list_insert(get_commit_reference(args[i]), &revs);
result = get_octopus_merge_bases(revs);

if (!result)
return 1;

while (result) {
printf("%s\n", sha1_to_hex(result->item->object.sha1));
if (!show_all)
return 0;
result = result->next;
}

return 0;
}

int cmd_merge_base(int argc, const char **argv, const char *prefix)
{
struct commit **rev;
int rev_nr = 0;
int show_all = 0;
int octopus = 0;

struct option options[] = {
OPT_BOOLEAN('a', "all", &show_all, "outputs all common ancestors"),
OPT_BOOLEAN('a', "all", &show_all, "output all common ancestors"),
OPT_BOOLEAN(0, "octopus", &octopus, "find ancestors for a single n-way merge"),
OPT_END()
};

git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options, merge_base_usage, 0);
if (argc < 2)
if (!octopus && argc < 2)
usage_with_options(merge_base_usage, options);

if (octopus)
return show_octopus_merge_bases(argc, argv, show_all);

rev = xmalloc(argc * sizeof(*rev));
while (argc-- > 0)
rev[rev_nr++] = get_commit_reference(*argv++);
Expand Down
2 changes: 2 additions & 0 deletions t/t6010-merge-base.sh
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,11 @@ test_expect_success 'merge-base A B C' '
git rev-parse --verify MMR >expected.sb &&
git merge-base --all MMA MMB MMC >actual &&
git merge-base --all --octopus MMA MMB MMC >actual.common &&
git show-branch --merge-base MMA MMB MMC >actual.sb &&
test_cmp expected actual &&
test_cmp expected.sb actual.common &&
test_cmp expected.sb actual.sb
'

Expand Down

0 comments on commit aa8f98c

Please sign in to comment.