merge-base --octopus to mimic show-branch --merge-base

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>
This commit is contained in:
Jonathan Nieder
2010-08-17 02:01:15 -05:00
committed by Junio C Hamano
parent 1846e9edf6
commit aa8f98c1bf
3 changed files with 46 additions and 10 deletions

View File

@ -8,7 +8,7 @@ git-merge-base - Find as good common ancestors as possible for a merge
SYNOPSIS SYNOPSIS
-------- --------
'git merge-base' [-a|--all] <commit> <commit>... 'git merge-base' [-a|--all] [--octopus] <commit> <commit>...
DESCRIPTION DESCRIPTION
----------- -----------
@ -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 ancestor', i.e. a 'merge base'. Note that there can be more than one
merge base for a pair of commits. merge base for a pair of commits.
Among the two commits to compute the merge base from, one is specified by Unless `--octopus` is given, among the two commits to compute the merge
the first commit argument on the command line; the other commit is a base from, one is specified by the first commit argument on the command
(possibly hypothetical) commit that is a merge across all the remaining line; the other commit is a (possibly hypothetical) commit that is a merge
commits on the command line. As the most common special case, specifying only across all the remaining commits on the command line. As the most common
two commits on the command line means computing the merge base between special case, specifying only two commits on the command line means
the given two commits. computing the merge base between the given two commits.
As a consequence, the 'merge base' is not necessarily contained in each of the 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 commit arguments if more than two commits are specified. This is different
@ -37,6 +37,11 @@ OPTIONS
--all:: --all::
Output all merge bases for the commits, instead of just one. 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 DISCUSSION
---------- ----------

View File

@ -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[] = { static const char * const merge_base_usage[] = {
"git merge-base [-a|--all] <commit> <commit>...", "git merge-base [-a|--all] [--octopus] <commit> <commit>...",
NULL NULL
}; };
@ -41,21 +41,50 @@ static struct commit *get_commit_reference(const char *arg)
return r; 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) int cmd_merge_base(int argc, const char **argv, const char *prefix)
{ {
struct commit **rev; struct commit **rev;
int rev_nr = 0; int rev_nr = 0;
int show_all = 0; int show_all = 0;
int octopus = 0;
struct option options[] = { 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() OPT_END()
}; };
git_config(git_default_config, NULL); git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options, merge_base_usage, 0); 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); usage_with_options(merge_base_usage, options);
if (octopus)
return show_octopus_merge_bases(argc, argv, show_all);
rev = xmalloc(argc * sizeof(*rev)); rev = xmalloc(argc * sizeof(*rev));
while (argc-- > 0) while (argc-- > 0)
rev[rev_nr++] = get_commit_reference(*argv++); rev[rev_nr++] = get_commit_reference(*argv++);

View File

@ -164,9 +164,11 @@ test_expect_success 'merge-base A B C' '
git rev-parse --verify MMR >expected.sb && git rev-parse --verify MMR >expected.sb &&
git merge-base --all MMA MMB MMC >actual && 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 && git show-branch --merge-base MMA MMB MMC >actual.sb &&
test_cmp expected actual && test_cmp expected actual &&
test_cmp expected.sb actual.common &&
test_cmp expected.sb actual.sb test_cmp expected.sb actual.sb
' '