diff options
Diffstat (limited to 'revision.c')
-rw-r--r-- | revision.c | 280 |
1 files changed, 193 insertions, 87 deletions
diff --git a/revision.c b/revision.c index 17f9fcb966..7934b2f68b 100644 --- a/revision.c +++ b/revision.c @@ -535,6 +535,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs) int left_count = 0, right_count = 0; int left_first; struct patch_ids ids; + unsigned cherry_flag; /* First count the commits on the left and on the right */ for (p = list; p; p = p->next) { @@ -572,6 +573,9 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs) commit->util = add_commit_patch_id(commit, &ids); } + /* either cherry_mark or cherry_pick are true */ + cherry_flag = revs->cherry_mark ? PATCHSAME : SHOWN; + /* Check the other side */ for (p = list; p; p = p->next) { struct commit *commit = p->item; @@ -594,7 +598,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs) if (!id) continue; id->seen = 1; - commit->object.flags |= SHOWN; + commit->object.flags |= cherry_flag; } /* Now check the original side for seen ones */ @@ -606,7 +610,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs) if (!ent) continue; if (ent->seen) - commit->object.flags |= SHOWN; + commit->object.flags |= cherry_flag; commit->util = NULL; } @@ -729,6 +733,23 @@ static struct commit_list *collect_bottom_commits(struct commit_list *list) return bottom; } +/* Assumes either left_only or right_only is set */ +static void limit_left_right(struct commit_list *list, struct rev_info *revs) +{ + struct commit_list *p; + + for (p = list; p; p = p->next) { + struct commit *commit = p->item; + + if (revs->right_only) { + if (commit->object.flags & SYMMETRIC_LEFT) + commit->object.flags |= SHOWN; + } else /* revs->left_only is set */ + if (!(commit->object.flags & SYMMETRIC_LEFT)) + commit->object.flags |= SHOWN; + } +} + static int limit_list(struct rev_info *revs) { int slop = SLOP; @@ -781,9 +802,12 @@ static int limit_list(struct rev_info *revs) show(revs, newlist); show_early_output = NULL; } - if (revs->cherry_pick) + if (revs->cherry_pick || revs->cherry_mark) cherry_pick_list(newlist, revs); + if (revs->left_only || revs->right_only) + limit_left_right(newlist, revs); + if (bottom) { limit_to_ancestry(bottom, newlist); free_commit_list(bottom); @@ -917,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; @@ -930,6 +955,8 @@ void init_revisions(struct rev_info *revs, const char *prefix) revs->diffopt.prefix = prefix; revs->diffopt.prefix_length = strlen(prefix); } + + revs->notes_opt.use_default_notes = -1; } static void add_pending_commit_list(struct rev_info *revs, @@ -1152,7 +1179,9 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg !strcmp(arg, "--tags") || !strcmp(arg, "--remotes") || !strcmp(arg, "--reflog") || !strcmp(arg, "--not") || !strcmp(arg, "--no-walk") || !strcmp(arg, "--do-walk") || - !strcmp(arg, "--bisect")) + !strcmp(arg, "--bisect") || !prefixcmp(arg, "--glob=") || + !prefixcmp(arg, "--branches=") || !prefixcmp(arg, "--tags=") || + !prefixcmp(arg, "--remotes=")) { unkv[(*unkc)++] = arg; return 1; @@ -1252,16 +1281,47 @@ 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")) { revs->left_right = 1; + } else if (!strcmp(arg, "--left-only")) { + if (revs->right_only) + die("--left-only is incompatible with --right-only" + " or --cherry"); + revs->left_only = 1; + } else if (!strcmp(arg, "--right-only")) { + if (revs->left_only) + die("--right-only is incompatible with --left-only"); + revs->right_only = 1; + } else if (!strcmp(arg, "--cherry")) { + if (revs->left_only) + die("--cherry is incompatible with --left-only"); + revs->cherry_mark = 1; + revs->right_only = 1; + revs->max_parents = 1; + revs->limited = 1; } else if (!strcmp(arg, "--count")) { revs->count = 1; + } else if (!strcmp(arg, "--cherry-mark")) { + if (revs->cherry_pick) + die("--cherry-mark is incompatible with --cherry-pick"); + revs->cherry_mark = 1; + revs->limited = 1; /* needs limit_list() */ } else if (!strcmp(arg, "--cherry-pick")) { + if (revs->cherry_mark) + die("--cherry-pick is incompatible with --cherry-mark"); revs->cherry_pick = 1; revs->limited = 1; } else if (!strcmp(arg, "--objects")) { @@ -1308,32 +1368,39 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg revs->verbose_header = 1; revs->pretty_given = 1; get_commit_format(arg+9, revs); - } else if (!strcmp(arg, "--show-notes")) { + } else if (!strcmp(arg, "--show-notes") || !strcmp(arg, "--notes")) { revs->show_notes = 1; revs->show_notes_given = 1; - } else if (!prefixcmp(arg, "--show-notes=")) { + revs->notes_opt.use_default_notes = 1; + } else if (!prefixcmp(arg, "--show-notes=") || + !prefixcmp(arg, "--notes=")) { struct strbuf buf = STRBUF_INIT; revs->show_notes = 1; revs->show_notes_given = 1; - if (!revs->notes_opt.extra_notes_refs) - revs->notes_opt.extra_notes_refs = xcalloc(1, sizeof(struct string_list)); - if (!prefixcmp(arg+13, "refs/")) - /* happy */; - else if (!prefixcmp(arg+13, "notes/")) - strbuf_addstr(&buf, "refs/"); + if (!prefixcmp(arg, "--show-notes")) { + if (revs->notes_opt.use_default_notes < 0) + revs->notes_opt.use_default_notes = 1; + strbuf_addstr(&buf, arg+13); + } else - strbuf_addstr(&buf, "refs/notes/"); - strbuf_addstr(&buf, arg+13); - string_list_append(revs->notes_opt.extra_notes_refs, + strbuf_addstr(&buf, arg+8); + expand_notes_ref(&buf); + string_list_append(&revs->notes_opt.extra_notes_refs, strbuf_detach(&buf, NULL)); } else if (!strcmp(arg, "--no-notes")) { revs->show_notes = 0; revs->show_notes_given = 1; + revs->notes_opt.use_default_notes = -1; + /* we have been strdup'ing ourselves, so trick + * string_list into free()ing strings */ + revs->notes_opt.extra_notes_refs.strdup_strings = 1; + string_list_clear(&revs->notes_opt.extra_notes_refs, 0); + revs->notes_opt.extra_notes_refs.strdup_strings = 0; } else if (!strcmp(arg, "--standard-notes")) { revs->show_notes_given = 1; - revs->notes_opt.suppress_default_notes = 0; + revs->notes_opt.use_default_notes = 1; } else if (!strcmp(arg, "--no-standard-notes")) { - revs->notes_opt.suppress_default_notes = 1; + revs->notes_opt.use_default_notes = 0; } else if (!strcmp(arg, "--oneline")) { revs->verbose_header = 1; get_commit_format("oneline", revs); @@ -1441,6 +1508,69 @@ static int for_each_good_bisect_ref(const char *submodule, each_ref_fn fn, void return for_each_ref_in_submodule(submodule, "refs/bisect/good", fn, cb_data); } +static int handle_revision_pseudo_opt(const char *submodule, + struct rev_info *revs, + int argc, const char **argv, int *flags) +{ + const char *arg = argv[0]; + const char *optarg; + int argcount; + + /* + * NOTE! + * + * Commands like "git shortlog" will not accept the options below + * unless parse_revision_opt queues them (as opposed to erroring + * out). + * + * When implementing your new pseudo-option, remember to + * register it in the list at the top of handle_revision_opt. + */ + if (!strcmp(arg, "--all")) { + handle_refs(submodule, revs, *flags, for_each_ref_submodule); + handle_refs(submodule, revs, *flags, head_ref_submodule); + } else if (!strcmp(arg, "--branches")) { + handle_refs(submodule, revs, *flags, for_each_branch_ref_submodule); + } else if (!strcmp(arg, "--bisect")) { + handle_refs(submodule, revs, *flags, for_each_bad_bisect_ref); + handle_refs(submodule, revs, *flags ^ UNINTERESTING, for_each_good_bisect_ref); + revs->bisect = 1; + } else if (!strcmp(arg, "--tags")) { + handle_refs(submodule, revs, *flags, for_each_tag_ref_submodule); + } else if (!strcmp(arg, "--remotes")) { + handle_refs(submodule, revs, *flags, for_each_remote_ref_submodule); + } else if ((argcount = parse_long_opt("glob", argv, &optarg))) { + struct all_refs_cb cb; + init_all_refs_cb(&cb, revs, *flags); + for_each_glob_ref(handle_one_ref, optarg, &cb); + return argcount; + } else if (!prefixcmp(arg, "--branches=")) { + struct all_refs_cb cb; + init_all_refs_cb(&cb, revs, *flags); + for_each_glob_ref_in(handle_one_ref, arg + 11, "refs/heads/", &cb); + } else if (!prefixcmp(arg, "--tags=")) { + struct all_refs_cb cb; + init_all_refs_cb(&cb, revs, *flags); + for_each_glob_ref_in(handle_one_ref, arg + 7, "refs/tags/", &cb); + } else if (!prefixcmp(arg, "--remotes=")) { + struct all_refs_cb cb; + init_all_refs_cb(&cb, revs, *flags); + for_each_glob_ref_in(handle_one_ref, arg + 10, "refs/remotes/", &cb); + } else if (!strcmp(arg, "--reflog")) { + handle_reflog(revs, *flags); + } else if (!strcmp(arg, "--not")) { + *flags ^= UNINTERESTING; + } else if (!strcmp(arg, "--no-walk")) { + revs->no_walk = 1; + } else if (!strcmp(arg, "--do-walk")) { + revs->no_walk = 0; + } else { + return 0; + } + + return 1; +} + /* * Parse revision information, filling in the "rev_info" structure, * and removing the used arguments from the argument list. @@ -1453,8 +1583,6 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s int i, flags, left, seen_dashdash, read_from_stdin, got_rev_arg = 0; struct cmdline_pathspec prune_data; const char *submodule = NULL; - const char *optarg; - int argcount; memset(&prune_data, 0, sizeof(prune_data)); if (opt) @@ -1482,70 +1610,14 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s if (*arg == '-') { int opts; - if (!strcmp(arg, "--all")) { - handle_refs(submodule, revs, flags, for_each_ref_submodule); - handle_refs(submodule, revs, flags, head_ref_submodule); - continue; - } - if (!strcmp(arg, "--branches")) { - handle_refs(submodule, revs, flags, for_each_branch_ref_submodule); - continue; - } - if (!strcmp(arg, "--bisect")) { - handle_refs(submodule, revs, flags, for_each_bad_bisect_ref); - handle_refs(submodule, revs, flags ^ UNINTERESTING, for_each_good_bisect_ref); - revs->bisect = 1; - continue; - } - if (!strcmp(arg, "--tags")) { - handle_refs(submodule, revs, flags, for_each_tag_ref_submodule); - continue; - } - if (!strcmp(arg, "--remotes")) { - handle_refs(submodule, revs, flags, for_each_remote_ref_submodule); - continue; - } - if ((argcount = parse_long_opt("glob", argv + i, &optarg))) { - struct all_refs_cb cb; - i += argcount - 1; - init_all_refs_cb(&cb, revs, flags); - for_each_glob_ref(handle_one_ref, optarg, &cb); - continue; - } - if (!prefixcmp(arg, "--branches=")) { - struct all_refs_cb cb; - init_all_refs_cb(&cb, revs, flags); - for_each_glob_ref_in(handle_one_ref, arg + 11, "refs/heads/", &cb); - continue; - } - if (!prefixcmp(arg, "--tags=")) { - struct all_refs_cb cb; - init_all_refs_cb(&cb, revs, flags); - for_each_glob_ref_in(handle_one_ref, arg + 7, "refs/tags/", &cb); - continue; - } - if (!prefixcmp(arg, "--remotes=")) { - struct all_refs_cb cb; - init_all_refs_cb(&cb, revs, flags); - for_each_glob_ref_in(handle_one_ref, arg + 10, "refs/remotes/", &cb); - continue; - } - if (!strcmp(arg, "--reflog")) { - handle_reflog(revs, flags); - continue; - } - if (!strcmp(arg, "--not")) { - flags ^= UNINTERESTING; - continue; - } - if (!strcmp(arg, "--no-walk")) { - revs->no_walk = 1; - continue; - } - if (!strcmp(arg, "--do-walk")) { - revs->no_walk = 0; + opts = handle_revision_pseudo_opt(submodule, + revs, argc - i, argv + i, + &flags); + if (opts > 0) { + i += opts - 1; continue; } + if (!strcmp(arg, "--stdin")) { if (revs->disable_stdin) { argv[left++] = arg; @@ -1972,10 +2044,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) { @@ -2222,3 +2299,32 @@ struct commit *get_revision(struct rev_info *revs) graph_update(revs->graph, c); return c; } + +char *get_revision_mark(const struct rev_info *revs, const struct commit *commit) +{ + if (commit->object.flags & BOUNDARY) + return "-"; + else if (commit->object.flags & UNINTERESTING) + return "^"; + else if (commit->object.flags & PATCHSAME) + return "="; + else if (!revs || revs->left_right) { + if (commit->object.flags & SYMMETRIC_LEFT) + return "<"; + else + return ">"; + } else if (revs->graph) + return "*"; + else if (revs->cherry_mark) + return "+"; + return ""; +} + +void put_revision_mark(const struct rev_info *revs, const struct commit *commit) +{ + char *mark = get_revision_mark(revs, commit); + if (!strlen(mark)) + return; + fputs(mark, stdout); + putchar(' '); +} |