diff options
Diffstat (limited to 'revision.c')
| -rw-r--r-- | revision.c | 259 |
1 files changed, 153 insertions, 106 deletions
diff --git a/revision.c b/revision.c index f5f5b84f2b..cf5e6c1ec9 100644 --- a/revision.c +++ b/revision.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" @@ -7,7 +8,7 @@ #include "hex.h" #include "object-name.h" #include "object-file.h" -#include "object-store-ll.h" +#include "odb.h" #include "oidset.h" #include "tag.h" #include "blob.h" @@ -49,23 +50,13 @@ #include "parse-options.h" #include "wildmatch.h" -volatile show_early_output_fn_t show_early_output; - -static const char *term_bad; -static const char *term_good; +static char *term_bad; +static char *term_good; implement_shared_commit_slab(revision_sources, char *); static inline int want_ancestry(const struct rev_info *revs); -void show_object_with_name(FILE *out, struct object *obj, const char *name) -{ - fprintf(out, "%s ", oid_to_hex(&obj->oid)); - for (const char *p = name; *p && *p != '\n'; p++) - fputc(*p, out); - fputc('\n', out); -} - static void mark_blob_uninteresting(struct blob *blob) { if (!blob) @@ -390,7 +381,8 @@ static struct object *get_reference(struct rev_info *revs, const char *name, if (!object) { if (revs->ignore_missing) return NULL; - if (revs->exclude_promisor_objects && is_promisor_object(oid)) + if (revs->exclude_promisor_objects && + is_promisor_object(revs->repo, oid)) return NULL; if (revs->do_not_die_on_missing_objects) { oidset_insert(&revs->missing_commits, oid); @@ -432,7 +424,7 @@ static struct commit *handle_commit(struct rev_info *revs, if (revs->ignore_missing_links || (flags & UNINTERESTING)) return NULL; if (revs->exclude_promisor_objects && - is_promisor_object(&tag->tagged->oid)) + is_promisor_object(revs->repo, &tag->tagged->oid)) return NULL; if (revs->do_not_die_on_missing_objects && oid) { oidset_insert(&revs->missing_commits, oid); @@ -679,26 +671,66 @@ static void trace2_bloom_filter_statistics_atexit(void) static int forbid_bloom_filters(struct pathspec *spec) { - if (spec->has_wildcard) - return 1; - if (spec->nr > 1) - return 1; - if (spec->magic & ~PATHSPEC_LITERAL) - return 1; - if (spec->nr && (spec->items[0].magic & ~PATHSPEC_LITERAL)) + unsigned int allowed_magic = + PATHSPEC_FROMTOP | + PATHSPEC_MAXDEPTH | + PATHSPEC_LITERAL | + PATHSPEC_GLOB | + PATHSPEC_ATTR; + + if (spec->magic & ~allowed_magic) return 1; + for (size_t nr = 0; nr < spec->nr; nr++) + if (spec->items[nr].magic & ~allowed_magic) + return 1; return 0; } -static void prepare_to_use_bloom_filter(struct rev_info *revs) +static void release_revisions_bloom_keyvecs(struct rev_info *revs); + +static int convert_pathspec_to_bloom_keyvec(struct bloom_keyvec **out, + const struct pathspec_item *pi, + const struct bloom_filter_settings *settings) { - struct pathspec_item *pi; char *path_alloc = NULL; - const char *path, *p; + const char *path; size_t len; - int path_component_nr = 1; + int res = -1; + len = pi->nowildcard_len; + if (len != pi->len) { + /* + * for path like "dir/file*", nowildcard part would be + * "dir/file", but only "dir" should be used for the + * bloom filter. + */ + while (len > 0 && pi->match[len - 1] != '/') + len--; + } + /* remove single trailing slash from path, if needed */ + if (len > 0 && pi->match[len - 1] == '/') + len--; + + if (!len) + goto cleanup; + + if (len != pi->len) { + path_alloc = xmemdupz(pi->match, len); + path = path_alloc; + } else + path = pi->match; + + *out = bloom_keyvec_new(path, len, settings); + + res = 0; +cleanup: + free(path_alloc); + return res; +} + +static void prepare_to_use_bloom_filter(struct rev_info *revs) +{ if (!revs->commits) return; @@ -714,48 +746,14 @@ static void prepare_to_use_bloom_filter(struct rev_info *revs) if (!revs->pruning.pathspec.nr) return; - pi = &revs->pruning.pathspec.items[0]; - - /* remove single trailing slash from path, if needed */ - if (pi->len > 0 && pi->match[pi->len - 1] == '/') { - path_alloc = xmemdupz(pi->match, pi->len - 1); - path = path_alloc; - } else - path = pi->match; + revs->bloom_keyvecs_nr = revs->pruning.pathspec.nr; + CALLOC_ARRAY(revs->bloom_keyvecs, revs->bloom_keyvecs_nr); - len = strlen(path); - if (!len) { - revs->bloom_filter_settings = NULL; - free(path_alloc); - return; - } - - p = path; - while (*p) { - /* - * At this point, the path is normalized to use Unix-style - * path separators. This is required due to how the - * changed-path Bloom filters store the paths. - */ - if (*p == '/') - path_component_nr++; - p++; - } - - revs->bloom_keys_nr = path_component_nr; - ALLOC_ARRAY(revs->bloom_keys, revs->bloom_keys_nr); - - fill_bloom_key(path, len, &revs->bloom_keys[0], - revs->bloom_filter_settings); - path_component_nr = 1; - - p = path + len - 1; - while (p > path) { - if (*p == '/') - fill_bloom_key(path, p - path, - &revs->bloom_keys[path_component_nr++], - revs->bloom_filter_settings); - p--; + for (int i = 0; i < revs->pruning.pathspec.nr; i++) { + if (convert_pathspec_to_bloom_keyvec(&revs->bloom_keyvecs[i], + &revs->pruning.pathspec.items[i], + revs->bloom_filter_settings)) + goto fail; } if (trace2_is_enabled() && !bloom_filter_atexit_registered) { @@ -763,17 +761,18 @@ static void prepare_to_use_bloom_filter(struct rev_info *revs) bloom_filter_atexit_registered = 1; } - free(path_alloc); + return; + +fail: + revs->bloom_filter_settings = NULL; + release_revisions_bloom_keyvecs(revs); } static int check_maybe_different_in_bloom_filter(struct rev_info *revs, struct commit *commit) { struct bloom_filter *filter; - int result = 1, j; - - if (!revs->repo->objects->commit_graph) - return -1; + int result = 0; if (commit_graph_generation(commit) == GENERATION_NUMBER_INFINITY) return -1; @@ -785,10 +784,10 @@ static int check_maybe_different_in_bloom_filter(struct rev_info *revs, return -1; } - for (j = 0; result && j < revs->bloom_keys_nr; j++) { - result = bloom_filter_contains(filter, - &revs->bloom_keys[j], - revs->bloom_filter_settings); + for (size_t nr = 0; !result && nr < revs->bloom_keyvecs_nr; nr++) { + result = bloom_filter_contains_vec(filter, + revs->bloom_keyvecs[nr], + revs->bloom_filter_settings); } if (result) @@ -829,7 +828,7 @@ static int rev_compare_tree(struct rev_info *revs, return REV_TREE_SAME; } - if (revs->bloom_keys_nr && !nth_parent) { + if (revs->bloom_keyvecs_nr && !nth_parent) { bloom_ret = check_maybe_different_in_bloom_filter(revs, commit); if (bloom_ret == 0) @@ -856,7 +855,7 @@ static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit, if (!t1) return 0; - if (!nth_parent && revs->bloom_keys_nr) { + if (!nth_parent && revs->bloom_keyvecs_nr) { bloom_ret = check_maybe_different_in_bloom_filter(revs, commit); if (!bloom_ret) return 1; @@ -1211,7 +1210,7 @@ static int process_parents(struct rev_info *revs, struct commit *commit, 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)) { + is_promisor_object(revs->repo, &p->object.oid)) { if (revs->first_parent_only) break; continue; @@ -1485,7 +1484,6 @@ static int limit_list(struct rev_info *revs) while (original_list) { struct commit *commit = pop_commit(&original_list); struct object *obj = &commit->object; - show_early_output_fn_t show; if (commit == interesting_cache) interesting_cache = NULL; @@ -1509,13 +1507,6 @@ static int limit_list(struct rev_info *revs) continue; date = commit->date; p = &commit_list_insert(commit, p)->next; - - show = show_early_output; - if (!show) - continue; - - show(revs, newlist); - show_early_output = NULL; } if (revs->cherry_pick || revs->cherry_mark) cherry_pick_list(newlist, revs); @@ -1642,7 +1633,7 @@ void exclude_hidden_refs(struct ref_exclusions *exclusions, const char *section) cb.exclusions = exclusions; cb.section = section; - git_config(hide_refs_config, &cb); + repo_config(the_repository, hide_refs_config, &cb); } struct all_refs_cb { @@ -1711,7 +1702,8 @@ static void handle_one_reflog_commit(struct object_id *oid, void *cb_data) } } -static int handle_one_reflog_ent(struct object_id *ooid, struct object_id *noid, +static int handle_one_reflog_ent(const char *refname UNUSED, + struct object_id *ooid, struct object_id *noid, const char *email UNUSED, timestamp_t timestamp UNUSED, int tz UNUSED, @@ -1872,15 +1864,20 @@ void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags) for (p = worktrees; *p; p++) { struct worktree *wt = *p; struct index_state istate = INDEX_STATE_INIT(revs->repo); + char *wt_gitdir; if (wt->is_current) continue; /* current index already taken care of */ + wt_gitdir = get_worktree_git_dir(wt); + if (read_index_from(&istate, worktree_git_path(the_repository, wt, "index"), - get_worktree_git_dir(wt)) > 0) + wt_gitdir) > 0) do_add_index_objects_to_pending(revs, &istate, flags); + discard_index(&istate); + free(wt_gitdir); } free_worktrees(worktrees); } @@ -1908,7 +1905,8 @@ static void add_alternate_refs_to_pending(struct rev_info *revs, struct add_alternate_refs_data data; data.revs = revs; data.flags = flags; - for_each_alternate_ref(add_one_alternate_ref, &data); + odb_for_each_alternate_ref(the_repository->objects, + add_one_alternate_ref, &data); } static int add_parents_only(struct rev_info *revs, const char *arg_, int flags, @@ -2061,6 +2059,7 @@ static void prepare_show_merge(struct rev_info *revs) parse_pathspec(&revs->prune_data, PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL, PATHSPEC_PREFER_FULL | PATHSPEC_LITERAL_PATH, "", prune); revs->limited = 1; + free(prune); } static int dotdot_missing(const char *arg, char *dotdot, @@ -2319,6 +2318,24 @@ static timestamp_t parse_age(const char *arg) return num; } +static void overwrite_argv(int *argc, const char **argv, + const char **value, + const struct setup_revision_opt *opt) +{ + /* + * Detect the case when we are overwriting ourselves. The assignment + * itself would be a noop either way, but this lets us avoid corner + * cases around the free() and NULL operations. + */ + if (*value != argv[*argc]) { + if (opt && opt->free_removed_argv_elements) + free((char *)argv[*argc]); + argv[*argc] = *value; + *value = NULL; + } + (*argc)++; +} + 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) @@ -2340,7 +2357,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg starts_with(arg, "--branches=") || starts_with(arg, "--tags=") || starts_with(arg, "--remotes=") || starts_with(arg, "--no-walk=")) { - unkv[(*unkc)++] = arg; + overwrite_argv(unkc, unkv, &argv[0], opt); return 1; } @@ -2442,13 +2459,6 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg } else if (!strcmp(arg, "--author-date-order")) { revs->sort_order = REV_SORT_BY_AUTHOR_DATE; revs->topo_order = 1; - } else if (!strcmp(arg, "--early-output")) { - revs->early_output = 100; - revs->topo_order = 1; - } else if (skip_prefix(arg, "--early-output=", &optarg)) { - if (strtoul_ui(optarg, 10, &revs->early_output) < 0) - die("'%s': not a non-negative integer", optarg); - revs->topo_order = 1; } else if (!strcmp(arg, "--parents")) { revs->rewrite_parents = 1; revs->print_parents = 1; @@ -2481,10 +2491,12 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg die(_("options '%s' and '%s' cannot be used together"), "--left-only", "--right-only/--cherry"); revs->left_only = 1; + revs->limited = 1; } else if (!strcmp(arg, "--right-only")) { if (revs->left_only) die(_("options '%s' and '%s' cannot be used together"), "--right-only", "--left-only"); revs->right_only = 1; + revs->limited = 1; } else if (!strcmp(arg, "--cherry")) { if (revs->left_only) die(_("options '%s' and '%s' cannot be used together"), "--cherry", "--left-only"); @@ -2709,7 +2721,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg } else { int opts = diff_opt_parse(&revs->diffopt, argv, argc, revs->prefix); if (!opts) - unkv[(*unkc)++] = arg; + overwrite_argv(unkc, unkv, &argv[0], opt); return opts; } @@ -3021,7 +3033,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s if (!strcmp(arg, "--stdin")) { if (revs->disable_stdin) { - argv[left++] = arg; + overwrite_argv(&left, argv, &argv[i], opt); continue; } if (revs->read_from_stdin++) @@ -3110,7 +3122,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s /* Pickaxe, diff-filter and rename following need diffs */ if ((revs->diffopt.pickaxe_opts & DIFF_PICKAXE_KINDS_MASK) || - revs->diffopt.filter || + revs->diffopt.filter || revs->diffopt.filter_not || revs->diffopt.flags.follow_renames) revs->diff = 1; @@ -3177,9 +3189,34 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s revs->show_notes_given = 1; } + if (argv) { + if (opt && opt->free_removed_argv_elements) + free((char *)argv[left]); + argv[left] = NULL; + } + return left; } +void setup_revisions_from_strvec(struct strvec *argv, struct rev_info *revs, + struct setup_revision_opt *opt) +{ + struct setup_revision_opt fallback_opt; + int ret; + + if (!opt) { + memset(&fallback_opt, 0, sizeof(fallback_opt)); + opt = &fallback_opt; + } + opt->free_removed_argv_elements = 1; + + ret = setup_revisions(argv->nr, argv->v, revs, opt); + + for (size_t i = ret; i < argv->nr; i++) + free((char *)argv->v[i]); + argv->nr = ret; +} + static void release_revisions_cmdline(struct rev_cmdline_info *cmdline) { unsigned int i; @@ -3199,6 +3236,14 @@ static void release_revisions_mailmap(struct string_list *mailmap) static void release_revisions_topo_walk_info(struct topo_walk_info *info); +static void release_revisions_bloom_keyvecs(struct rev_info *revs) +{ + for (size_t nr = 0; nr < revs->bloom_keyvecs_nr; nr++) + bloom_keyvec_free(revs->bloom_keyvecs[nr]); + FREE_AND_NULL(revs->bloom_keyvecs); + revs->bloom_keyvecs_nr = 0; +} + static void free_void_commit_list(void *list) { free_commit_list(list); @@ -3227,6 +3272,7 @@ void release_revisions(struct rev_info *revs) clear_decoration(&revs->treesame, free); line_log_free(revs); oidset_clear(&revs->missing_commits); + release_revisions_bloom_keyvecs(revs); } static void add_child(struct rev_info *revs, struct commit *parent, struct commit *child) @@ -3600,7 +3646,8 @@ static void set_children(struct rev_info *revs) void reset_revision_walk(void) { - clear_object_flags(SEEN | ADDED | SHOWN | TOPO_WALK_EXPLORED | TOPO_WALK_INDEGREE); + clear_object_flags(the_repository, + SEEN | ADDED | SHOWN | TOPO_WALK_EXPLORED | TOPO_WALK_INDEGREE); } static int mark_uninteresting(const struct object_id *oid, @@ -3915,7 +3962,7 @@ int prepare_revision_walk(struct rev_info *revs) revs->treesame.name = "treesame"; if (revs->exclude_promisor_objects) { - for_each_packed_object(mark_uninteresting, revs, + for_each_packed_object(revs->repo, mark_uninteresting, revs, FOR_EACH_OBJECT_PROMISOR_ONLY); } @@ -4103,10 +4150,10 @@ enum commit_action get_commit_action(struct rev_info *revs, struct commit *commi { if (commit->object.flags & SHOWN) return commit_ignore; - if (revs->unpacked && has_object_pack(&commit->object.oid)) + if (revs->unpacked && has_object_pack(revs->repo, &commit->object.oid)) return commit_ignore; if (revs->no_kept_objects) { - if (has_object_kept_pack(&commit->object.oid, + if (has_object_kept_pack(revs->repo, &commit->object.oid, revs->keep_pack_cache_flags)) return commit_ignore; } |
