summaryrefslogtreecommitdiff
path: root/src/diff_tform.c
diff options
context:
space:
mode:
authorRussell Belfer <rb@github.com>2013-12-02 13:27:06 -0800
committerRussell Belfer <rb@github.com>2013-12-02 13:27:06 -0800
commit2123a17f83cc95adee4e7259d0686b07f074de4c (patch)
treeb04541454e33323e77d1f3e58eee32e8abb3df16 /src/diff_tform.c
parent14984af6cb9906746d2c64c5df7542ecd7406b16 (diff)
downloadlibgit2-2123a17f83cc95adee4e7259d0686b07f074de4c.tar.gz
Fix bug making split deltas a COPIED targets
When FIND_COPIES is used in combination with BREAK_REWRITES for rename detection, there was a bug where the split MODIFIED delta was only used as a target for RENAME records and not for COPIED records. This fixes that, converting the split into a pair of DELETED and COPIED deltas when that circumstance arises.
Diffstat (limited to 'src/diff_tform.c')
-rw-r--r--src/diff_tform.c46
1 files changed, 30 insertions, 16 deletions
diff --git a/src/diff_tform.c b/src/diff_tform.c
index 28a9cc70d..3b5575d28 100644
--- a/src/diff_tform.c
+++ b/src/diff_tform.c
@@ -366,12 +366,28 @@ static int normalize_find_opts(
return 0;
}
+static int insert_delete_side_of_split(
+ git_diff *diff, git_vector *onto, const git_diff_delta *delta)
+{
+ /* make new record for DELETED side of split */
+ git_diff_delta *deleted = diff_delta__dup(delta, &diff->pool);
+ GITERR_CHECK_ALLOC(deleted);
+
+ deleted->status = GIT_DELTA_DELETED;
+ deleted->nfiles = 1;
+ memset(&deleted->new_file, 0, sizeof(deleted->new_file));
+ deleted->new_file.path = deleted->old_file.path;
+ deleted->new_file.flags |= GIT_DIFF_FLAG_VALID_OID;
+
+ return git_vector_insert(onto, deleted);
+}
+
static int apply_splits_and_deletes(
git_diff *diff, size_t expected_size, bool actually_split)
{
git_vector onto = GIT_VECTOR_INIT;
size_t i;
- git_diff_delta *delta, *deleted;
+ git_diff_delta *delta;
if (git_vector_init(&onto, expected_size, git_diff_delta__cmp) < 0)
return -1;
@@ -384,17 +400,7 @@ static int apply_splits_and_deletes(
if ((delta->flags & GIT_DIFF_FLAG__TO_SPLIT) != 0 && actually_split) {
delta->similarity = 0;
- /* make new record for DELETED side of split */
- if (!(deleted = diff_delta__dup(delta, &diff->pool)))
- goto on_error;
-
- deleted->status = GIT_DELTA_DELETED;
- deleted->nfiles = 1;
- memset(&deleted->new_file, 0, sizeof(deleted->new_file));
- deleted->new_file.path = deleted->old_file.path;
- deleted->new_file.flags |= GIT_DIFF_FLAG_VALID_OID;
-
- if (git_vector_insert(&onto, deleted) < 0)
+ if (insert_delete_side_of_split(diff, &onto, delta) < 0)
goto on_error;
if (diff->new_src == GIT_ITERATOR_TYPE_WORKDIR)
@@ -1058,10 +1064,7 @@ find_best_matches:
}
}
- else if (delta_is_new_only(tgt)) {
- if (!FLAG_SET(&opts, GIT_DIFF_FIND_COPIES))
- continue;
-
+ else if (FLAG_SET(&opts, GIT_DIFF_FIND_COPIES)) {
if (tgt2src_copy[t].similarity < opts.copy_threshold)
continue;
@@ -1069,10 +1072,21 @@ find_best_matches:
best_match = &tgt2src_copy[t];
src = GIT_VECTOR_GET(&diff->deltas, best_match->idx);
+ if (delta_is_split(tgt)) {
+ error = insert_delete_side_of_split(diff, &diff->deltas, tgt);
+ if (error < 0)
+ goto cleanup;
+ num_rewrites--;
+ }
+
+ if (!delta_is_split(tgt) && !delta_is_new_only(tgt))
+ continue;
+
tgt->status = GIT_DELTA_COPIED;
tgt->similarity = best_match->similarity;
tgt->nfiles = 2;
memcpy(&tgt->old_file, &src->old_file, sizeof(tgt->old_file));
+ tgt->flags &= ~GIT_DIFF_FLAG__TO_SPLIT;
num_updates++;
}