From ad5aeeded3295589b2573b143f754762a56f8f82 Mon Sep 17 00:00:00 2001 From: Michael J Gruber Date: Mon, 21 Mar 2011 11:14:06 +0100 Subject: [PATCH] revision.c: introduce --min-parents and --max-parents options Introduce --min-parents and --max-parents options which limit the revisions to those commits which have at least (or at most) that many commits, where negative arguments for --max-parents= denote infinity (i.e. no upper limit). In particular: --max-parents=1 is the same as --no-merges; --min-parents=2 is the same as --merges; --max-parents=0 shows only roots; and --min-parents=3 shows only octopus merges Using --min-parents=n and --max-parents=m with n>m gives you what you ask for (i.e. nothing) for obvious reasons, just like when you give --merges (show only merge commits) and --no-merges (show only non-merge commits) at the same time. Also, introduce --no-min-parents and --no-max-parents to do the obvious thing for convenience. We compute the number of parents only when we limit by that, so there is no performance impact when there are no limiters. Signed-off-by: Michael J Gruber Signed-off-by: Junio C Hamano --- builtin/log.c | 2 +- builtin/rev-list.c | 4 ++++ builtin/rev-parse.c | 4 ++++ revision.c | 28 +++++++++++++++++++++------- revision.h | 4 ++-- 5 files changed, 32 insertions(+), 10 deletions(-) diff --git a/builtin/log.c b/builtin/log.c index d8c6c28d2f..669796d7b2 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -1055,7 +1055,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)); diff --git a/builtin/rev-list.c b/builtin/rev-list.c index f458cb7587..9bfb94201f 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -16,6 +16,10 @@ static const char rev_list_usage[] = " --min-age=\n" " --sparse\n" " --no-merges\n" +" --min-parents=\n" +" --no-min-parents\n" +" --max-parents=\n" +" --no-max-parents\n" " --remove-empty\n" " --all\n" " --branches\n" diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index a5a1c86e92..adb1cae4f2 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -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", diff --git a/revision.c b/revision.c index 626f6a23d1..8540a5d2f1 100644 --- a/revision.c +++ b/revision.c @@ -945,6 +945,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; @@ -1280,9 +1281,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")) { @@ -1301,7 +1310,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; @@ -2032,10 +2041,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) { diff --git a/revision.h b/revision.h index 1c0abf0f58..8214a55348 100644 --- a/revision.h +++ b/revision.h @@ -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;