]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'mg/rev-list-n-parents'
authorJunio C Hamano <gitster@pobox.com>
Sun, 27 Mar 2011 03:13:17 +0000 (20:13 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sun, 27 Mar 2011 03:13:17 +0000 (20:13 -0700)
* mg/rev-list-n-parents:
  tests: avoid nonportable {foo,bar} glob
  rev-list --min-parents,--max-parents: doc, test and completion
  revision.c: introduce --min-parents and --max-parents options
  t6009: use test_commit() from test-lib.sh

Documentation/git-rev-list.txt
Documentation/rev-list-options.txt
builtin/log.c
builtin/rev-list.c
builtin/rev-parse.c
contrib/completion/git-completion.bash
revision.c
revision.h
t/t6009-rev-list-parent.sh

index b08dfbc3c455a19b3257e7e921c2a1a7436ddf3e..415f4f0b303da22e9eec19c1b9e24732a74ecf67 100644 (file)
@@ -16,6 +16,10 @@ SYNOPSIS
             [ \--sparse ]
             [ \--merges ]
             [ \--no-merges ]
+            [ \--min-parents=<number> ]
+            [ \--no-min-parents ]
+            [ \--max-parents=<number> ]
+            [ \--no-max-parents ]
             [ \--first-parent ]
             [ \--remove-empty ]
             [ \--full-history ]
index 5c6850f0486dbea0c515e2323bc6455d89897628..ea5c6c49bd1b673aba48c057add1b5d15ae840a0 100644 (file)
@@ -72,11 +72,26 @@ endif::git-rev-list[]
 
 --merges::
 
-       Print only merge commits.
+       Print only merge commits. This is exactly the same as `--min-parents=2`.
 
 --no-merges::
 
-       Do not print commits with more than one parent.
+       Do not print commits with more than one parent. This is
+       exactly the same as `--max-parents=1`.
+
+--min-parents=<number>::
+--max-parents=<number>::
+--no-min-parents::
+--no-max-parents::
+
+       Show only commits which have at least (or at most) that many
+       commits. In particular, `--max-parents=1` is the same as `--no-merges`,
+       `--min-parents=2` is the same as `--merges`.  `--max-parents=0`
+       gives all root commits and `--min-parents=3` all octopus merges.
++
+`--no-min-parents` and `--no-max-parents` reset these limits (to no limit)
+again.  Equivalent forms are `--min-parents=0` (any commit has 0 or more
+parents) and `--max-parents=-1` (negative numbers denote no upper limit).
 
 --first-parent::
        Follow only the first parent commit upon seeing a merge
index 796e9e57460468748d1e2af975ac52a6470a379d..4a0f78dc7139ac529e60e7e1099834ff7efe1163 100644 (file)
@@ -1061,7 +1061,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        rev.commit_format = CMIT_FMT_EMAIL;
        rev.verbose_header = 1;
        rev.diff = 1;
-       rev.no_merges = 1;
+       rev.max_parents = 1;
        DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
        rev.subject_prefix = fmt_patch_subject_prefix;
        memset(&s_r_opt, 0, sizeof(s_r_opt));
index f458cb7587c7d40cf93d42d73379fac485ee3889..9bfb94201f298f5902c6da13b12f4ca539bb86ed 100644 (file)
@@ -16,6 +16,10 @@ static const char rev_list_usage[] =
 "    --min-age=<epoch>\n"
 "    --sparse\n"
 "    --no-merges\n"
+"    --min-parents=<n>\n"
+"    --no-min-parents\n"
+"    --max-parents=<n>\n"
+"    --no-max-parents\n"
 "    --remove-empty\n"
 "    --all\n"
 "    --branches\n"
index a5a1c86e92720e8beefd8275acfc5df2dbdce175..adb1cae4f27ad3993aa2418f7b0fd355d19cdab9 100644 (file)
@@ -48,6 +48,10 @@ static int is_rev_argument(const char *arg)
                "--max-count=",
                "--min-age=",
                "--no-merges",
+               "--min-parents=",
+               "--no-min-parents",
+               "--max-parents=",
+               "--no-max-parents",
                "--objects",
                "--objects-edge",
                "--parents",
index 1b589fadbb5dd94827cf1565bce232d0f3a3c42a..840ae38760a5de84b369b208a52cc579ce478378 100755 (executable)
@@ -1577,6 +1577,8 @@ __git_log_common_options="
        --max-count=
        --max-age= --since= --after=
        --min-age= --until= --before=
+       --min-parents= --max-parents=
+       --no-min-parents --no-max-parents
 "
 # Options that go well for log and gitk (not shortlog)
 __git_log_gitk_options="
index e96c281d1f04f37e519e9447e18e43b86cb2363a..0f38364cf3f81a9088305ca802adf8b7c9260e91 100644 (file)
@@ -941,6 +941,7 @@ void init_revisions(struct rev_info *revs, const char *prefix)
        revs->min_age = -1;
        revs->skip_count = -1;
        revs->max_count = -1;
+       revs->max_parents = -1;
 
        revs->commit_format = CMIT_FMT_DEFAULT;
 
@@ -1277,9 +1278,17 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
        } else if (!strcmp(arg, "--remove-empty")) {
                revs->remove_empty_trees = 1;
        } else if (!strcmp(arg, "--merges")) {
-               revs->merges_only = 1;
+               revs->min_parents = 2;
        } else if (!strcmp(arg, "--no-merges")) {
-               revs->no_merges = 1;
+               revs->max_parents = 1;
+       } else if (!prefixcmp(arg, "--min-parents=")) {
+               revs->min_parents = atoi(arg+14);
+       } else if (!prefixcmp(arg, "--no-min-parents")) {
+               revs->min_parents = 0;
+       } else if (!prefixcmp(arg, "--max-parents=")) {
+               revs->max_parents = atoi(arg+14);
+       } else if (!prefixcmp(arg, "--no-max-parents")) {
+               revs->max_parents = -1;
        } else if (!strcmp(arg, "--boundary")) {
                revs->boundary = 1;
        } else if (!strcmp(arg, "--left-right")) {
@@ -1298,7 +1307,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
                        die("--cherry is incompatible with --left-only");
                revs->cherry_mark = 1;
                revs->right_only = 1;
-               revs->no_merges = 1;
+               revs->max_parents = 1;
                revs->limited = 1;
        } else if (!strcmp(arg, "--count")) {
                revs->count = 1;
@@ -2029,10 +2038,15 @@ enum commit_action get_commit_action(struct rev_info *revs, struct commit *commi
                return commit_ignore;
        if (revs->min_age != -1 && (commit->date > revs->min_age))
                return commit_ignore;
-       if (revs->no_merges && commit->parents && commit->parents->next)
-               return commit_ignore;
-       if (revs->merges_only && !(commit->parents && commit->parents->next))
-               return commit_ignore;
+       if (revs->min_parents || (revs->max_parents >= 0)) {
+               int n = 0;
+               struct commit_list *p;
+               for (p = commit->parents; p; p = p->next)
+                       n++;
+               if ((n < revs->min_parents) ||
+                   ((revs->max_parents >= 0) && (n > revs->max_parents)))
+                       return commit_ignore;
+       }
        if (!commit_match(commit, revs))
                return commit_ignore;
        if (revs->prune && revs->dense) {
index ae948601f94c726c3677f23517dba5c046431904..9fd8f3016fe8f935f176f57c615f72df8ba8d157 100644 (file)
@@ -41,8 +41,6 @@ struct rev_info {
        /* Traversal flags */
        unsigned int    dense:1,
                        prune:1,
-                       no_merges:1,
-                       merges_only:1,
                        no_walk:1,
                        show_all:1,
                        remove_empty_trees:1,
@@ -126,6 +124,8 @@ struct rev_info {
        int max_count;
        unsigned long max_age;
        unsigned long min_age;
+       int min_parents;
+       int max_parents;
 
        /* diff info for patches and for paths limiting */
        struct diff_options diffopt;
index 52f7b277ceae3ae183bc6082c01af9f76bd39a86..30507407ff6375f96c632c7c3f62ae3d338ed5ea 100755 (executable)
@@ -1,14 +1,15 @@
 #!/bin/sh
 
-test_description='properly cull all ancestors'
+test_description='ancestor culling and limiting by parent number'
 
 . ./test-lib.sh
 
-commit () {
-       test_tick &&
-       echo $1 >file &&
-       git commit -a -m $1 &&
-       git tag $1
+check_revlist () {
+       rev_list_args="$1" &&
+       shift &&
+       git rev-parse "$@" >expect &&
+       git rev-list $rev_list_args --all >actual &&
+       test_cmp expect actual
 }
 
 test_expect_success setup '
@@ -16,13 +17,13 @@ test_expect_success setup '
        touch file &&
        git add file &&
 
-       commit one &&
+       test_commit one &&
 
        test_tick=$(($test_tick - 2400)) &&
 
-       commit two &&
-       commit three &&
-       commit four &&
+       test_commit two &&
+       test_commit three &&
+       test_commit four &&
 
        git log --pretty=oneline --abbrev-commit
 '
@@ -35,4 +36,101 @@ test_expect_success 'one is ancestor of others and should not be shown' '
 
 '
 
+test_expect_success 'setup roots, merges and octopuses' '
+
+       git checkout --orphan newroot &&
+       test_commit five &&
+       git checkout -b sidebranch two &&
+       test_commit six &&
+       git checkout -b anotherbranch three &&
+       test_commit seven &&
+       git checkout -b yetanotherbranch four &&
+       test_commit eight &&
+       git checkout master &&
+       test_merge normalmerge newroot &&
+       test_tick &&
+       git merge -m tripus sidebranch anotherbranch &&
+       git tag tripus &&
+       git checkout -b tetrabranch normalmerge &&
+       test_tick &&
+       git merge -m tetrapus sidebranch anotherbranch yetanotherbranch &&
+       git tag tetrapus &&
+       git checkout master
+'
+
+test_expect_success 'rev-list roots' '
+
+       check_revlist "--max-parents=0" one five
+'
+
+test_expect_success 'rev-list no merges' '
+
+       check_revlist "--max-parents=1" one eight seven six five four three two &&
+       check_revlist "--no-merges" one eight seven six five four three two
+'
+
+test_expect_success 'rev-list no octopuses' '
+
+       check_revlist "--max-parents=2" one normalmerge eight seven six five four three two
+'
+
+test_expect_success 'rev-list no roots' '
+
+       check_revlist "--min-parents=1" tetrapus tripus normalmerge eight seven six four three two
+'
+
+test_expect_success 'rev-list merges' '
+
+       check_revlist "--min-parents=2" tetrapus tripus normalmerge &&
+       check_revlist "--merges" tetrapus tripus normalmerge
+'
+
+test_expect_success 'rev-list octopus' '
+
+       check_revlist "--min-parents=3" tetrapus tripus
+'
+
+test_expect_success 'rev-list ordinary commits' '
+
+       check_revlist "--min-parents=1 --max-parents=1" eight seven six four three two
+'
+
+test_expect_success 'rev-list --merges --no-merges yields empty set' '
+
+       check_revlist "--min-parents=2 --no-merges" &&
+       check_revlist "--merges --no-merges" &&
+       check_revlist "--no-merges --merges"
+'
+
+test_expect_success 'rev-list override and infinities' '
+
+       check_revlist "--min-parents=2 --max-parents=1 --max-parents=3" tripus normalmerge &&
+       check_revlist "--min-parents=1 --min-parents=2 --max-parents=7" tetrapus tripus normalmerge &&
+       check_revlist "--min-parents=2 --max-parents=8" tetrapus tripus normalmerge &&
+       check_revlist "--min-parents=2 --max-parents=-1" tetrapus tripus normalmerge &&
+       check_revlist "--min-parents=2 --no-max-parents" tetrapus tripus normalmerge &&
+       check_revlist "--max-parents=0 --min-parents=1 --no-min-parents" one five
+'
+
+test_expect_success 'dodecapus' '
+
+       roots= &&
+       for i in 1 2 3 4 5 6 7 8 9 10 11
+       do
+               git checkout -b root$i five &&
+               test_commit $i &&
+               roots="$roots root$i" ||
+               return
+       done &&
+       git checkout master &&
+       test_tick &&
+       git merge -m dodecapus $roots &&
+       git tag dodecapus &&
+
+       check_revlist "--min-parents=4" dodecapus tetrapus &&
+       check_revlist "--min-parents=8" dodecapus &&
+       check_revlist "--min-parents=12" dodecapus &&
+       check_revlist "--min-parents=13" &&
+       check_revlist "--min-parents=4 --max-parents=11" tetrapus
+'
 test_done