Skip to content

Commit

Permalink
Merge branch 'mg/rev-list-n-parents'
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
gitster committed Mar 27, 2011
2 parents 8194fca + 482ce70 commit bf0c5bb
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 22 deletions.
4 changes: 4 additions & 0 deletions Documentation/git-rev-list.txt
Expand Up @@ -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 ]
Expand Down
19 changes: 17 additions & 2 deletions Documentation/rev-list-options.txt
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion builtin/log.c
Expand Up @@ -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));
Expand Down
4 changes: 4 additions & 0 deletions builtin/rev-list.c
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions builtin/rev-parse.c
Expand Up @@ -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",
Expand Down
2 changes: 2 additions & 0 deletions contrib/completion/git-completion.bash
Expand Up @@ -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="
Expand Down
28 changes: 21 additions & 7 deletions revision.c
Expand Up @@ -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;

Expand Down Expand Up @@ -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")) {
Expand All @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down
4 changes: 2 additions & 2 deletions revision.h
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down
118 changes: 108 additions & 10 deletions t/t6009-rev-list-parent.sh
@@ -1,28 +1,29 @@
#!/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 '
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
'
Expand All @@ -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

0 comments on commit bf0c5bb

Please sign in to comment.