diff options
Diffstat (limited to 'revision.c')
| -rw-r--r-- | revision.c | 475 |
1 files changed, 289 insertions, 186 deletions
diff --git a/revision.c b/revision.c index 7d435f8048..100e5ad511 100644 --- a/revision.c +++ b/revision.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "config.h" #include "object-store.h" #include "tag.h" #include "blob.h" @@ -33,6 +34,7 @@ #include "bloom.h" #include "json-writer.h" #include "list-objects-filter-options.h" +#include "resolve-undo.h" volatile show_early_output_fn_t show_early_output; @@ -46,13 +48,6 @@ 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)); - /* - * This "for (const char *p = ..." is made as a first step towards - * making use of such declarations elsewhere in our codebase. If - * it causes compilation problems on your platform, please report - * it to the Git mailing list at git@vger.kernel.org. In the meantime, - * adding -std=gnu99 to CFLAGS may help if you are with older GCC. - */ for (const char *p = name; *p && *p != '\n'; p++) fputc(*p, out); fputc('\n', out); @@ -118,10 +113,10 @@ struct path_and_oids_entry { struct oidset trees; }; -static int path_and_oids_cmp(const void *hashmap_cmp_fn_data, +static int path_and_oids_cmp(const void *hashmap_cmp_fn_data UNUSED, const struct hashmap_entry *eptr, const struct hashmap_entry *entry_or_key, - const void *keydata) + const void *keydata UNUSED) { const struct path_and_oids_entry *e1, *e2; @@ -372,18 +367,10 @@ static struct object *get_reference(struct rev_info *revs, const char *name, unsigned int flags) { struct object *object; - struct commit *commit; - /* - * If the repository has commit graphs, we try to opportunistically - * look up the object ID in those graphs. Like this, we can avoid - * parsing commit data from disk. - */ - commit = lookup_commit_in_graph(revs->repo, oid); - if (commit) - object = &commit->object; - else - object = parse_object(revs->repo, oid); + object = parse_object_with_flags(revs->repo, oid, + revs->verify_objects ? 0 : + PARSE_OBJECT_SKIP_HASH_CHECK); if (!object) { if (revs->ignore_missing) @@ -606,13 +593,19 @@ static struct commit *one_relevant_parent(const struct rev_info *revs, * * 2. We saw anything except REV_TREE_NEW. */ +#define REV_TREE_SAME 0 +#define REV_TREE_NEW 1 /* Only new files */ +#define REV_TREE_OLD 2 /* Only files removed */ +#define REV_TREE_DIFFERENT 3 /* Mixed changes */ static int tree_difference = REV_TREE_SAME; static void file_add_remove(struct diff_options *options, - int addremove, unsigned mode, - const struct object_id *oid, - int oid_valid, - const char *fullpath, unsigned dirty_submodule) + int addremove, + unsigned mode UNUSED, + const struct object_id *oid UNUSED, + int oid_valid UNUSED, + const char *fullpath UNUSED, + unsigned dirty_submodule UNUSED) { int diff = addremove == '+' ? REV_TREE_NEW : REV_TREE_OLD; struct rev_info *revs = options->change_fn_data; @@ -623,12 +616,15 @@ static void file_add_remove(struct diff_options *options, } static void file_change(struct diff_options *options, - unsigned old_mode, unsigned new_mode, - const struct object_id *old_oid, - const struct object_id *new_oid, - int old_oid_valid, int new_oid_valid, - const char *fullpath, - unsigned old_dirty_submodule, unsigned new_dirty_submodule) + unsigned old_mode UNUSED, + unsigned new_mode UNUSED, + const struct object_id *old_oid UNUSED, + const struct object_id *new_oid UNUSED, + int old_oid_valid UNUSED, + int new_oid_valid UNUSED, + const char *fullpath UNUSED, + unsigned old_dirty_submodule UNUSED, + unsigned new_dirty_submodule UNUSED) { tree_difference = REV_TREE_DIFFERENT; options->flags.has_changes = 1; @@ -1100,7 +1096,7 @@ static int process_parents(struct rev_info *revs, struct commit *commit, struct commit_list **list, struct prio_queue *queue) { struct commit_list *parent = commit->parents; - unsigned left_flag; + unsigned pass_flags; if (commit->object.flags & ADDED) return 0; @@ -1155,7 +1151,7 @@ static int process_parents(struct rev_info *revs, struct commit *commit, if (revs->no_walk) return 0; - left_flag = (commit->object.flags & SYMMETRIC_LEFT); + pass_flags = (commit->object.flags & (SYMMETRIC_LEFT | ANCESTRY_PATH)); for (parent = commit->parents; parent; parent = parent->next) { struct commit *p = parent->item; @@ -1176,7 +1172,7 @@ static int process_parents(struct rev_info *revs, struct commit *commit, if (!*slot) *slot = *revision_sources_at(revs->sources, commit); } - p->object.flags |= left_flag; + p->object.flags |= pass_flags; if (!(p->object.flags & SEEN)) { p->object.flags |= (SEEN | NOT_USER_GIVEN); if (list) @@ -1299,13 +1295,24 @@ static int still_interesting(struct commit_list *src, timestamp_t date, int slop } /* - * "rev-list --ancestry-path A..B" computes commits that are ancestors - * of B but not ancestors of A but further limits the result to those - * that are descendants of A. This takes the list of bottom commits and - * the result of "A..B" without --ancestry-path, and limits the latter - * further to the ones that can reach one of the commits in "bottom". + * "rev-list --ancestry-path=C_0 [--ancestry-path=C_1 ...] A..B" + * computes commits that are ancestors of B but not ancestors of A but + * further limits the result to those that have any of C in their + * ancestry path (i.e. are either ancestors of any of C, descendants + * of any of C, or are any of C). If --ancestry-path is specified with + * no commit, we use all bottom commits for C. + * + * Before this function is called, ancestors of C will have already + * been marked with ANCESTRY_PATH previously. + * + * This takes the list of bottom commits and the result of "A..B" + * without --ancestry-path, and limits the latter further to the ones + * that have any of C in their ancestry path. Since the ancestors of C + * have already been marked (a prerequisite of this function), we just + * need to mark the descendants, then exclude any commit that does not + * have any of these marks. */ -static void limit_to_ancestry(struct commit_list *bottom, struct commit_list *list) +static void limit_to_ancestry(struct commit_list *bottoms, struct commit_list *list) { struct commit_list *p; struct commit_list *rlist = NULL; @@ -1318,7 +1325,7 @@ static void limit_to_ancestry(struct commit_list *bottom, struct commit_list *li for (p = list; p; p = p->next) commit_list_insert(p->item, &rlist); - for (p = bottom; p; p = p->next) + for (p = bottoms; p; p = p->next) p->item->object.flags |= TMP_MARK; /* @@ -1351,38 +1358,39 @@ static void limit_to_ancestry(struct commit_list *bottom, struct commit_list *li */ /* - * The ones that are not marked with TMP_MARK are uninteresting + * The ones that are not marked with either TMP_MARK or + * ANCESTRY_PATH are uninteresting */ for (p = list; p; p = p->next) { struct commit *c = p->item; - if (c->object.flags & TMP_MARK) + if (c->object.flags & (TMP_MARK | ANCESTRY_PATH)) continue; c->object.flags |= UNINTERESTING; } - /* We are done with the TMP_MARK */ + /* We are done with TMP_MARK and ANCESTRY_PATH */ for (p = list; p; p = p->next) - p->item->object.flags &= ~TMP_MARK; - for (p = bottom; p; p = p->next) - p->item->object.flags &= ~TMP_MARK; + p->item->object.flags &= ~(TMP_MARK | ANCESTRY_PATH); + for (p = bottoms; p; p = p->next) + p->item->object.flags &= ~(TMP_MARK | ANCESTRY_PATH); free_commit_list(rlist); } /* - * Before walking the history, keep the set of "negative" refs the - * caller has asked to exclude. + * Before walking the history, add the set of "negative" refs the + * caller has asked to exclude to the bottom list. * * This is used to compute "rev-list --ancestry-path A..B", as we need * to filter the result of "A..B" further to the ones that can actually * reach A. */ -static struct commit_list *collect_bottom_commits(struct commit_list *list) +static void collect_bottom_commits(struct commit_list *list, + struct commit_list **bottom) { - struct commit_list *elem, *bottom = NULL; + struct commit_list *elem; for (elem = list; elem; elem = elem->next) if (elem->item->object.flags & BOTTOM) - commit_list_insert(elem->item, &bottom); - return bottom; + commit_list_insert(elem->item, bottom); } /* Assumes either left_only or right_only is set */ @@ -1409,12 +1417,12 @@ static int limit_list(struct rev_info *revs) struct commit_list *original_list = revs->commits; struct commit_list *newlist = NULL; struct commit_list **p = &newlist; - struct commit_list *bottom = NULL; struct commit *interesting_cache = NULL; - if (revs->ancestry_path) { - bottom = collect_bottom_commits(original_list); - if (!bottom) + if (revs->ancestry_path_implicit_bottoms) { + collect_bottom_commits(original_list, + &revs->ancestry_path_bottoms); + if (!revs->ancestry_path_bottoms) die("--ancestry-path given but there are no bottom commits"); } @@ -1440,6 +1448,9 @@ static int limit_list(struct rev_info *revs) if (revs->min_age != -1 && (commit->date > revs->min_age) && !revs->line_level_traverse) continue; + if (revs->max_age_as_filter != -1 && + (commit->date < revs->max_age_as_filter) && !revs->line_level_traverse) + continue; date = commit->date; p = &commit_list_insert(commit, p)->next; @@ -1456,10 +1467,8 @@ static int limit_list(struct rev_info *revs) if (revs->left_only || revs->right_only) limit_left_right(newlist, revs); - if (bottom) { - limit_to_ancestry(bottom, newlist); - free_commit_list(bottom); - } + if (revs->ancestry_path) + limit_to_ancestry(revs->ancestry_path_bottoms, newlist); /* * Check if any commits have become TREESAME by some of their parents @@ -1514,34 +1523,85 @@ static void add_rev_cmdline_list(struct rev_info *revs, } } -struct all_refs_cb { - int all_flags; - int warned_bad_reflog; - struct rev_info *all_revs; - const char *name_for_errormsg; - struct worktree *wt; -}; - -int ref_excluded(struct string_list *ref_excludes, const char *path) +int ref_excluded(const struct ref_exclusions *exclusions, const char *path) { + const char *stripped_path = strip_namespace(path); struct string_list_item *item; - if (!ref_excludes) - return 0; - for_each_string_list_item(item, ref_excludes) { + for_each_string_list_item(item, &exclusions->excluded_refs) { if (!wildmatch(item->string, path, 0)) return 1; } + + if (ref_is_hidden(stripped_path, path, &exclusions->hidden_refs)) + return 1; + return 0; } +void init_ref_exclusions(struct ref_exclusions *exclusions) +{ + struct ref_exclusions blank = REF_EXCLUSIONS_INIT; + memcpy(exclusions, &blank, sizeof(*exclusions)); +} + +void clear_ref_exclusions(struct ref_exclusions *exclusions) +{ + string_list_clear(&exclusions->excluded_refs, 0); + string_list_clear(&exclusions->hidden_refs, 0); + exclusions->hidden_refs_configured = 0; +} + +void add_ref_exclusion(struct ref_exclusions *exclusions, const char *exclude) +{ + string_list_append(&exclusions->excluded_refs, exclude); +} + +struct exclude_hidden_refs_cb { + struct ref_exclusions *exclusions; + const char *section; +}; + +static int hide_refs_config(const char *var, const char *value, void *cb_data) +{ + struct exclude_hidden_refs_cb *cb = cb_data; + cb->exclusions->hidden_refs_configured = 1; + return parse_hide_refs_config(var, value, cb->section, + &cb->exclusions->hidden_refs); +} + +void exclude_hidden_refs(struct ref_exclusions *exclusions, const char *section) +{ + struct exclude_hidden_refs_cb cb; + + if (strcmp(section, "receive") && strcmp(section, "uploadpack")) + die(_("unsupported section for hidden refs: %s"), section); + + if (exclusions->hidden_refs_configured) + die(_("--exclude-hidden= passed more than once")); + + cb.exclusions = exclusions; + cb.section = section; + + git_config(hide_refs_config, &cb); +} + +struct all_refs_cb { + int all_flags; + int warned_bad_reflog; + struct rev_info *all_revs; + const char *name_for_errormsg; + struct worktree *wt; +}; + static int handle_one_ref(const char *path, const struct object_id *oid, - int flag, void *cb_data) + int flag UNUSED, + void *cb_data) { struct all_refs_cb *cb = cb_data; struct object *object; - if (ref_excluded(cb->all_revs->ref_excludes, path)) + if (ref_excluded(&cb->all_revs->ref_excludes, path)) return 0; object = get_reference(cb->all_revs, path, oid, cb->all_flags); @@ -1559,24 +1619,6 @@ static void init_all_refs_cb(struct all_refs_cb *cb, struct rev_info *revs, cb->wt = NULL; } -void clear_ref_exclusion(struct string_list **ref_excludes_p) -{ - if (*ref_excludes_p) { - string_list_clear(*ref_excludes_p, 0); - free(*ref_excludes_p); - } - *ref_excludes_p = NULL; -} - -void add_ref_exclusion(struct string_list **ref_excludes_p, const char *exclude) -{ - if (!*ref_excludes_p) { - CALLOC_ARRAY(*ref_excludes_p, 1); - (*ref_excludes_p)->strdup_strings = 1; - } - string_list_append(*ref_excludes_p, exclude); -} - static void handle_refs(struct ref_store *refs, struct rev_info *revs, unsigned flags, int (*for_each)(struct ref_store *, each_ref_fn, void *)) @@ -1611,8 +1653,11 @@ 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, - const char *email, timestamp_t timestamp, int tz, - const char *message, void *cb_data) + const char *email UNUSED, + timestamp_t timestamp UNUSED, + int tz UNUSED, + const char *message UNUSED, + void *cb_data) { handle_one_reflog_commit(ooid, cb_data); handle_one_reflog_commit(noid, cb_data); @@ -1620,8 +1665,8 @@ static int handle_one_reflog_ent(struct object_id *ooid, struct object_id *noid, } static int handle_one_reflog(const char *refname_in_wt, - const struct object_id *oid, - int flag, void *cb_data) + const struct object_id *oid UNUSED, + int flag UNUSED, void *cb_data) { struct all_refs_cb *cb = cb_data; struct strbuf refname = STRBUF_INIT; @@ -1690,6 +1735,39 @@ static void add_cache_tree(struct cache_tree *it, struct rev_info *revs, } +static void add_resolve_undo_to_pending(struct index_state *istate, struct rev_info *revs) +{ + struct string_list_item *item; + struct string_list *resolve_undo = istate->resolve_undo; + + if (!resolve_undo) + return; + + for_each_string_list_item(item, resolve_undo) { + const char *path = item->string; + struct resolve_undo_info *ru = item->util; + int i; + + if (!ru) + continue; + for (i = 0; i < 3; i++) { + struct blob *blob; + + if (!ru->mode[i] || !S_ISREG(ru->mode[i])) + continue; + + blob = lookup_blob(revs->repo, &ru->oid[i]); + if (!blob) { + warning(_("resolve-undo records `%s` which is missing"), + oid_to_hex(&ru->oid[i])); + continue; + } + add_pending_object_with_path(revs, &blob->object, "", + ru->mode[i], path); + } + } +} + static void do_add_index_objects_to_pending(struct rev_info *revs, struct index_state *istate, unsigned int flags) @@ -1718,6 +1796,8 @@ static void do_add_index_objects_to_pending(struct rev_info *revs, add_cache_tree(istate->cache_tree, revs, &path, flags); strbuf_release(&path); } + + add_resolve_undo_to_pending(istate, revs); } void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags) @@ -1823,29 +1903,15 @@ void repo_init_revisions(struct repository *r, struct rev_info *revs, const char *prefix) { - memset(revs, 0, sizeof(*revs)); + struct rev_info blank = REV_INFO_INIT; + memcpy(revs, &blank, sizeof(*revs)); revs->repo = r; - revs->abbrev = DEFAULT_ABBREV; - revs->simplify_history = 1; revs->pruning.repo = r; - revs->pruning.flags.recursive = 1; - revs->pruning.flags.quick = 1; revs->pruning.add_remove = file_add_remove; revs->pruning.change = file_change; revs->pruning.change_fn_data = revs; - revs->sort_order = REV_SORT_IN_GRAPH_ORDER; - revs->dense = 1; revs->prefix = prefix; - revs->max_age = -1; - revs->min_age = -1; - revs->skip_count = -1; - revs->max_count = -1; - revs->max_parents = -1; - revs->expand_tabs_in_log = -1; - - revs->commit_format = CMIT_FMT_DEFAULT; - revs->expand_tabs_in_log_default = 8; grep_init(&revs->grep_filter, revs->repo); revs->grep_filter.status_only = 1; @@ -1857,6 +1923,8 @@ 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); } static void add_pending_commit_list(struct rev_info *revs, @@ -2069,9 +2137,8 @@ static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int fl int exclude_parent = 1; if (mark[2]) { - char *end; - exclude_parent = strtoul(mark + 2, &end, 10); - if (*end != '\0' || !exclude_parent) + if (strtol_i(mark + 2, 10, &exclude_parent) || + exclude_parent < 1) return -1; } @@ -2170,7 +2237,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg const struct setup_revision_opt* opt) { const char *arg = argv[0]; - const char *optarg; + const char *optarg = NULL; int argcount; const unsigned hexsz = the_hash_algo->hexsz; @@ -2182,7 +2249,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg !strcmp(arg, "--bisect") || starts_with(arg, "--glob=") || !strcmp(arg, "--indexed-objects") || !strcmp(arg, "--alternate-refs") || - starts_with(arg, "--exclude=") || + starts_with(arg, "--exclude=") || starts_with(arg, "--exclude-hidden=") || starts_with(arg, "--branches=") || starts_with(arg, "--tags=") || starts_with(arg, "--remotes=") || starts_with(arg, "--no-walk=")) { @@ -2218,6 +2285,9 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg } else if ((argcount = parse_long_opt("since", argv, &optarg))) { revs->max_age = approxidate(optarg); return argcount; + } else if ((argcount = parse_long_opt("since-as-filter", argv, &optarg))) { + revs->max_age_as_filter = approxidate(optarg); + return argcount; } else if ((argcount = parse_long_opt("after", argv, &optarg))) { revs->max_age = approxidate(optarg); return argcount; @@ -2238,6 +2308,23 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg revs->ancestry_path = 1; revs->simplify_history = 0; revs->limited = 1; + revs->ancestry_path_implicit_bottoms = 1; + } 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"); + + revs->ancestry_path = 1; + revs->simplify_history = 0; + revs->limited = 1; + + if (repo_get_oid_committish(revs->repo, optarg, &oid)) + return error(msg, optarg); + get_reference(revs, optarg, &oid, ANCESTRY_PATH); + c = lookup_commit_reference(revs->repo, &oid); + if (!c) + return error(msg, optarg); + commit_list_insert(c, &revs->ancestry_path_bottoms); } else if (!strcmp(arg, "-g") || !strcmp(arg, "--walk-reflogs")) { init_reflog_walk(&revs->reflog_info); } else if (!strcmp(arg, "--default")) { @@ -2352,6 +2439,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg revs->tree_objects = 1; revs->blob_objects = 1; revs->verify_objects = 1; + disable_commit_graph(revs->repo); } else if (!strcmp(arg, "--unpacked")) { revs->unpacked = 1; } else if (starts_with(arg, "--unpacked=")) { @@ -2625,10 +2713,12 @@ static int handle_revision_pseudo_opt(struct rev_info *revs, init_all_refs_cb(&cb, revs, *flags); other_head_refs(handle_one_ref, &cb); } - clear_ref_exclusion(&revs->ref_excludes); + 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")); handle_refs(refs, revs, *flags, refs_for_each_branch_ref); - clear_ref_exclusion(&revs->ref_excludes); + clear_ref_exclusions(&revs->ref_excludes); } else if (!strcmp(arg, "--bisect")) { read_bisect_terms(&term_bad, &term_good); handle_refs(refs, revs, *flags, for_each_bad_bisect_ref); @@ -2636,35 +2726,48 @@ static int handle_revision_pseudo_opt(struct rev_info *revs, for_each_good_bisect_ref); 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")); handle_refs(refs, revs, *flags, refs_for_each_tag_ref); - clear_ref_exclusion(&revs->ref_excludes); + 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")); handle_refs(refs, revs, *flags, refs_for_each_remote_ref); - clear_ref_exclusion(&revs->ref_excludes); + clear_ref_exclusions(&revs->ref_excludes); } 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); - clear_ref_exclusion(&revs->ref_excludes); + clear_ref_exclusions(&revs->ref_excludes); return argcount; } else if ((argcount = parse_long_opt("exclude", argv, &optarg))) { add_ref_exclusion(&revs->ref_excludes, optarg); return argcount; + } else if ((argcount = parse_long_opt("exclude-hidden", argv, &optarg))) { + exclude_hidden_refs(&revs->ref_excludes, optarg); + return argcount; } 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")); init_all_refs_cb(&cb, revs, *flags); for_each_glob_ref_in(handle_one_ref, optarg, "refs/heads/", &cb); - clear_ref_exclusion(&revs->ref_excludes); + 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")); init_all_refs_cb(&cb, revs, *flags); for_each_glob_ref_in(handle_one_ref, optarg, "refs/tags/", &cb); - clear_ref_exclusion(&revs->ref_excludes); + 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")); init_all_refs_cb(&cb, revs, *flags); for_each_glob_ref_in(handle_one_ref, optarg, "refs/remotes/", &cb); - clear_ref_exclusion(&revs->ref_excludes); + clear_ref_exclusions(&revs->ref_excludes); } else if (!strcmp(arg, "--reflog")) { add_reflogs_to_pending(revs, *flags); } else if (!strcmp(arg, "--indexed-objects")) { @@ -2738,6 +2841,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s const char *arg = argv[i]; if (strcmp(arg, "--")) continue; + if (opt && opt->free_removed_argv_elements) + free((char *)argv[i]); argv[i] = NULL; argc = i; if (argv[i + 1]) @@ -2833,7 +2938,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s } strvec_clear(&prune_data); - if (revs->def == NULL) + if (!revs->def) revs->def = opt ? opt->def : NULL; if (opt && opt->tweak) opt->tweak(revs, opt); @@ -2923,6 +3028,44 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s return left; } +static void release_revisions_cmdline(struct rev_cmdline_info *cmdline) +{ + unsigned int i; + + for (i = 0; i < cmdline->nr; i++) + free((char *)cmdline->rev[i].name); + free(cmdline->rev); +} + +static void release_revisions_mailmap(struct string_list *mailmap) +{ + if (!mailmap) + return; + clear_mailmap(mailmap); + free(mailmap); +} + +static void release_revisions_topo_walk_info(struct topo_walk_info *info); + +void release_revisions(struct rev_info *revs) +{ + free_commit_list(revs->commits); + free_commit_list(revs->ancestry_path_bottoms); + object_array_clear(&revs->pending); + object_array_clear(&revs->boundary_commits); + release_revisions_cmdline(&revs->cmdline); + list_objects_filter_release(&revs->filter); + clear_pathspec(&revs->prune_data); + date_mode_release(&revs->date_mode); + 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->pruning); + reflog_walk_info_release(revs->reflog_info); + release_revisions_topo_walk_info(revs->topo_walk_info); +} + static void add_child(struct rev_info *revs, struct commit *parent, struct commit *child) { struct commit_list *l = xcalloc(1, sizeof(*l)); @@ -3433,17 +3576,22 @@ static void compute_indegrees_to_depth(struct rev_info *revs, indegree_walk_step(revs); } -static void reset_topo_walk(struct rev_info *revs) +static void release_revisions_topo_walk_info(struct topo_walk_info *info) { - struct topo_walk_info *info = revs->topo_walk_info; - + if (!info) + return; clear_prio_queue(&info->explore_queue); clear_prio_queue(&info->indegree_queue); clear_prio_queue(&info->topo_queue); clear_indegree_slab(&info->indegree); clear_author_date_slab(&info->author_date); + free(info); +} - FREE_AND_NULL(revs->topo_walk_info); +static void reset_topo_walk(struct rev_info *revs) +{ + release_revisions_topo_walk_info(revs->topo_walk_info); + revs->topo_walk_info = NULL; } static void init_topo_walk(struct rev_info *revs) @@ -3652,7 +3800,7 @@ static enum rewrite_result rewrite_one_1(struct rev_info *revs, return rewrite_one_ok; if (!p->parents) return rewrite_one_noparents; - if ((p = one_relevant_parent(revs, p->parents)) == NULL) + if (!(p = one_relevant_parent(revs, p->parents))) return rewrite_one_ok; *pp = p; } @@ -3704,51 +3852,6 @@ int rewrite_parents(struct rev_info *revs, struct commit *commit, return 0; } -static int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap) -{ - char *person, *endp; - size_t len, namelen, maillen; - const char *name; - const char *mail; - struct ident_split ident; - - person = strstr(buf->buf, what); - if (!person) - return 0; - - person += strlen(what); - endp = strchr(person, '\n'); - if (!endp) - return 0; - - len = endp - person; - - if (split_ident_line(&ident, person, len)) - return 0; - - mail = ident.mail_begin; - maillen = ident.mail_end - ident.mail_begin; - name = ident.name_begin; - namelen = ident.name_end - ident.name_begin; - - if (map_user(mailmap, &mail, &maillen, &name, &namelen)) { - struct strbuf namemail = STRBUF_INIT; - - strbuf_addf(&namemail, "%.*s <%.*s>", - (int)namelen, name, (int)maillen, mail); - - strbuf_splice(buf, ident.name_begin - buf->buf, - ident.mail_end - ident.name_begin + 1, - namemail.buf, namemail.len); - - strbuf_release(&namemail); - - return 1; - } - - return 0; -} - static int commit_match(struct commit *commit, struct rev_info *opt) { int retval; @@ -3781,11 +3884,12 @@ static int commit_match(struct commit *commit, struct rev_info *opt) strbuf_addstr(&buf, message); if (opt->grep_filter.header_list && opt->mailmap) { + const char *commit_headers[] = { "author ", "committer ", NULL }; + if (!buf.len) strbuf_addstr(&buf, message); - commit_rewrite_person(&buf, "\nauthor ", opt->mailmap); - commit_rewrite_person(&buf, "\ncommitter ", opt->mailmap); + apply_mailmap_to_header(&buf, commit_headers, opt->mailmap); } /* Append "fake" message parts as needed */ @@ -3862,6 +3966,9 @@ enum commit_action get_commit_action(struct rev_info *revs, struct commit *commi if (revs->min_age != -1 && comparison_date(revs, commit) > revs->min_age) return commit_ignore; + if (revs->max_age_as_filter != -1 && + comparison_date(revs, commit) < revs->max_age_as_filter) + return commit_ignore; if (revs->min_parents || (revs->max_parents >= 0)) { int n = commit_list_count(commit->parents); if ((n < revs->min_parents) || @@ -4080,10 +4187,8 @@ static void create_boundary_commit_list(struct rev_info *revs) * boundary commits anyway. (This is what the code has always * done.) */ - if (revs->commits) { - free_commit_list(revs->commits); - revs->commits = NULL; - } + free_commit_list(revs->commits); + revs->commits = NULL; /* * Put all of the actual boundary commits from revs->boundary_commits @@ -4220,10 +4325,8 @@ struct commit *get_revision(struct rev_info *revs) graph_update(revs->graph, c); if (!c) { free_saved_parents(revs); - if (revs->previous_parents) { - free_commit_list(revs->previous_parents); - revs->previous_parents = NULL; - } + free_commit_list(revs->previous_parents); + revs->previous_parents = NULL; } return c; } |
