Commit 3b750a88 by Tim

Git blame buffer gives the wrong result in many cases where there are multiple local edits.

I added multiple failing tests cases to tests/libgit2/blame/buffer.c to cover the test cases.

blame.c has been updated to get these tests to pass. 
Fixes include:
    shift_hunks_by now no longer shifts hunks before the start line. 
    Adjusting the wedge line in the case where a new hunk deletes and adds lines.
    In buffer_line_cb for addions humks are now shifted after the current diff line.
    Fixing the logic for removing a line in buffer_line_cb to work with multi-line deletions.
 
parent f041a94e
......@@ -119,8 +119,11 @@ static void shift_hunks_by(git_vector *v, size_t start_line, int shift_by)
size_t i;
if (!git_vector_bsearch2(&i, v, hunk_byfinalline_search_cmp, &start_line)) {
for (; i < v->length; i++) {
for (i = 0; i < v->length; i++) {
git_blame_hunk *hunk = (git_blame_hunk*)v->contents[i];
if(hunk->final_start_line_number < start_line){
continue;
}
hunk->final_start_line_number += shift_by;
}
}
......@@ -444,21 +447,20 @@ static int buffer_hunk_cb(
GIT_UNUSED(delta);
wedge_line = (hunk->old_lines == 0) ? hunk->new_start : hunk->old_start;
wedge_line = (hunk->new_start >= hunk->old_start || hunk->old_lines==0) ? hunk->new_start : hunk->old_start;
blame->current_diff_line = wedge_line;
blame->current_hunk = (git_blame_hunk*)git_blame_get_hunk_byline(blame, wedge_line);
if (!blame->current_hunk) {
/* Line added at the end of the file */
blame->current_hunk = new_hunk(wedge_line, 0, wedge_line,
blame->path, blame);
blame->current_diff_line++;
GIT_ERROR_CHECK_ALLOC(blame->current_hunk);
git_vector_insert(&blame->hunks, blame->current_hunk);
} else if (!hunk_starts_at_or_after_line(blame->current_hunk, wedge_line)){
/* If this hunk doesn't start between existing hunks, split a hunk up so it does */
blame->current_hunk = split_hunk_in_vector(&blame->hunks, blame->current_hunk,
wedge_line - blame->current_hunk->orig_start_line_number, true,
wedge_line - blame->current_hunk->final_start_line_number, true,
blame);
GIT_ERROR_CHECK_ALLOC(blame->current_hunk);
}
......@@ -484,13 +486,12 @@ static int buffer_line_cb(
hunk_ends_at_or_before_line(blame->current_hunk, blame->current_diff_line)) {
/* Append to the current buffer-blame hunk */
blame->current_hunk->lines_in_hunk++;
shift_hunks_by(&blame->hunks, blame->current_diff_line+1, 1);
shift_hunks_by(&blame->hunks, blame->current_diff_line, 1);
} else {
/* Create a new buffer-blame hunk with this line */
shift_hunks_by(&blame->hunks, blame->current_diff_line, 1);
blame->current_hunk = new_hunk(blame->current_diff_line, 1, 0, blame->path, blame);
GIT_ERROR_CHECK_ALLOC(blame->current_hunk);
git_vector_insert_sorted(&blame->hunks, blame->current_hunk, NULL);
}
blame->current_diff_line++;
......@@ -498,15 +499,16 @@ static int buffer_line_cb(
if (line->origin == GIT_DIFF_LINE_DELETION) {
/* Trim the line from the current hunk; remove it if it's now empty */
size_t shift_base = blame->current_diff_line + blame->current_hunk->lines_in_hunk+1;
size_t shift_base = blame->current_diff_line + blame->current_hunk->lines_in_hunk;
if (--(blame->current_hunk->lines_in_hunk) == 0) {
size_t i;
shift_base--;
size_t i_next;
if (!git_vector_search2(&i, &blame->hunks, ptrs_equal_cmp, blame->current_hunk)) {
git_vector_remove(&blame->hunks, i);
free_hunk(blame->current_hunk);
blame->current_hunk = (git_blame_hunk*)git_blame_get_hunk_byindex(blame, (uint32_t)i);
i_next = min( i , blame->hunks.length -1);
blame->current_hunk = (git_blame_hunk*)git_blame_get_hunk_byindex(blame, (uint32_t)i_next);
}
}
shift_hunks_by(&blame->hunks, shift_base, -1);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment