Skip to content

Commit

Permalink
merge-base --independent to print reduced parent list in a merge
Browse files Browse the repository at this point in the history
While show-branch --independent does not support more than MAX_REVS
revs, git internally supports more with a different algorithm.
Expose that functionality as "git merge-base --independent".

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 aa8f98c commit a1e0ad7
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 7 deletions.
9 changes: 9 additions & 0 deletions Documentation/git-merge-base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ git-merge-base - Find as good common ancestors as possible for a merge

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

DESCRIPTION
-----------
Expand Down Expand Up @@ -42,6 +44,13 @@ OPTIONS
in preparation for an n-way merge. This mimics the behavior
of 'git show-branch --merge-base'.

--independent::
Instead of printing merge bases, print a minimal subset of
the supplied commits with the same ancestors. In other words,
among the commits given, list those which cannot be reached
from any other. This mimics the behavior of 'git show-branch
--independent'.

DISCUSSION
----------

Expand Down
21 changes: 15 additions & 6 deletions builtin/merge-base.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,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] [--octopus] <commit> <commit>...",
"git merge-base --independent <commit>...",
NULL
};

Expand All @@ -41,15 +42,19 @@ 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)
static int handle_octopus(int count, const char **args, int reduce, int show_all)
{
struct commit_list *revs = NULL;
struct commit_list *result;
int i;

for (i = count - 1; i >= 0; i++)
if (reduce)
show_all = 1;

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

result = reduce ? reduce_heads(revs) : get_octopus_merge_bases(revs);

if (!result)
return 1;
Expand All @@ -70,20 +75,24 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix)
int rev_nr = 0;
int show_all = 0;
int octopus = 0;
int reduce = 0;

struct option options[] = {
OPT_BOOLEAN('a', "all", &show_all, "output all common ancestors"),
OPT_BOOLEAN(0, "octopus", &octopus, "find ancestors for a single n-way merge"),
OPT_BOOLEAN(0, "independent", &reduce, "list revs not reachable from others"),
OPT_END()
};

git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options, merge_base_usage, 0);
if (!octopus && argc < 2)
if (!octopus && !reduce && argc < 2)
usage_with_options(merge_base_usage, options);
if (reduce && (show_all || octopus))
die("--independent cannot be used with other options");

if (octopus)
return show_octopus_merge_bases(argc, argv, show_all);
if (octopus || reduce)
return handle_octopus(argc, argv, reduce, show_all);

rev = xmalloc(argc * sizeof(*rev));
while (argc-- > 0)
Expand Down
39 changes: 38 additions & 1 deletion t/t6010-merge-base.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Copyright (c) 2005 Junio C Hamano
#

test_description='Merge base computation.
test_description='Merge base and parent list computation.
'

. ./test-lib.sh
Expand Down Expand Up @@ -75,6 +75,26 @@ test_expect_success 'merge-base G H' '
test_cmp expected actual.sb
'

test_expect_success 'merge-base/show-branch --independent' '
git name-rev "$H" >expected1 &&
git name-rev "$H" "$G" >expected2 &&
parents=$(git merge-base --independent H) &&
git name-rev $parents >actual1.mb &&
parents=$(git merge-base --independent A H G) &&
git name-rev $parents >actual2.mb &&
parents=$(git show-branch --independent H) &&
git name-rev $parents >actual1.sb &&
parents=$(git show-branch --independent A H G) &&
git name-rev $parents >actual2.sb &&
test_cmp expected1 actual1.mb &&
test_cmp expected2 actual2.mb &&
test_cmp expected1 actual1.sb &&
test_cmp expected2 actual2.sb
'

test_expect_success 'unsynchronized clocks' '
# This test is to demonstrate that relying on timestamps in a distributed
# SCM to provide a _consistent_ partial ordering of commits leads to
Expand Down Expand Up @@ -125,6 +145,23 @@ test_expect_success 'unsynchronized clocks' '
test_cmp expected actual.all
'

test_expect_success '--independent with unsynchronized clocks' '
IB=$(doit 0 IB) &&
I1=$(doit -10 I1 $IB) &&
I2=$(doit -9 I2 $I1) &&
I3=$(doit -8 I3 $I2) &&
I4=$(doit -7 I4 $I3) &&
I5=$(doit -6 I5 $I4) &&
I6=$(doit -5 I6 $I5) &&
I7=$(doit -4 I7 $I6) &&
I8=$(doit -3 I8 $I7) &&
IH=$(doit -2 IH $I8) &&
echo $IH >expected &&
git merge-base --independent IB IH >actual &&
test_cmp expected actual
'

test_expect_success 'merge-base for octopus-step (setup)' '
# Another set to demonstrate base between one commit and a merge
# in the documentation.
Expand Down

0 comments on commit a1e0ad7

Please sign in to comment.