diff options
Diffstat (limited to 'revision.c')
| -rw-r--r-- | revision.c | 186 |
1 files changed, 134 insertions, 52 deletions
diff --git a/revision.c b/revision.c index 2424c9bd67..1c0192f522 100644 --- a/revision.c +++ b/revision.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "config.h" #include "environment.h" @@ -29,6 +31,7 @@ #include "bisect.h" #include "packfile.h" #include "worktree.h" +#include "path.h" #include "read-cache.h" #include "setup.h" #include "sparse-index.h" @@ -81,7 +84,7 @@ static void mark_tree_contents_uninteresting(struct repository *r, if (parse_tree_gently(tree, 1) < 0) return; - init_tree_desc(&desc, tree->buffer, tree->size); + init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size); while (tree_entry(&desc, &entry)) { switch (object_type(entry.mode)) { case OBJ_TREE: @@ -188,7 +191,7 @@ static void add_children_by_path(struct repository *r, if (parse_tree_gently(tree, 1) < 0) return; - init_tree_desc(&desc, tree->buffer, tree->size); + init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size); while (tree_entry(&desc, &entry)) { switch (object_type(entry.mode)) { case OBJ_TREE: @@ -381,13 +384,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; @@ -415,15 +423,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; @@ -833,17 +847,28 @@ static int rev_compare_tree(struct rev_info *revs, return tree_difference; } -static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit) +static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit, + int nth_parent) { struct tree *t1 = repo_get_commit_tree(the_repository, commit); + int bloom_ret = -1; if (!t1) return 0; + if (!nth_parent && revs->bloom_keys_nr) { + bloom_ret = check_maybe_different_in_bloom_filter(revs, commit); + if (!bloom_ret) + return 1; + } + tree_difference = REV_TREE_SAME; revs->pruning.flags.has_changes = 0; diff_tree_oid(NULL, &t1->object.oid, "", &revs->pruning); + if (bloom_ret == 1 && tree_difference == REV_TREE_SAME) + count_bloom_filter_false_positive++; + return tree_difference == REV_TREE_SAME; } @@ -881,7 +906,7 @@ static int compact_treesame(struct rev_info *revs, struct commit *commit, unsign if (nth_parent != 0) die("compact_treesame %u", nth_parent); old_same = !!(commit->object.flags & TREESAME); - if (rev_same_tree_as_empty(revs, commit)) + if (rev_same_tree_as_empty(revs, commit, nth_parent)) commit->object.flags |= TREESAME; else commit->object.flags &= ~TREESAME; @@ -977,7 +1002,14 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit) return; if (!commit->parents) { - if (rev_same_tree_as_empty(revs, commit)) + /* + * Pretend as if we are comparing ourselves to the + * (non-existent) first parent of this commit object. Even + * though no such parent exists, its changed-path Bloom filter + * (if one exists) is relative to the empty tree, using Bloom + * filters is allowed here. + */ + if (rev_same_tree_as_empty(revs, commit, 0)) commit->object.flags |= TREESAME; return; } @@ -1058,7 +1090,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit) case REV_TREE_NEW: if (revs->remove_empty_trees && - rev_same_tree_as_empty(revs, p)) { + rev_same_tree_as_empty(revs, p, nth_parent)) { /* We are adding all the specified * paths from this parent, so the * history beyond this parent is not @@ -1686,9 +1718,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; @@ -1729,7 +1759,8 @@ void add_reflogs_to_pending(struct rev_info *revs, unsigned flags) cb.all_revs = revs; cb.all_flags = flags; cb.wt = NULL; - for_each_reflog(handle_one_reflog, &cb); + refs_for_each_reflog(get_main_ref_store(the_repository), + handle_one_reflog, &cb); if (!revs->single_worktree) add_other_reflogs_to_pending(&cb); @@ -1947,6 +1978,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, @@ -1961,11 +1993,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 (!refs_read_ref_full(get_main_ref_store(the_repository), 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; @@ -1973,12 +2025,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); @@ -2066,14 +2118,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); @@ -2096,30 +2151,26 @@ static int handle_dotdot(const char *arg, struct rev_info *revs, int flags, int cant_be_filename) { - struct object_context a_oc, b_oc; + struct object_context a_oc = {0}, b_oc = {0}; char *dotdot = strstr(arg, ".."); int ret; if (!dotdot) return -1; - memset(&a_oc, 0, sizeof(a_oc)); - memset(&b_oc, 0, sizeof(b_oc)); - *dotdot = '\0'; ret = handle_dotdot_1(arg, dotdot, revs, flags, cant_be_filename, &a_oc, &b_oc); *dotdot = '.'; - free(a_oc.path); - free(b_oc.path); - + object_context_release(&a_oc); + object_context_release(&b_oc); return ret; } static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int flags, unsigned revarg_opt) { - struct object_context oc; + struct object_context oc = {0}; char *mark; struct object *object; struct object_id oid; @@ -2127,6 +2178,7 @@ static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int fl const char *arg = arg_; int cant_be_filename = revarg_opt & REVARG_CANNOT_BE_FILENAME; unsigned get_sha1_flags = GET_OID_RECORD_PATH; + int ret; flags = flags & UNINTERESTING ? flags | BOTTOM : flags & ~BOTTOM; @@ -2135,17 +2187,22 @@ static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int fl * Just ".."? That is not a range but the * pathspec for the parent directory. */ - return -1; + ret = -1; + goto out; } - if (!handle_dotdot(arg, revs, flags, revarg_opt)) - return 0; + if (!handle_dotdot(arg, revs, flags, revarg_opt)) { + ret = 0; + goto out; + } mark = strstr(arg, "^@"); if (mark && !mark[2]) { *mark = 0; - if (add_parents_only(revs, arg, flags, 0)) - return 0; + if (add_parents_only(revs, arg, flags, 0)) { + ret = 0; + goto out; + } *mark = '^'; } mark = strstr(arg, "^!"); @@ -2160,8 +2217,10 @@ static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int fl if (mark[2]) { if (strtol_i(mark + 2, 10, &exclude_parent) || - exclude_parent < 1) - return -1; + exclude_parent < 1) { + ret = -1; + goto out; + } } *mark = 0; @@ -2178,17 +2237,30 @@ 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; - if (get_oid_with_context(revs->repo, arg, get_sha1_flags, &oid, &oc)) - return revs->ignore_missing ? 0 : -1; + /* + * 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)) { + ret = revs->ignore_missing ? 0 : -1; + goto out; + } 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; + if (!object) { + ret = (revs->ignore_missing || revs->do_not_die_on_missing_objects) ? 0 : -1; + goto out; + } 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); - return 0; + + ret = 0; + +out: + object_context_release(&oc); + return ret; } int handle_revision_arg(const char *arg, struct rev_info *revs, int flags, unsigned revarg_opt) @@ -2320,7 +2392,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; @@ -2611,10 +2683,11 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg } else if (!strcmp(arg, "--invert-grep")) { revs->grep_filter.no_body_match = 1; } else if ((argcount = parse_long_opt("encoding", argv, &optarg))) { + free(git_log_output_encoding); if (strcmp(optarg, "none")) git_log_output_encoding = xstrdup(optarg); else - git_log_output_encoding = ""; + git_log_output_encoding = xstrdup(""); return argcount; } else if (!strcmp(arg, "--reverse")) { revs->reverse ^= 1; @@ -2751,7 +2824,8 @@ static int handle_revision_pseudo_opt(struct rev_info *revs, } 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); + refs_for_each_glob_ref(get_main_ref_store(the_repository), + handle_one_ref, optarg, &cb); clear_ref_exclusions(&revs->ref_excludes); return argcount; } else if ((argcount = parse_long_opt("exclude", argv, &optarg))) { @@ -2766,7 +2840,9 @@ static int handle_revision_pseudo_opt(struct rev_info *revs, 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); + refs_for_each_glob_ref_in(get_main_ref_store(the_repository), + 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; @@ -2774,7 +2850,9 @@ static int handle_revision_pseudo_opt(struct rev_info *revs, 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); + refs_for_each_glob_ref_in(get_main_ref_store(the_repository), + 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; @@ -2782,7 +2860,9 @@ static int handle_revision_pseudo_opt(struct rev_info *revs, 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); + refs_for_each_glob_ref_in(get_main_ref_store(the_repository), + handle_one_ref, optarg, + "refs/remotes/", &cb); clear_ref_exclusions(&revs->ref_excludes); } else if (!strcmp(arg, "--reflog")) { add_reflogs_to_pending(revs, *flags); @@ -2873,7 +2953,8 @@ static void NORETURN diagnose_missing_default(const char *def) int flags; const char *refname; - refname = resolve_ref_unsafe(def, 0, NULL, &flags); + refname = refs_resolve_ref_unsafe(get_main_ref_store(the_repository), + def, 0, NULL, &flags); if (!refname || !(flags & REF_ISSYMREF) || (flags & REF_ISBROKEN)) die(_("your current branch appears to be broken")); @@ -3015,6 +3096,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s diagnose_missing_default(revs->def); object = get_reference(revs, revs->def, &oid, 0); add_pending_object_with_mode(revs, object, revs->def, oc.mode); + object_context_release(&oc); } /* Did the user ask for any diff output? Run the diff! */ @@ -3121,6 +3203,7 @@ void release_revisions(struct rev_info *revs) { free_commit_list(revs->commits); free_commit_list(revs->ancestry_path_bottoms); + release_display_notes(&revs->notes_opt); object_array_clear(&revs->pending); object_array_clear(&revs->boundary_commits); release_revisions_cmdline(&revs->cmdline); @@ -3130,7 +3213,7 @@ void release_revisions(struct rev_info *revs) release_revisions_mailmap(revs->mailmap); free_grep_patterns(&revs->grep_filter); graph_clear(revs->graph); - /* TODO (need to handle "no_free"): diff_free(&revs->diffopt) */ + diff_free(&revs->diffopt); diff_free(&revs->pruning); reflog_walk_info_release(revs->reflog_info); release_revisions_topo_walk_info(revs->topo_walk_info); @@ -3830,8 +3913,6 @@ int prepare_revision_walk(struct rev_info *revs) FOR_EACH_OBJECT_PROMISOR_ONLY); } - oidset_init(&revs->missing_commits, 0); - if (!revs->reflog_info) prepare_to_use_bloom_filter(revs); if (!revs->unsorted_input) @@ -4385,6 +4466,7 @@ struct commit *get_revision(struct rev_info *revs) reversed = NULL; while ((c = get_revision_internal(revs))) commit_list_insert(c, &reversed); + free_commit_list(revs->commits); revs->commits = reversed; revs->reverse = 0; revs->reverse_output_stage = 1; |
