From e7c85120eab6c942d15c0f5ed3a2c8b6ec667617 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Fri, 1 Nov 2013 11:39:37 -0700 Subject: [PATCH] More tests and fixed for merging reversed diffs There were a lot more cases to deal with to make sure that our merged (i.e. workdir-to-tree-to-index) diffs were matching the output of core Git. --- src/diff_tform.c | 57 +++++++++++++++++++++++++++++---------- tests-clar/diff/workdir.c | 32 ++++++++++++++++++++++ 2 files changed, 75 insertions(+), 14 deletions(-) diff --git a/src/diff_tform.c b/src/diff_tform.c index 0aec754a4..28a9cc70d 100644 --- a/src/diff_tform.c +++ b/src/diff_tform.c @@ -46,7 +46,6 @@ fail: } static git_diff_delta *diff_delta__merge_like_cgit( - uint16_t flags, const git_diff_delta *a, const git_diff_delta *b, git_pool *pool) @@ -99,15 +98,46 @@ static git_diff_delta *diff_delta__merge_like_cgit( return dup; } -int git_diff_merge( - git_diff *onto, - const git_diff *from) +static git_diff_delta *diff_delta__merge_like_cgit_reversed( + const git_diff_delta *a, + const git_diff_delta *b, + git_pool *pool) +{ + git_diff_delta *dup; + + /* reversed version of above logic */ + + if (a->status == GIT_DELTA_UNMODIFIED) + return diff_delta__dup(b, pool); + + if ((dup = diff_delta__dup(a, pool)) == NULL) + return NULL; + + if (b->status == GIT_DELTA_UNMODIFIED || b->status == GIT_DELTA_UNTRACKED) + return dup; + + if (dup->status == GIT_DELTA_DELETED) { + if (b->status == GIT_DELTA_ADDED) + dup->status = GIT_DELTA_UNMODIFIED; + } else { + dup->status = b->status; + } + + git_oid_cpy(&dup->old_file.oid, &b->old_file.oid); + dup->old_file.mode = b->old_file.mode; + dup->old_file.size = b->old_file.size; + dup->old_file.flags = b->old_file.flags; + + return dup; +} + +int git_diff_merge(git_diff *onto, const git_diff *from) { int error = 0; git_pool onto_pool; git_vector onto_new; git_diff_delta *delta; - bool ignore_case = false; + bool ignore_case, reversed; unsigned int i, j; assert(onto && from); @@ -115,11 +145,11 @@ int git_diff_merge( if (!from->deltas.length) return 0; - if ((onto->opts.flags & GIT_DIFF_IGNORE_CASE) != - (from->opts.flags & GIT_DIFF_IGNORE_CASE) || - (onto->opts.flags & GIT_DIFF_REVERSE) != - (from->opts.flags & GIT_DIFF_REVERSE)) - { + ignore_case = ((onto->opts.flags & GIT_DIFF_IGNORE_CASE) != 0); + reversed = ((onto->opts.flags & GIT_DIFF_REVERSE) != 0); + + if (ignore_case != ((from->opts.flags & GIT_DIFF_IGNORE_CASE) != 0) || + reversed != ((from->opts.flags & GIT_DIFF_REVERSE) != 0)) { giterr_set(GITERR_INVALID, "Attempt to merge diffs created with conflicting options"); return -1; @@ -130,8 +160,6 @@ int git_diff_merge( git_pool_init(&onto_pool, 1, 0) < 0) return -1; - ignore_case = ((onto->opts.flags & GIT_DIFF_IGNORE_CASE) != 0); - for (i = 0, j = 0; i < onto->deltas.length || j < from->deltas.length; ) { git_diff_delta *o = GIT_VECTOR_GET(&onto->deltas, i); const git_diff_delta *f = GIT_VECTOR_GET(&from->deltas, j); @@ -145,8 +173,9 @@ int git_diff_merge( delta = diff_delta__dup(f, &onto_pool); j++; } else { - delta = diff_delta__merge_like_cgit( - onto->opts.flags, o, f, &onto_pool); + delta = reversed ? + diff_delta__merge_like_cgit_reversed(o, f, &onto_pool) : + diff_delta__merge_like_cgit(o, f, &onto_pool); i++; j++; } diff --git a/tests-clar/diff/workdir.c b/tests-clar/diff/workdir.c index 8611be8c8..fba64eff3 100644 --- a/tests-clar/diff/workdir.c +++ b/tests-clar/diff/workdir.c @@ -196,6 +196,38 @@ void test_diff_workdir__to_tree(void) git_diff_free(diff); + /* Let's try that once more with a reversed diff */ + + opts.flags |= GIT_DIFF_REVERSE; + + cl_git_pass(git_diff_tree_to_index(&diff, g_repo, b, NULL, &opts)); + cl_git_pass(git_diff_index_to_workdir(&diff2, g_repo, NULL, &opts)); + cl_git_pass(git_diff_merge(diff, diff2)); + git_diff_free(diff2); + + memset(&exp, 0, sizeof(exp)); + + cl_git_pass(git_diff_foreach( + diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); + + cl_assert_equal_i(16, exp.files); + cl_assert_equal_i(5, exp.file_status[GIT_DELTA_DELETED]); + cl_assert_equal_i(4, exp.file_status[GIT_DELTA_ADDED]); + cl_assert_equal_i(3, exp.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); + cl_assert_equal_i(3, exp.file_status[GIT_DELTA_UNTRACKED]); + + cl_assert_equal_i(12, exp.hunks); + + cl_assert_equal_i(19, exp.lines); + cl_assert_equal_i(3, exp.line_ctxt); + cl_assert_equal_i(12, exp.line_dels); + cl_assert_equal_i(4, exp.line_adds); + + git_diff_free(diff); + + /* all done now */ + git_tree_free(a); git_tree_free(b); }