Signed-off-by: Bo Yang <struggleyb.nku@xxxxxxxxx> --- line.c | 48 ++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 38 insertions(+), 10 deletions(-) diff --git a/line.c b/line.c index 272f166..bc9fc76 100644 --- a/line.c +++ b/line.c @@ -390,6 +390,7 @@ struct diff_line_range *diff_line_range_clone(struct diff_line_range *r) struct diff_line_range *ret = xmalloc(sizeof(*ret)); int i = 0; + assert(r); DIFF_LINE_RANGE_INIT(ret); ret->ranges = xcalloc(r->nr, sizeof(struct range)); memcpy(ret->ranges, r->ranges, sizeof(struct range) * r->nr); @@ -993,13 +994,21 @@ static void diff_update_parent_range(struct rev_info *rev, struct commit *commit assign_range_to_parent(rev, commit, c, r, &rev->diffopt, 1); } +struct commit_state { + struct diff_line_range *range; + struct object obj; +}; + static void assign_parents_range(struct rev_info *rev, struct commit *commit) { struct commit_list *parents = commit->parents; struct diff_line_range *r = lookup_line_range(rev, commit); struct diff_line_range *copy = NULL, *range = NULL; + struct decoration parents_state; + struct commit_state *state = NULL; int nontrivial = 0; + memset(&parents_state, 0, sizeof(parents_state)); /* * If we are in linear history, update range and flush the patch if * necessary @@ -1020,36 +1029,44 @@ static void assign_parents_range(struct rev_info *rev, struct commit *commit) while (parents) { struct commit *p = parents->item; int diff = 0; + struct diff_line_range *origin_range = lookup_line_range(rev, p); + if (origin_range) + origin_range = diff_line_range_clone_deeply(origin_range); + + state = xmalloc(sizeof(*state)); + state->range = origin_range; + state->obj = p->object; + add_decoration(&parents_state, &p->object, state); diff = assign_range_to_parent(rev, commit, p, r, &rev->diffopt, 1); /* Since all the ranges comes from this parent, we can ignore others */ if (diff == 0) { - /* parent rewriting code */ + /* restore the state of parents before this one */ parents = commit->parents; while (parents->item != p) { struct commit_list *list = parents; struct diff_line_range *line_range = NULL; parents = parents->next; line_range = lookup_line_range(rev, list->item); - add_line_range(rev, list->item, NULL); - free(line_range); - list->item->object.flags &= ~(RANGE_UPDATE | NEED_PRINT | EVIL_MERGE); + cleanup(line_range); + state = lookup_decoration(&parents_state, &list->item->object); + add_decoration(&parents_state, &list->item->object, NULL); + add_line_range(rev, list->item, state->range); + list->item->object = state->obj; + free(state); free(list); } + commit->parents = parents; parents = parents->next; commit->parents->next = NULL; while (parents) { struct commit_list *list = parents; - struct diff_line_range *line_range = NULL; parents = parents->next; - line_range = lookup_line_range(rev, list->item); - add_line_range(rev, list->item, NULL); - free(line_range); - list->item->object.flags &= ~(RANGE_UPDATE | NEED_PRINT | EVIL_MERGE); free(list); } - return; + goto out; } + /* take the ranges from 'commit', try to detect nontrivial merge */ assign_range_to_parent(rev, commit, p, copy, &rev->diffopt, 0); parents = parents->next; } @@ -1066,6 +1083,17 @@ static void assign_parents_range(struct rev_info *rev, struct commit *commit) range = range->next; } +out: + parents = commit->parents; + while (parents) { + state = lookup_decoration(&parents_state, &parents->item->object); + if (state) { + cleanup(state->range); + free(state); + } + parents = parents->next; + } + if (nontrivial) { add_decoration(&rev->nontrivial_merge, &commit->object, copy); } else { -- 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