diff options
Diffstat (limited to 'revision.c')
-rw-r--r-- | revision.c | 184 |
1 files changed, 134 insertions, 50 deletions
diff --git a/revision.c b/revision.c index a60dfc23a2..7e45f765d9 100644 --- a/revision.c +++ b/revision.c @@ -6,6 +6,7 @@ #include "object-name.h" #include "object-file.h" #include "object-store-ll.h" +#include "oidset.h" #include "tag.h" #include "blob.h" #include "tree.h" @@ -20,12 +21,10 @@ #include "reflog-walk.h" #include "patch-ids.h" #include "decorate.h" -#include "log-tree.h" #include "string-list.h" #include "line-log.h" #include "mailmap.h" #include "commit-slab.h" -#include "dir.h" #include "cache-tree.h" #include "bisect.h" #include "packfile.h" @@ -382,13 +381,18 @@ static struct object *get_reference(struct rev_info *revs, const char *name, object = parse_object_with_flags(revs->repo, oid, revs->verify_objects ? 0 : - PARSE_OBJECT_SKIP_HASH_CHECK); + PARSE_OBJECT_SKIP_HASH_CHECK | + PARSE_OBJECT_DISCARD_TREE); if (!object) { if (revs->ignore_missing) - return object; + return NULL; if (revs->exclude_promisor_objects && is_promisor_object(oid)) return NULL; + if (revs->do_not_die_on_missing_objects) { + oidset_insert(&revs->missing_commits, oid); + return NULL; + } die("bad object %s", name); } object->flags |= flags; @@ -416,15 +420,21 @@ static struct commit *handle_commit(struct rev_info *revs, */ while (object->type == OBJ_TAG) { struct tag *tag = (struct tag *) object; + struct object_id *oid; if (revs->tag_objects && !(flags & UNINTERESTING)) add_pending_object(revs, object, tag->tag); - object = parse_object(revs->repo, get_tagged_oid(tag)); + oid = get_tagged_oid(tag); + object = parse_object(revs->repo, oid); if (!object) { if (revs->ignore_missing_links || (flags & UNINTERESTING)) return NULL; if (revs->exclude_promisor_objects && is_promisor_object(&tag->tagged->oid)) return NULL; + if (revs->do_not_die_on_missing_objects && oid) { + oidset_insert(&revs->missing_commits, oid); + return NULL; + } die("bad object %s", oid_to_hex(&tag->tagged->oid)); } object->flags |= flags; @@ -1112,6 +1122,9 @@ static int process_parents(struct rev_info *revs, struct commit *commit, if (commit->object.flags & ADDED) return 0; + if (revs->do_not_die_on_missing_objects && + oidset_contains(&revs->missing_commits, &commit->object.oid)) + return 0; commit->object.flags |= ADDED; if (revs->include_check && @@ -1168,7 +1181,8 @@ static int process_parents(struct rev_info *revs, struct commit *commit, for (parent = commit->parents; parent; parent = parent->next) { struct commit *p = parent->item; int gently = revs->ignore_missing_links || - revs->exclude_promisor_objects; + revs->exclude_promisor_objects || + revs->do_not_die_on_missing_objects; if (repo_parse_commit_gently(revs->repo, p, gently) < 0) { if (revs->exclude_promisor_objects && is_promisor_object(&p->object.oid)) { @@ -1176,7 +1190,11 @@ static int process_parents(struct rev_info *revs, struct commit *commit, break; continue; } - return -1; + + if (revs->do_not_die_on_missing_objects) + oidset_insert(&revs->missing_commits, &p->object.oid); + else + return -1; /* corrupt repository */ } if (revs->sources) { char **slot = revision_sources_at(revs->sources, p); @@ -1679,9 +1697,7 @@ static int handle_one_reflog_ent(struct object_id *ooid, struct object_id *noid, return 0; } -static int handle_one_reflog(const char *refname_in_wt, - const struct object_id *oid UNUSED, - int flag UNUSED, void *cb_data) +static int handle_one_reflog(const char *refname_in_wt, void *cb_data) { struct all_refs_cb *cb = cb_data; struct strbuf refname = STRBUF_INIT; @@ -1940,6 +1956,7 @@ void repo_init_revisions(struct repository *r, init_display_notes(&revs->notes_opt); list_objects_filter_init(&revs->filter); init_ref_exclusions(&revs->ref_excludes); + oidset_init(&revs->missing_commits, 0); } static void add_pending_commit_list(struct rev_info *revs, @@ -1954,11 +1971,31 @@ static void add_pending_commit_list(struct rev_info *revs, } } +static const char *lookup_other_head(struct object_id *oid) +{ + int i; + static const char *const other_head[] = { + "MERGE_HEAD", "CHERRY_PICK_HEAD", "REVERT_HEAD", "REBASE_HEAD" + }; + + for (i = 0; i < ARRAY_SIZE(other_head); i++) + if (!read_ref_full(other_head[i], + RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE, + oid, NULL)) { + if (is_null_oid(oid)) + die(_("%s exists but is a symbolic ref"), other_head[i]); + return other_head[i]; + } + + die(_("--merge requires one of the pseudorefs MERGE_HEAD, CHERRY_PICK_HEAD, REVERT_HEAD or REBASE_HEAD")); +} + static void prepare_show_merge(struct rev_info *revs) { - struct commit_list *bases; + struct commit_list *bases = NULL; struct commit *head, *other; struct object_id oid; + const char *other_name; const char **prune = NULL; int i, prune_num = 1; /* counting terminating NULL */ struct index_state *istate = revs->repo->index; @@ -1966,12 +2003,12 @@ static void prepare_show_merge(struct rev_info *revs) if (repo_get_oid(the_repository, "HEAD", &oid)) die("--merge without HEAD?"); head = lookup_commit_or_die(&oid, "HEAD"); - if (repo_get_oid(the_repository, "MERGE_HEAD", &oid)) - die("--merge without MERGE_HEAD?"); - other = lookup_commit_or_die(&oid, "MERGE_HEAD"); + other_name = lookup_other_head(&oid); + other = lookup_commit_or_die(&oid, other_name); add_pending_object(revs, &head->object, "HEAD"); - add_pending_object(revs, &other->object, "MERGE_HEAD"); - bases = repo_get_merge_bases(the_repository, head, other); + add_pending_object(revs, &other->object, other_name); + if (repo_get_merge_bases(the_repository, head, other, &bases) < 0) + exit(128); add_rev_cmdline_list(revs, bases, REV_CMD_MERGE_BASE, UNINTERESTING | BOTTOM); add_pending_commit_list(revs, bases, UNINTERESTING | BOTTOM); free_commit_list(bases); @@ -2059,14 +2096,17 @@ static int handle_dotdot_1(const char *arg, char *dotdot, } else { /* A...B -- find merge bases between the two */ struct commit *a, *b; - struct commit_list *exclude; + struct commit_list *exclude = NULL; a = lookup_commit_reference(revs->repo, &a_obj->oid); b = lookup_commit_reference(revs->repo, &b_obj->oid); if (!a || !b) return dotdot_missing(arg, dotdot, revs, symmetric); - exclude = repo_get_merge_bases(the_repository, a, b); + if (repo_get_merge_bases(the_repository, a, b, &exclude) < 0) { + free_commit_list(exclude); + return -1; + } add_rev_cmdline_list(revs, exclude, REV_CMD_MERGE_BASE, flags_exclude); add_pending_commit_list(revs, exclude, flags_exclude); @@ -2171,13 +2211,18 @@ static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int fl if (revarg_opt & REVARG_COMMITTISH) get_sha1_flags |= GET_OID_COMMITTISH; + /* + * Even if revs->do_not_die_on_missing_objects is set, we + * should error out if we can't even get an oid, as + * `--missing=print` should be able to report missing oids. + */ if (get_oid_with_context(revs->repo, arg, get_sha1_flags, &oid, &oc)) return revs->ignore_missing ? 0 : -1; if (!cant_be_filename) verify_non_filename(revs->prefix, arg); object = get_reference(revs, arg, &oid, flags ^ local_flags); if (!object) - return revs->ignore_missing ? 0 : -1; + return (revs->ignore_missing || revs->do_not_die_on_missing_objects) ? 0 : -1; add_rev_cmdline(revs, object, arg_, REV_CMD_REV, flags ^ local_flags); add_pending_object_with_path(revs, object, arg, oc.mode, oc.path); free(oc.path); @@ -2214,6 +2259,27 @@ static void add_message_grep(struct rev_info *revs, const char *pattern) add_grep(revs, pattern, GREP_PATTERN_BODY); } +static int parse_count(const char *arg) +{ + int count; + + if (strtol_i(arg, 10, &count) < 0) + die("'%s': not an integer", arg); + return count; +} + +static timestamp_t parse_age(const char *arg) +{ + timestamp_t num; + char *p; + + errno = 0; + num = parse_timestamp(arg, &p, 10); + if (errno || *p || p == arg) + die("'%s': not a number of seconds since epoch", arg); + return num; +} + static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv, int *unkc, const char **unkv, const struct setup_revision_opt* opt) @@ -2240,29 +2306,27 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg } if ((argcount = parse_long_opt("max-count", argv, &optarg))) { - revs->max_count = atoi(optarg); + revs->max_count = parse_count(optarg); revs->no_walk = 0; return argcount; } else if ((argcount = parse_long_opt("skip", argv, &optarg))) { - revs->skip_count = atoi(optarg); + revs->skip_count = parse_count(optarg); return argcount; } else if ((*arg == '-') && isdigit(arg[1])) { /* accept -<digit>, like traditional "head" */ - if (strtol_i(arg + 1, 10, &revs->max_count) < 0 || - revs->max_count < 0) - die("'%s': not a non-negative integer", arg + 1); + revs->max_count = parse_count(arg + 1); revs->no_walk = 0; } else if (!strcmp(arg, "-n")) { if (argc <= 1) return error("-n requires an argument"); - revs->max_count = atoi(argv[1]); + revs->max_count = parse_count(argv[1]); revs->no_walk = 0; return 2; } else if (skip_prefix(arg, "-n", &optarg)) { - revs->max_count = atoi(optarg); + revs->max_count = parse_count(optarg); revs->no_walk = 0; } else if ((argcount = parse_long_opt("max-age", argv, &optarg))) { - revs->max_age = atoi(optarg); + revs->max_age = parse_age(optarg); return argcount; } else if ((argcount = parse_long_opt("since", argv, &optarg))) { revs->max_age = approxidate(optarg); @@ -2274,7 +2338,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg revs->max_age = approxidate(optarg); return argcount; } else if ((argcount = parse_long_opt("min-age", argv, &optarg))) { - revs->min_age = atoi(optarg); + revs->min_age = parse_age(optarg); return argcount; } else if ((argcount = parse_long_opt("before", argv, &optarg))) { revs->min_age = approxidate(optarg); @@ -2294,7 +2358,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg } else if (skip_prefix(arg, "--ancestry-path=", &optarg)) { struct commit *c; struct object_id oid; - const char *msg = _("could not get commit for ancestry-path argument %s"); + const char *msg = _("could not get commit for --ancestry-path argument %s"); revs->ancestry_path = 1; revs->simplify_history = 0; @@ -2362,11 +2426,11 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg } else if (!strcmp(arg, "--no-merges")) { revs->max_parents = 1; } else if (skip_prefix(arg, "--min-parents=", &optarg)) { - revs->min_parents = atoi(optarg); + revs->min_parents = parse_count(optarg); } else if (!strcmp(arg, "--no-min-parents")) { revs->min_parents = 0; } else if (skip_prefix(arg, "--max-parents=", &optarg)) { - revs->max_parents = atoi(optarg); + revs->max_parents = parse_count(optarg); } else if (!strcmp(arg, "--no-max-parents")) { revs->max_parents = -1; } else if (!strcmp(arg, "--boundary")) { @@ -2375,8 +2439,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg revs->left_right = 1; } else if (!strcmp(arg, "--left-only")) { if (revs->right_only) - die("--left-only is incompatible with --right-only" - " or --cherry"); + die(_("options '%s' and '%s' cannot be used together"), + "--left-only", "--right-only/--cherry"); revs->left_only = 1; } else if (!strcmp(arg, "--right-only")) { if (revs->left_only) @@ -2484,6 +2548,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg revs->break_bar = xstrdup(optarg); revs->track_linear = 1; revs->track_first_time = 1; + } else if (!strcmp(arg, "--show-notes-by-default")) { + revs->show_notes_by_default = 1; } else if (skip_prefix(arg, "--show-notes=", &optarg) || skip_prefix(arg, "--notes=", &optarg)) { if (starts_with(arg, "--show-notes=") && @@ -2698,7 +2764,8 @@ static int handle_revision_pseudo_opt(struct rev_info *revs, clear_ref_exclusions(&revs->ref_excludes); } else if (!strcmp(arg, "--branches")) { if (revs->ref_excludes.hidden_refs_configured) - return error(_("--exclude-hidden cannot be used together with --branches")); + return error(_("options '%s' and '%s' cannot be used together"), + "--exclude-hidden", "--branches"); handle_refs(refs, revs, *flags, refs_for_each_branch_ref); clear_ref_exclusions(&revs->ref_excludes); } else if (!strcmp(arg, "--bisect")) { @@ -2709,12 +2776,14 @@ static int handle_revision_pseudo_opt(struct rev_info *revs, revs->bisect = 1; } else if (!strcmp(arg, "--tags")) { if (revs->ref_excludes.hidden_refs_configured) - return error(_("--exclude-hidden cannot be used together with --tags")); + return error(_("options '%s' and '%s' cannot be used together"), + "--exclude-hidden", "--tags"); handle_refs(refs, revs, *flags, refs_for_each_tag_ref); clear_ref_exclusions(&revs->ref_excludes); } else if (!strcmp(arg, "--remotes")) { if (revs->ref_excludes.hidden_refs_configured) - return error(_("--exclude-hidden cannot be used together with --remotes")); + return error(_("options '%s' and '%s' cannot be used together"), + "--exclude-hidden", "--remotes"); handle_refs(refs, revs, *flags, refs_for_each_remote_ref); clear_ref_exclusions(&revs->ref_excludes); } else if ((argcount = parse_long_opt("glob", argv, &optarg))) { @@ -2732,21 +2801,24 @@ static int handle_revision_pseudo_opt(struct rev_info *revs, } else if (skip_prefix(arg, "--branches=", &optarg)) { struct all_refs_cb cb; if (revs->ref_excludes.hidden_refs_configured) - return error(_("--exclude-hidden cannot be used together with --branches")); + return error(_("options '%s' and '%s' cannot be used together"), + "--exclude-hidden", "--branches"); init_all_refs_cb(&cb, revs, *flags); for_each_glob_ref_in(handle_one_ref, optarg, "refs/heads/", &cb); clear_ref_exclusions(&revs->ref_excludes); } else if (skip_prefix(arg, "--tags=", &optarg)) { struct all_refs_cb cb; if (revs->ref_excludes.hidden_refs_configured) - return error(_("--exclude-hidden cannot be used together with --tags")); + return error(_("options '%s' and '%s' cannot be used together"), + "--exclude-hidden", "--tags"); init_all_refs_cb(&cb, revs, *flags); for_each_glob_ref_in(handle_one_ref, optarg, "refs/tags/", &cb); clear_ref_exclusions(&revs->ref_excludes); } else if (skip_prefix(arg, "--remotes=", &optarg)) { struct all_refs_cb cb; if (revs->ref_excludes.hidden_refs_configured) - return error(_("--exclude-hidden cannot be used together with --remotes")); + return error(_("options '%s' and '%s' cannot be used together"), + "--exclude-hidden", "--remotes"); init_all_refs_cb(&cb, revs, *flags); for_each_glob_ref_in(handle_one_ref, optarg, "refs/remotes/", &cb); clear_ref_exclusions(&revs->ref_excludes); @@ -2788,13 +2860,13 @@ static int handle_revision_pseudo_opt(struct rev_info *revs, } static void read_revisions_from_stdin(struct rev_info *revs, - struct strvec *prune, - int *flags) + struct strvec *prune) { struct strbuf sb; int seen_dashdash = 0; int seen_end_of_options = 0; int save_warning; + int flags = 0; save_warning = warn_on_object_refname_ambiguity; warn_on_object_refname_ambiguity = 0; @@ -2817,13 +2889,13 @@ static void read_revisions_from_stdin(struct rev_info *revs, continue; } - if (handle_revision_pseudo_opt(revs, argv, flags) > 0) + if (handle_revision_pseudo_opt(revs, argv, &flags) > 0) continue; die(_("invalid option '%s' in --stdin mode"), sb.buf); } - if (handle_revision_arg(sb.buf, revs, 0, + if (handle_revision_arg(sb.buf, revs, flags, REVARG_CANNOT_BE_FILENAME)) die("bad revision '%s'", sb.buf); } @@ -2906,7 +2978,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s } if (revs->read_from_stdin++) die("--stdin given twice?"); - read_revisions_from_stdin(revs, &prune_data, &flags); + read_revisions_from_stdin(revs, &prune_data); continue; } @@ -3025,8 +3097,6 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s revs->grep_filter.ignore_locale = 1; compile_grep_patterns(&revs->grep_filter); - if (revs->reverse && revs->reflog_info) - die(_("options '%s' and '%s' cannot be used together"), "--reverse", "--walk-reflogs"); if (revs->reflog_info && revs->limited) die("cannot combine --walk-reflogs with history-limiting options"); if (revs->rewrite_parents && revs->children.name) @@ -3037,11 +3107,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s /* * Limitations on the graph functionality */ - if (revs->reverse && revs->graph) - die(_("options '%s' and '%s' cannot be used together"), "--reverse", "--graph"); + die_for_incompatible_opt3(!!revs->graph, "--graph", + !!revs->reverse, "--reverse", + !!revs->reflog_info, "--walk-reflogs"); - if (revs->reflog_info && revs->graph) - die(_("options '%s' and '%s' cannot be used together"), "--walk-reflogs", "--graph"); if (revs->no_walk && revs->graph) die(_("options '%s' and '%s' cannot be used together"), "--no-walk", "--graph"); if (!revs->reflog_info && revs->grep_filter.use_reflog_filter) @@ -3054,6 +3123,11 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s if (revs->expand_tabs_in_log < 0) revs->expand_tabs_in_log = revs->expand_tabs_in_log_default; + if (!revs->show_notes_given && revs->show_notes_by_default) { + enable_default_display_notes(&revs->notes_opt, &revs->show_notes); + revs->show_notes_given = 1; + } + return left; } @@ -3076,6 +3150,11 @@ static void release_revisions_mailmap(struct string_list *mailmap) static void release_revisions_topo_walk_info(struct topo_walk_info *info); +static void free_void_commit_list(void *list) +{ + free_commit_list(list); +} + void release_revisions(struct rev_info *revs) { free_commit_list(revs->commits); @@ -3093,6 +3172,11 @@ void release_revisions(struct rev_info *revs) diff_free(&revs->pruning); reflog_walk_info_release(revs->reflog_info); release_revisions_topo_walk_info(revs->topo_walk_info); + clear_decoration(&revs->children, free_void_commit_list); + clear_decoration(&revs->merge_simplification, free); + clear_decoration(&revs->treesame, free); + line_log_free(revs); + oidset_clear(&revs->missing_commits); } static void add_child(struct rev_info *revs, struct commit *parent, struct commit *child) |