merge-base --independent to print reduced parent list in a merge
authorJonathan Nieder <jrnieder@gmail.com>
Tue, 17 Aug 2010 07:01:54 +0000 (02:01 -0500)
committerJunio C Hamano <gitster@pobox.com>
Wed, 18 Aug 2010 21:02:03 +0000 (14:02 -0700)
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>
Documentation/git-merge-base.txt
builtin/merge-base.c
t/t6010-merge-base.sh

index 125207ef1edad16503545f457bba8525017c8b1a..eedef1bb1a14591d23b1fe6e93da1e3c2be2786b 100644 (file)
@@ -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
 -----------
@@ -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
 ----------
 
index c30128659f0e6edd9baf261e73c9da6b4a308964..96dd160731ce29b18be646893057929bab97cb8a 100644 (file)
@@ -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
 };
 
@@ -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;
@@ -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)
index 001431b36310813e0cd75d9aac364d72c8d0673d..62197a3d35f257dee6545d0f7768f21242e696ca 100755 (executable)
@@ -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
@@ -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
@@ -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.