Walking forward through history (i.e., topologically earliest commits first), we filter the parent list of every commit as follows. Consider a parent P: - If P touches any of the interesting line ranges, we keep it. - If P is a merge, we also keep it. - Otherwise, P is rewritten to its (only) parent P^. So, there will be more commits output than the situation which parent rewrite is not on. Signed-off-by: Bo Yang <struggleyb.nku@xxxxxxxxx> --- line.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- line.h | 2 + revision.c | 3 ++ 3 files changed, 96 insertions(+), 3 deletions(-) diff --git a/line.c b/line.c index 5317fe5..cc8be97 100644 --- a/line.c +++ b/line.c @@ -10,6 +10,9 @@ #include "xdiff-interface.h" #include "strbuf.h" #include "log-tree.h" +#include "graph.h" + +static int limited = 0; static void cleanup(struct diff_line_range *r) { @@ -1249,12 +1252,12 @@ int cmd_line_log_walk(struct rev_info *rev) die("revision walk prepare failed"); list = rev->commits; - if (list) { + if (list && !limited) { list->item->object.flags |= RANGE_UPDATE; list = list->next; } /* Clear the flags */ - while (list) { + while (list && !limited) { list->item->object.flags &= ~(RANGE_UPDATE | EVIL_MERGE | NEED_PRINT); list = list->next; } @@ -1268,7 +1271,9 @@ int cmd_line_log_walk(struct rev_info *rev) assign_parents_range(rev, commit); } - if (commit->object.flags & NEED_PRINT || rev->full_line_diff) { + if (commit->object.flags & NEED_PRINT || rev->full_line_diff || rev->graph) { + if (rev->graph) + graph_update(rev->graph, commit); line_log_flush(rev, commit); } @@ -1293,3 +1298,86 @@ int cmd_line_log_walk(struct rev_info *rev) return 0; } +static enum rewrite_result rewrite_one(struct rev_info *rev, struct commit **pp) +{ + struct diff_line_range *r = NULL; + struct commit *p; + while (1) { + p = *pp; + if (p->object.flags & RANGE_UPDATE) + assign_parents_range(rev, p); + if (p->parents && p->parents->next) + return rewrite_one_ok; + if (p->object.flags & NEED_PRINT) + return rewrite_one_ok; + if (!p->parents) + return rewrite_one_noparents; + + r = lookup_line_range(rev, p); + if (!r) + return rewrite_one_noparents; + *pp = p->parents->item; + } +} + +/* The rev->commits must be sorted in topologically order */ +void limit_list_line(struct rev_info *rev) +{ + struct commit_list *list = rev->commits; + struct commit_list *commits = xmalloc(sizeof(struct commit_list)); + struct commit_list *out = commits, *prev = commits; + struct commit *c; + struct diff_line_range *r; + + if (list) { + list->item->object.flags |= RANGE_UPDATE; + list = list->next; + } + /* Clear the flags */ + while (list) { + list->item->object.flags &= ~(RANGE_UPDATE | EVIL_MERGE | NEED_PRINT); + list = list->next; + } + + list = rev->commits; + while (list) { + c = list->item; + + if (c->object.flags & RANGE_UPDATE) + assign_parents_range(rev, c); + + if (c->object.flags & NEED_PRINT || + (c->parents && c->parents->next)) { + if (rewrite_parents(rev, c, rewrite_one)) + die("Can't rewrite parent for commit %s", + sha1_to_hex(c->object.sha1)); + commits->item = c; + commits->next = xmalloc(sizeof(struct commit_list)); + prev = commits; + commits = commits->next; + } else { + r = lookup_line_range(rev, c); + if (r) { + cleanup(r); + r = NULL; + add_line_range(rev, c, r); + } + } + + list = list->next; + } + + prev->next = NULL; + free(commits); + + list = rev->commits; + while (list) { + struct commit_list *l = list; + list = list->next; + free(l); + } + + rev->commits = out; + limited = 1; +} + diff --git a/line.h b/line.h index 3f5c827..a2083ec 100644 --- a/line.h +++ b/line.h @@ -136,4 +136,6 @@ const char *parse_loc(const char *spec, nth_line_fn_t nth_line, extern int cmd_line_log_walk(struct rev_info *rev); +extern void limit_list_line(struct rev_info *rev); + #endif diff --git a/revision.c b/revision.c index fb08978..a6527ca 100644 --- a/revision.c +++ b/revision.c @@ -13,6 +13,7 @@ #include "decorate.h" #include "log-tree.h" #include "string-list.h" +#include "line.h" volatile show_early_output_fn_t show_early_output; @@ -1886,6 +1887,8 @@ int prepare_revision_walk(struct rev_info *revs) return -1; if (revs->topo_order) sort_in_topological_order(&revs->commits, revs->lifo); + if (revs->rewrite_parents && revs->line_level_traverse) + limit_list_line(revs); if (revs->simplify_merges) simplify_merges(revs); if (revs->children.name) -- 1.7.0.2.273.gc2413.dirty -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html