diff --git a/line-log.c b/line-log.c index 9010e00950..520ee715bc 100644 --- a/line-log.c +++ b/line-log.c @@ -1227,7 +1227,7 @@ static int process_ranges_merge_commit(struct rev_info *rev, struct commit *comm /* NEEDSWORK leaking like a sieve */ } -static int process_ranges_arbitrary_commit(struct rev_info *rev, struct commit *commit) +int line_log_process_ranges_arbitrary_commit(struct rev_info *rev, struct commit *commit) { struct line_log_data *range = lookup_line_range(rev, commit); int changed = 0; @@ -1270,7 +1270,7 @@ int line_log_filter(struct rev_info *rev) while (list) { struct commit_list *to_free = NULL; commit = list->item; - if (process_ranges_arbitrary_commit(rev, commit)) { + if (line_log_process_ranges_arbitrary_commit(rev, commit)) { *pp = list; pp = &list->next; } else diff --git a/line-log.h b/line-log.h index 882c5055bb..82ae8d98a4 100644 --- a/line-log.h +++ b/line-log.h @@ -54,6 +54,8 @@ struct line_log_data { void line_log_init(struct rev_info *rev, const char *prefix, struct string_list *args); int line_log_filter(struct rev_info *rev); +int line_log_process_ranges_arbitrary_commit(struct rev_info *rev, + struct commit *commit); int line_log_print(struct rev_info *rev, struct commit *commit); diff --git a/revision.c b/revision.c index f78c636e4d..3228db9af6 100644 --- a/revision.c +++ b/revision.c @@ -39,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; @@ -3511,7 +3513,14 @@ 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); @@ -3722,6 +3731,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; diff --git a/t/t4211-line-log.sh b/t/t4211-line-log.sh index ea4a939836..1428eae262 100755 --- a/t/t4211-line-log.sh +++ b/t/t4211-line-log.sh @@ -263,7 +263,7 @@ test_expect_success 'setup for checking line-log and parent oids' ' ' # Parent oid should be from immediate parent. -test_expect_failure 'parent oids without parent rewriting' ' +test_expect_success 'parent oids without parent rewriting' ' cat >expect <<-EOF && $head_oid $prev_oid Modify func2() in file.c $root_oid Add func1() and func2() in file.c