summaryrefslogtreecommitdiff
path: root/revision.c
diff options
context:
space:
mode:
Diffstat (limited to 'revision.c')
-rw-r--r--revision.c370
1 files changed, 300 insertions, 70 deletions
diff --git a/revision.c b/revision.c
index 8136929e23..9dff845bed 100644
--- a/revision.c
+++ b/revision.c
@@ -23,12 +23,14 @@
#include "bisect.h"
#include "packfile.h"
#include "worktree.h"
-#include "argv-array.h"
+#include "strvec.h"
#include "commit-reach.h"
#include "commit-graph.h"
#include "prio-queue.h"
#include "hashmap.h"
#include "utf8.h"
+#include "bloom.h"
+#include "json-writer.h"
volatile show_early_output_fn_t show_early_output;
@@ -37,6 +39,8 @@ static const 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)
{
const char *p;
@@ -120,11 +124,6 @@ static int path_and_oids_cmp(const void *hashmap_cmp_fn_data,
return strcmp(e1->path, e2->path);
}
-static void paths_and_oids_init(struct hashmap *map)
-{
- hashmap_init(map, path_and_oids_cmp, NULL, 0);
-}
-
static void paths_and_oids_clear(struct hashmap *map)
{
struct hashmap_iter iter;
@@ -135,7 +134,7 @@ static void paths_and_oids_clear(struct hashmap *map)
free(entry->path);
}
- hashmap_free_entries(map, struct path_and_oids_entry, ent);
+ hashmap_clear_and_free(map, struct path_and_oids_entry, ent);
}
static void paths_and_oids_insert(struct hashmap *map,
@@ -209,7 +208,7 @@ void mark_trees_uninteresting_sparse(struct repository *r,
struct oidset *trees)
{
unsigned has_interesting = 0, has_uninteresting = 0;
- struct hashmap map;
+ struct hashmap map = HASHMAP_INIT(path_and_oids_cmp, NULL);
struct hashmap_iter map_iter;
struct path_and_oids_entry *entry;
struct object_id *oid;
@@ -233,8 +232,6 @@ void mark_trees_uninteresting_sparse(struct repository *r,
if (!has_uninteresting || !has_interesting)
return;
- paths_and_oids_init(&map);
-
oidset_iter_init(trees, &iter);
while ((oid = oidset_iter_next(&iter))) {
struct tree *tree = lookup_tree(r, oid);
@@ -311,13 +308,14 @@ static void add_pending_object_with_path(struct rev_info *revs,
const char *name, unsigned mode,
const char *path)
{
+ struct interpret_branch_name_options options = { 0 };
if (!obj)
return;
if (revs->no_walk && (obj->flags & UNINTERESTING))
revs->no_walk = 0;
if (revs->reflog_info && obj->type == OBJ_COMMIT) {
struct strbuf buf = STRBUF_INIT;
- int len = interpret_branch_name(name, 0, &buf, 0);
+ int len = interpret_branch_name(name, 0, &buf, &options);
if (0 < len && name[len] && buf.len)
strbuf_addstr(&buf, name + len);
@@ -435,7 +433,7 @@ static struct commit *handle_commit(struct rev_info *revs,
if (object->type == OBJ_COMMIT) {
struct commit *commit = (struct commit *)object;
- if (parse_commit(commit) < 0)
+ if (repo_parse_commit(revs->repo, commit) < 0)
die("unable to parse commit %s", name);
if (flags & UNINTERESTING) {
mark_parents_uninteresting(commit);
@@ -624,11 +622,156 @@ static void file_change(struct diff_options *options,
options->flags.has_changes = 1;
}
+static int bloom_filter_atexit_registered;
+static unsigned int count_bloom_filter_maybe;
+static unsigned int count_bloom_filter_definitely_not;
+static unsigned int count_bloom_filter_false_positive;
+static unsigned int count_bloom_filter_not_present;
+
+static void trace2_bloom_filter_statistics_atexit(void)
+{
+ struct json_writer jw = JSON_WRITER_INIT;
+
+ jw_object_begin(&jw, 0);
+ jw_object_intmax(&jw, "filter_not_present", count_bloom_filter_not_present);
+ jw_object_intmax(&jw, "maybe", count_bloom_filter_maybe);
+ jw_object_intmax(&jw, "definitely_not", count_bloom_filter_definitely_not);
+ jw_object_intmax(&jw, "false_positive", count_bloom_filter_false_positive);
+ jw_end(&jw);
+
+ trace2_data_json("bloom", the_repository, "statistics", &jw);
+
+ jw_release(&jw);
+}
+
+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))
+ return 1;
+
+ return 0;
+}
+
+static void prepare_to_use_bloom_filter(struct rev_info *revs)
+{
+ struct pathspec_item *pi;
+ char *path_alloc = NULL;
+ const char *path, *p;
+ size_t len;
+ int path_component_nr = 1;
+
+ if (!revs->commits)
+ return;
+
+ if (forbid_bloom_filters(&revs->prune_data))
+ return;
+
+ repo_parse_commit(revs->repo, revs->commits->item);
+
+ revs->bloom_filter_settings = get_bloom_filter_settings(revs->repo);
+ if (!revs->bloom_filter_settings)
+ return;
+
+ 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;
+
+ 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--;
+ }
+
+ if (trace2_is_enabled() && !bloom_filter_atexit_registered) {
+ atexit(trace2_bloom_filter_statistics_atexit);
+ bloom_filter_atexit_registered = 1;
+ }
+
+ free(path_alloc);
+}
+
+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;
+
+ if (commit_graph_generation(commit) == GENERATION_NUMBER_INFINITY)
+ return -1;
+
+ filter = get_bloom_filter(revs->repo, commit);
+
+ if (!filter) {
+ count_bloom_filter_not_present++;
+ 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);
+ }
+
+ if (result)
+ count_bloom_filter_maybe++;
+ else
+ count_bloom_filter_definitely_not++;
+
+ return result;
+}
+
static int rev_compare_tree(struct rev_info *revs,
- struct commit *parent, struct commit *commit)
+ struct commit *parent, struct commit *commit, int nth_parent)
{
struct tree *t1 = get_commit_tree(parent);
struct tree *t2 = get_commit_tree(commit);
+ int bloom_ret = 1;
if (!t1)
return REV_TREE_NEW;
@@ -653,17 +796,26 @@ static int rev_compare_tree(struct rev_info *revs,
return REV_TREE_SAME;
}
+ if (revs->bloom_keys_nr && !nth_parent) {
+ bloom_ret = check_maybe_different_in_bloom_filter(revs, commit);
+
+ if (bloom_ret == 0)
+ return REV_TREE_SAME;
+ }
+
tree_difference = REV_TREE_SAME;
revs->pruning.flags.has_changes = 0;
- if (diff_tree_oid(&t1->object.oid, &t2->object.oid, "",
- &revs->pruning) < 0)
- return REV_TREE_DIFFERENT;
+ diff_tree_oid(&t1->object.oid, &t2->object.oid, "", &revs->pruning);
+
+ if (!nth_parent)
+ if (bloom_ret == 1 && tree_difference == REV_TREE_SAME)
+ count_bloom_filter_false_positive++;
+
return tree_difference;
}
static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit)
{
- int retval;
struct tree *t1 = get_commit_tree(commit);
if (!t1)
@@ -671,9 +823,9 @@ static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit)
tree_difference = REV_TREE_SAME;
revs->pruning.flags.has_changes = 0;
- retval = diff_tree_oid(NULL, &t1->object.oid, "", &revs->pruning);
+ diff_tree_oid(NULL, &t1->object.oid, "", &revs->pruning);
- return retval >= 0 && (tree_difference == REV_TREE_SAME);
+ return tree_difference == REV_TREE_SAME;
}
struct treesame_state {
@@ -851,11 +1003,11 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
ts->treesame[0] = 1;
}
}
- if (parse_commit(p) < 0)
+ if (repo_parse_commit(revs->repo, p) < 0)
die("cannot simplify commit %s (because of %s)",
oid_to_hex(&commit->object.oid),
oid_to_hex(&p->object.oid));
- switch (rev_compare_tree(revs, p, commit)) {
+ switch (rev_compare_tree(revs, p, commit, nth_parent)) {
case REV_TREE_SAME:
if (!revs->simplify_history || !relevant_commit(p)) {
/* Even if a merge with an uninteresting
@@ -870,7 +1022,19 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
}
parent->next = NULL;
commit->parents = parent;
- commit->object.flags |= TREESAME;
+
+ /*
+ * A merge commit is a "diversion" if it is not
+ * TREESAME to its first parent but is TREESAME
+ * to a later parent. In the simplified history,
+ * we "divert" the history walk to the later
+ * parent. These commits are shown when "show_pulls"
+ * is enabled, so do not mark the object as
+ * TREESAME here.
+ */
+ if (!revs->show_pulls || !nth_parent)
+ commit->object.flags |= TREESAME;
+
return;
case REV_TREE_NEW:
@@ -884,7 +1048,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
* IOW, we pretend this parent is a
* "root" commit.
*/
- if (parse_commit(p) < 0)
+ if (repo_parse_commit(revs->repo, p) < 0)
die("cannot simplify commit %s (invalid %s)",
oid_to_hex(&commit->object.oid),
oid_to_hex(&p->object.oid));
@@ -897,6 +1061,10 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
relevant_change = 1;
else
irrelevant_change = 1;
+
+ if (!nth_parent)
+ commit->object.flags |= PULL_MERGE;
+
continue;
}
die("bad tree compare for commit %s", oid_to_hex(&commit->object.oid));
@@ -948,7 +1116,7 @@ static int process_parents(struct rev_info *revs, struct commit *commit,
parent = parent->next;
if (p)
p->object.flags |= UNINTERESTING;
- if (parse_commit_gently(p, 1) < 0)
+ if (repo_parse_commit_gently(revs->repo, p, 1) < 0)
continue;
if (p->parents)
mark_parents_uninteresting(p);
@@ -979,7 +1147,7 @@ static int process_parents(struct rev_info *revs, struct commit *commit,
struct commit *p = parent->item;
int gently = revs->ignore_missing_links ||
revs->exclude_promisor_objects;
- if (parse_commit_gently(p, gently) < 0) {
+ if (repo_parse_commit_gently(revs->repo, p, gently) < 0) {
if (revs->exclude_promisor_objects &&
is_promisor_object(&p->object.oid)) {
if (revs->first_parent_only)
@@ -1253,7 +1421,8 @@ static int limit_list(struct rev_info *revs)
continue;
break;
}
- if (revs->min_age != -1 && (commit->date > revs->min_age))
+ if (revs->min_age != -1 && (commit->date > revs->min_age) &&
+ !revs->line_level_traverse)
continue;
date = commit->date;
p = &commit_list_insert(commit, p)->next;
@@ -1452,7 +1621,7 @@ static void add_other_reflogs_to_pending(struct all_refs_cb *cb)
{
struct worktree **worktrees, **p;
- worktrees = get_worktrees(0);
+ worktrees = get_worktrees();
for (p = worktrees; *p; p++) {
struct worktree *wt = *p;
@@ -1540,7 +1709,7 @@ void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags)
if (revs->single_worktree)
return;
- worktrees = get_worktrees(0);
+ worktrees = get_worktrees();
for (p = worktrees; *p; p++) {
struct worktree *wt = *p;
struct index_state istate = { NULL };
@@ -1637,7 +1806,7 @@ void repo_init_revisions(struct repository *r,
revs->repo = r;
revs->abbrev = DEFAULT_ABBREV;
- revs->ignore_merges = 1;
+ revs->ignore_merges = -1;
revs->simplify_history = 1;
revs->pruning.repo = r;
revs->pruning.flags.recursive = 1;
@@ -1658,7 +1827,6 @@ void repo_init_revisions(struct repository *r,
revs->commit_format = CMIT_FMT_DEFAULT;
revs->expand_tabs_in_log_default = 8;
- init_grep_defaults(revs->repo);
grep_init(&revs->grep_filter, revs->repo, prefix);
revs->grep_filter.status_only = 1;
@@ -1839,7 +2007,7 @@ static int handle_dotdot(const char *arg,
return ret;
}
-int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsigned revarg_opt)
+static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int flags, unsigned revarg_opt)
{
struct object_context oc;
char *mark;
@@ -1914,15 +2082,23 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi
return 0;
}
+int handle_revision_arg(const char *arg, struct rev_info *revs, int flags, unsigned revarg_opt)
+{
+ int ret = handle_revision_arg_1(arg, revs, flags, revarg_opt);
+ if (!ret)
+ revs->rev_input_given = 1;
+ return ret;
+}
+
static void read_pathspec_from_stdin(struct strbuf *sb,
- struct argv_array *prune)
+ struct strvec *prune)
{
while (strbuf_getline(sb, stdin) != EOF)
- argv_array_push(prune, sb->buf);
+ strvec_push(prune, sb->buf);
}
static void read_revisions_from_stdin(struct rev_info *revs,
- struct argv_array *prune)
+ struct strvec *prune)
{
struct strbuf sb;
int seen_dashdash = 0;
@@ -2157,7 +2333,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
} else if (!strcmp(arg, "--unpacked")) {
revs->unpacked = 1;
} else if (starts_with(arg, "--unpacked=")) {
- die("--unpacked=<packfile> no longer supported.");
+ die(_("--unpacked=<packfile> no longer supported"));
} else if (!strcmp(arg, "-r")) {
revs->diff = 1;
revs->diffopt.flags.recursive = 1;
@@ -2166,7 +2342,22 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
revs->diffopt.flags.recursive = 1;
revs->diffopt.flags.tree_in_recursive = 1;
} else if (!strcmp(arg, "-m")) {
+ /*
+ * To "diff-index", "-m" means "match missing", and to the "log"
+ * family of commands, it means "show full diff for merges". Set
+ * both fields appropriately.
+ */
revs->ignore_merges = 0;
+ revs->match_missing = 1;
+ } else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
+ if (!strcmp(optarg, "off")) {
+ revs->ignore_merges = 1;
+ } else {
+ die(_("unknown value for --diff-merges: %s"), optarg);
+ }
+ return argcount;
+ } else if (!strcmp(arg, "--no-diff-merges")) {
+ revs->ignore_merges = 1;
} else if (!strcmp(arg, "-c")) {
revs->diff = 1;
revs->dense_combined_merges = 0;
@@ -2241,6 +2432,10 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
revs->topo_order = 1;
revs->rewrite_parents = 1;
revs->graph = graph_init(revs);
+ } else if (!strcmp(arg, "--encode-email-headers")) {
+ revs->encode_email_headers = 1;
+ } else if (!strcmp(arg, "--no-encode-email-headers")) {
+ revs->encode_email_headers = 0;
} else if (!strcmp(arg, "--root")) {
revs->show_root_diff = 1;
} else if (!strcmp(arg, "--no-commit-id")) {
@@ -2265,6 +2460,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
} else if (!strcmp(arg, "--full-diff")) {
revs->diff = 1;
revs->full_diff = 1;
+ } else if (!strcmp(arg, "--show-pulls")) {
+ revs->show_pulls = 1;
} else if (!strcmp(arg, "--full-history")) {
revs->simplify_history = 0;
} else if (!strcmp(arg, "--relative-date")) {
@@ -2375,8 +2572,8 @@ static int for_each_good_bisect_ref(struct ref_store *refs, each_ref_fn fn, void
}
static int handle_revision_pseudo_opt(const char *submodule,
- struct rev_info *revs,
- int argc, const char **argv, int *flags)
+ struct rev_info *revs,
+ const char **argv, int *flags)
{
const char *arg = argv[0];
const char *optarg;
@@ -2510,8 +2707,8 @@ static void NORETURN diagnose_missing_default(const char *def)
*/
int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct setup_revision_opt *opt)
{
- int i, flags, left, seen_dashdash, got_rev_arg = 0, revarg_opt;
- struct argv_array prune_data = ARGV_ARRAY_INIT;
+ int i, flags, left, seen_dashdash, revarg_opt;
+ struct strvec prune_data = STRVEC_INIT;
const char *submodule = NULL;
int seen_end_of_options = 0;
@@ -2530,7 +2727,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
argv[i] = NULL;
argc = i;
if (argv[i + 1])
- argv_array_pushv(&prune_data, argv + i + 1);
+ strvec_pushv(&prune_data, argv + i + 1);
seen_dashdash = 1;
break;
}
@@ -2547,7 +2744,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
int opts;
opts = handle_revision_pseudo_opt(submodule,
- revs, argc - i, argv + i,
+ revs, argv + i,
&flags);
if (opts > 0) {
i += opts - 1;
@@ -2596,14 +2793,12 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
for (j = i; j < argc; j++)
verify_filename(revs->prefix, argv[j], j == i);
- argv_array_pushv(&prune_data, argv + i);
+ strvec_pushv(&prune_data, argv + i);
break;
}
- else
- got_rev_arg = 1;
}
- if (prune_data.argc) {
+ if (prune_data.nr) {
/*
* If we need to introduce the magic "a lone ':' means no
* pathspec whatsoever", here is the place to do so.
@@ -2619,9 +2814,9 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
* }
*/
parse_pathspec(&revs->prune_data, 0, 0,
- revs->prefix, prune_data.argv);
+ revs->prefix, prune_data.v);
}
- argv_array_clear(&prune_data);
+ strvec_clear(&prune_data);
if (revs->def == NULL)
revs->def = opt ? opt->def : NULL;
@@ -2629,7 +2824,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
opt->tweak(revs, opt);
if (revs->show_merge)
prepare_show_merge(revs);
- if (revs->def && !revs->pending.nr && !revs->rev_input_given && !got_rev_arg) {
+ if (revs->def && !revs->pending.nr && !revs->rev_input_given) {
struct object_id oid;
struct object *object;
struct object_context oc;
@@ -2652,6 +2847,12 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
if (revs->diffopt.objfind)
revs->simplify_history = 0;
+ if (revs->line_level_traverse) {
+ if (want_ancestry(revs))
+ revs->limited = 1;
+ revs->topo_order = 1;
+ }
+
if (revs->topo_order && !generation_numbers_enabled(the_repository))
revs->limited = 1;
@@ -2664,18 +2865,15 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
copy_pathspec(&revs->diffopt.pathspec,
&revs->prune_data);
}
- if (revs->combine_merges)
+ if (revs->combine_merges && revs->ignore_merges < 0)
revs->ignore_merges = 0;
+ if (revs->ignore_merges < 0)
+ revs->ignore_merges = 1;
if (revs->combined_all_paths && !revs->combine_merges)
die("--combined-all-paths makes no sense without -c or --cc");
revs->diffopt.abbrev = revs->abbrev;
- if (revs->line_level_traverse) {
- revs->limited = 1;
- revs->topo_order = 1;
- }
-
diff_setup_done(&revs->diffopt);
grep_commit_pattern_type(GREP_PATTERN_TYPE_UNSPECIFIED,
@@ -2704,9 +2902,6 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
if (!revs->reflog_info && revs->grep_filter.use_reflog_filter)
die("cannot use --grep-reflog without --walk-reflogs");
- if (revs->first_parent_only && revs->bisect)
- die(_("--first-parent is incompatible with --bisect"));
-
if (revs->line_level_traverse &&
(revs->diffopt.output_format & ~(DIFF_FORMAT_PATCH | DIFF_FORMAT_NO_OUTPUT)))
die(_("-L does not yet support diff formats besides -p and -s"));
@@ -3019,7 +3214,8 @@ static struct commit_list **simplify_one(struct rev_info *revs, struct commit *c
if (!cnt ||
(commit->object.flags & UNINTERESTING) ||
!(commit->object.flags & TREESAME) ||
- (parent = one_relevant_parent(revs, commit->parents)) == NULL)
+ (parent = one_relevant_parent(revs, commit->parents)) == NULL ||
+ (revs->show_pulls && (commit->object.flags & PULL_MERGE)))
st->simplified = commit;
else {
pst = locate_simplify_state(revs, parent);
@@ -3130,7 +3326,7 @@ static void explore_walk_step(struct rev_info *revs)
if (!c)
return;
- if (parse_commit_gently(c, 1) < 0)
+ if (repo_parse_commit_gently(revs->repo, c, 1) < 0)
return;
if (revs->sort_order == REV_SORT_BY_AUTHOR_DATE)
@@ -3155,7 +3351,7 @@ static void explore_to_depth(struct rev_info *revs,
struct topo_walk_info *info = revs->topo_walk_info;
struct commit *c;
while ((c = prio_queue_peek(&info->explore_queue)) &&
- c->generation >= gen_cutoff)
+ commit_graph_generation(c) >= gen_cutoff)
explore_walk_step(revs);
}
@@ -3168,10 +3364,10 @@ static void indegree_walk_step(struct rev_info *revs)
if (!c)
return;
- if (parse_commit_gently(c, 1) < 0)
+ if (repo_parse_commit_gently(revs->repo, c, 1) < 0)
return;
- explore_to_depth(revs, c->generation);
+ explore_to_depth(revs, commit_graph_generation(c));
for (p = c->parents; p; p = p->next) {
struct commit *parent = p->item;
@@ -3195,7 +3391,7 @@ static void compute_indegrees_to_depth(struct rev_info *revs,
struct topo_walk_info *info = revs->topo_walk_info;
struct commit *c;
while ((c = prio_queue_peek(&info->indegree_queue)) &&
- c->generation >= gen_cutoff)
+ commit_graph_generation(c) >= gen_cutoff)
indegree_walk_step(revs);
}
@@ -3248,15 +3444,17 @@ static void init_topo_walk(struct rev_info *revs)
info->min_generation = GENERATION_NUMBER_INFINITY;
for (list = revs->commits; list; list = list->next) {
struct commit *c = list->item;
+ uint32_t generation;
- if (parse_commit_gently(c, 1))
+ if (repo_parse_commit_gently(revs->repo, c, 1))
continue;
test_flag_and_insert(&info->explore_queue, c, TOPO_WALK_EXPLORED);
test_flag_and_insert(&info->indegree_queue, c, TOPO_WALK_INDEGREE);
- if (c->generation < info->min_generation)
- info->min_generation = c->generation;
+ generation = commit_graph_generation(c);
+ if (generation < info->min_generation)
+ info->min_generation = generation;
*(indegree_slab_at(&info->indegree, c)) = 1;
@@ -3307,15 +3505,17 @@ static void expand_topo_walk(struct rev_info *revs, struct commit *commit)
for (p = commit->parents; p; p = p->next) {
struct commit *parent = p->item;
int *pi;
+ uint32_t generation;
if (parent->object.flags & UNINTERESTING)
continue;
- if (parse_commit_gently(parent, 1) < 0)
+ if (repo_parse_commit_gently(revs->repo, parent, 1) < 0)
continue;
- if (parent->generation < info->min_generation) {
- info->min_generation = parent->generation;
+ generation = commit_graph_generation(parent);
+ if (generation < info->min_generation) {
+ info->min_generation = generation;
compute_indegrees_to_depth(revs, info->min_generation);
}
@@ -3362,6 +3562,8 @@ int prepare_revision_walk(struct rev_info *revs)
FOR_EACH_OBJECT_PROMISOR_ONLY);
}
+ if (!revs->reflog_info)
+ prepare_to_use_bloom_filter(revs);
if (revs->no_walk != REVISION_WALK_NO_WALK_UNSORTED)
commit_list_sort_by_date(&revs->commits);
if (revs->no_walk)
@@ -3373,12 +3575,20 @@ int prepare_revision_walk(struct rev_info *revs)
sort_in_topological_order(&revs->commits, revs->sort_order);
} else if (revs->topo_order)
init_topo_walk(revs);
- if (revs->line_level_traverse)
+ if (revs->line_level_traverse && want_ancestry(revs))
+ /*
+ * At the moment we can only do line-level log with parent
+ * rewriting by performing this expensive pre-filtering step.
+ * If parent rewriting is not requested, then we rather
+ * perform the line-level log filtering during the regular
+ * history traversal.
+ */
line_log_filter(revs);
if (revs->simplify_merges)
simplify_merges(revs);
if (revs->children.name)
set_children(revs);
+
return 0;
}
@@ -3583,6 +3793,22 @@ enum commit_action get_commit_action(struct rev_info *revs, struct commit *commi
return commit_ignore;
if (commit->object.flags & UNINTERESTING)
return commit_ignore;
+ if (revs->line_level_traverse && !want_ancestry(revs)) {
+ /*
+ * In case of line-level log with parent rewriting
+ * prepare_revision_walk() already took care of all line-level
+ * log filtering, and there is nothing left to do here.
+ *
+ * If parent rewriting was not requested, then this is the
+ * place to perform the line-level log filtering. Notably,
+ * this check, though expensive, must come before the other,
+ * cheaper filtering conditions, because the tracked line
+ * ranges must be adjusted even when the commit will end up
+ * being ignored based on other conditions.
+ */
+ if (!line_log_process_ranges_arbitrary_commit(revs, commit))
+ return commit_ignore;
+ }
if (revs->min_age != -1 &&
comparison_date(revs, commit) > revs->min_age)
return commit_ignore;
@@ -3602,6 +3828,10 @@ enum commit_action get_commit_action(struct rev_info *revs, struct commit *commi
/* drop merges unless we want parenthood */
if (!want_ancestry(revs))
return commit_ignore;
+
+ if (revs->show_pulls && (commit->object.flags & PULL_MERGE))
+ return commit_show;
+
/*
* If we want ancestry, then need to keep any merges
* between relevant commits to tie together topology.