diff --git a/src/libgit2/merge.h b/src/libgit2/merge.h index 23932905e80..fca9c20e9b4 100644 --- a/src/libgit2/merge.h +++ b/src/libgit2/merge.h @@ -165,6 +165,10 @@ GIT_INLINE(const char *) git_merge_file__best_path( if (!ancestor) { if (ours && theirs && strcmp(ours, theirs) == 0) return ours; + if (ours && !theirs) + return ours; + if (theirs && !ours) + return theirs; return NULL; } diff --git a/src/libgit2/merge_file.c b/src/libgit2/merge_file.c index ffe83cf2a3b..573c88adaa9 100644 --- a/src/libgit2/merge_file.c +++ b/src/libgit2/merge_file.c @@ -84,8 +84,8 @@ static int merge_file__xdiff( memset(&xmparam, 0x0, sizeof(xmparam_t)); - if (ours->size > LONG_MAX || - theirs->size > LONG_MAX || + if ((ours && ours->size > LONG_MAX) || + (theirs && theirs->size > LONG_MAX) || (ancestor && ancestor->size > LONG_MAX)) { git_error_set(GIT_ERROR_MERGE, "failed to merge files"); error = -1; @@ -99,15 +99,19 @@ static int merge_file__xdiff( ancestor_mmfile.size = (long)ancestor->size; } - xmparam.file1 = (options.our_label) ? - options.our_label : ours->path; - our_mmfile.ptr = (char *)ours->ptr; - our_mmfile.size = (long)ours->size; + if (ours) { + xmparam.file1 = (options.our_label) ? + options.our_label : ours->path; + our_mmfile.ptr = (char *)ours->ptr; + our_mmfile.size = (long)ours->size; + } - xmparam.file2 = (options.their_label) ? - options.their_label : theirs->path; - their_mmfile.ptr = (char *)theirs->ptr; - their_mmfile.size = (long)theirs->size; + if (theirs) { + xmparam.file2 = (options.their_label) ? + options.their_label : theirs->path; + their_mmfile.ptr = (char *)theirs->ptr; + their_mmfile.size = (long)theirs->size; + } if (options.favor == GIT_MERGE_FILE_FAVOR_OURS) xmparam.favor = XDL_MERGE_FAVOR_OURS; @@ -148,8 +152,8 @@ static int merge_file__xdiff( path = git_merge_file__best_path( ancestor ? ancestor->path : NULL, - ours->path, - theirs->path); + ours ? ours->path : NULL, + theirs ? theirs->path : NULL); if (path != NULL && (out->path = git__strdup(path)) == NULL) { error = -1; @@ -161,8 +165,8 @@ static int merge_file__xdiff( out->len = mmbuffer.size; out->mode = git_merge_file__best_mode( ancestor ? ancestor->mode : 0, - ours->mode, - theirs->mode); + ours ? ours->mode : 0, + theirs ? theirs->mode : 0); done: if (error < 0) @@ -276,15 +280,17 @@ int git_merge_file_from_index( const git_merge_file_options *options) { git_merge_file_input *ancestor_ptr = NULL, - ancestor_input = {0}, our_input = {0}, their_input = {0}; - git_odb *odb = NULL; + ancestor_input = {0}; + git_merge_file_input *our_ptr = NULL, + our_input = {0}; + git_merge_file_input *their_ptr = NULL, + their_input = {0}; + git_odb *odb; git_odb_object *odb_object[3] = { 0 }; int error = 0; GIT_ASSERT_ARG(out); GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(ours); - GIT_ASSERT_ARG(theirs); memset(out, 0x0, sizeof(git_merge_file_result)); @@ -299,12 +305,24 @@ int git_merge_file_from_index( ancestor_ptr = &ancestor_input; } - if ((error = merge_file_input_from_index(&our_input, &odb_object[1], odb, ours)) < 0 || - (error = merge_file_input_from_index(&their_input, &odb_object[2], odb, theirs)) < 0) - goto done; + if (ours) { + if ((error = merge_file_input_from_index( + &our_input, &odb_object[1], odb, ours)) < 0) + goto done; + + our_ptr = &our_input; + } + + if (theirs) { + if ((error = merge_file_input_from_index( + &their_input, &odb_object[2], odb, theirs)) < 0) + goto done; + + their_ptr = &their_input; + } error = merge_file__from_inputs(out, - ancestor_ptr, &our_input, &their_input, options); + ancestor_ptr, our_ptr, their_ptr, options); done: git_odb_object_free(odb_object[0]); diff --git a/tests/libgit2/merge/files.c b/tests/libgit2/merge/files.c index 0f2dfbdf428..0a393b870f9 100644 --- a/tests/libgit2/merge/files.c +++ b/tests/libgit2/merge/files.c @@ -175,6 +175,52 @@ void test_merge_files__automerge_from_index(void) git_merge_file_result_free(&result); } +void test_merge_files__automerge_from_index_delete_file(void) +{ + git_merge_file_result result = {0}; + git_index_entry ancestor, theirs, *ours = NULL; + + git_oid_from_string(&ancestor.id, "d427e0b2e138501a3d15cc376077a3631e15bd46", GIT_OID_SHA1); + ancestor.path = "automergeable.txt"; + ancestor.mode = GIT_FILEMODE_BLOB; + + git_oid_from_string(&theirs.id, "d427e0b2e138501a3d15cc376077a3631e15bd46", GIT_OID_SHA1); + theirs.path = "automergeable.txt"; + theirs.mode = GIT_FILEMODE_BLOB; + + cl_git_pass(git_merge_file_from_index(&result, repo, + &ancestor, ours, &theirs, 0)); + + cl_assert_equal_i(1, result.automergeable); + + cl_assert_equal_s(NULL, result.path); + cl_assert_equal_i(GIT_FILEMODE_UNREADABLE, result.mode); + + cl_assert_equal_i(0, result.len); + + git_merge_file_result_free(&result); +} + +void test_merge_files__automerge_from_index_add_file(void) +{ + git_merge_file_result result = {0}; + git_index_entry *ancestor=NULL, ours, *theirs=NULL; + + git_oid_from_string(&ours.id, "d427e0b2e138501a3d15cc376077a3631e15bd46", GIT_OID_SHA1); + ours.path = "automergeable.txt"; + ours.mode = GIT_FILEMODE_BLOB; + + cl_git_pass(git_merge_file_from_index(&result, repo, + ancestor, &ours, theirs, 0)); + + cl_assert_equal_i(1, result.automergeable); + + cl_assert_equal_s("automergeable.txt", result.path); + cl_assert_equal_i(GIT_FILEMODE_BLOB, result.mode); + + git_merge_file_result_free(&result); +} + void test_merge_files__automerge_whitespace_eol(void) { git_merge_file_input ancestor = GIT_MERGE_FILE_INPUT_INIT,