From 6b92c99bcbf32de131754a4f750278f84bf5b766 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 19 Jan 2014 01:20:25 -0800 Subject: [PATCH] Don't try to merge binary files --- src/checkout.c | 47 +++++++++++++++++- src/merge.c | 43 ++++++++++++++++ src/merge.h | 2 + tests/merge/workdir/simple.c | 37 ++++++++++++++ .../11/aeee27ac45a8402c2fd5b875d66dd844e5df00 | Bin 0 -> 51 bytes .../1c/51d885170f57a0c4e8c69ff6363d91a5b51f85 | Bin 0 -> 30 bytes .../23/ed141a6ae1e798b2f721afedbe947c119111ba | Bin 0 -> 30 bytes .../34/8dcd41e2b467991578e92bedd16971b877ef1e | Bin 0 -> 51 bytes .../6e/3b9eb35214d4e31ed5789afc7d520ac798ce55 | Bin 0 -> 51 bytes .../83/6b8b82b26cab22eaaed8820877c76d6c8bca19 | Bin 0 -> 30 bytes .../ad/01aebfdf2ac13145efafe3f9fcf798882f1730 | Bin 0 -> 158 bytes .../cc/338e4710c9b257106b8d16d82f86458d5beaf1 | Bin 0 -> 159 bytes .../d7/308cc367b2cc23f710834ec1fd8ffbacf1b460 | Bin 0 -> 132 bytes 13 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 tests/resources/merge-resolve/.gitted/objects/11/aeee27ac45a8402c2fd5b875d66dd844e5df00 create mode 100644 tests/resources/merge-resolve/.gitted/objects/1c/51d885170f57a0c4e8c69ff6363d91a5b51f85 create mode 100644 tests/resources/merge-resolve/.gitted/objects/23/ed141a6ae1e798b2f721afedbe947c119111ba create mode 100644 tests/resources/merge-resolve/.gitted/objects/34/8dcd41e2b467991578e92bedd16971b877ef1e create mode 100644 tests/resources/merge-resolve/.gitted/objects/6e/3b9eb35214d4e31ed5789afc7d520ac798ce55 create mode 100644 tests/resources/merge-resolve/.gitted/objects/83/6b8b82b26cab22eaaed8820877c76d6c8bca19 create mode 100644 tests/resources/merge-resolve/.gitted/objects/ad/01aebfdf2ac13145efafe3f9fcf798882f1730 create mode 100644 tests/resources/merge-resolve/.gitted/objects/cc/338e4710c9b257106b8d16d82f86458d5beaf1 create mode 100644 tests/resources/merge-resolve/.gitted/objects/d7/308cc367b2cc23f710834ec1fd8ffbacf1b460 diff --git a/src/checkout.c b/src/checkout.c index cc49800a2..f64aa9a77 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -70,7 +70,8 @@ typedef struct { int name_collision:1, directoryfile:1, - one_to_two:1; + one_to_two:1, + binary:1; } checkout_conflictdata; static int checkout_notify( @@ -681,6 +682,40 @@ GIT_INLINE(bool) conflict_pathspec_match( return false; } +GIT_INLINE(int) checkout_conflict_detect_binary(git_repository *repo, checkout_conflictdata *conflict) +{ + git_blob *ancestor_blob = NULL, *our_blob = NULL, *their_blob = NULL; + int error = 0; + + if (conflict->ancestor) { + if ((error = git_blob_lookup(&ancestor_blob, repo, &conflict->ancestor->oid)) < 0) + goto done; + + conflict->binary = git_blob_is_binary(ancestor_blob); + } + + if (!conflict->binary && conflict->ours) { + if ((error = git_blob_lookup(&our_blob, repo, &conflict->ours->oid)) < 0) + goto done; + + conflict->binary = git_blob_is_binary(our_blob); + } + + if (!conflict->binary && conflict->theirs) { + if ((error = git_blob_lookup(&their_blob, repo, &conflict->theirs->oid)) < 0) + goto done; + + conflict->binary = git_blob_is_binary(their_blob); + } + +done: + git_blob_free(ancestor_blob); + git_blob_free(our_blob); + git_blob_free(their_blob); + + return error; +} + static int checkout_conflicts_load(checkout_data *data, git_iterator *workdir, git_vector *pathspec) { git_index_conflict_iterator *iterator = NULL; @@ -705,6 +740,9 @@ static int checkout_conflicts_load(checkout_data *data, git_iterator *workdir, g conflict->ours = ours; conflict->theirs = theirs; + if ((error = checkout_conflict_detect_binary(data->repo, conflict)) < 0) + goto done; + git_vector_insert(&data->conflicts, conflict); } @@ -1706,6 +1744,7 @@ static int checkout_create_conflicts(checkout_data *data) int error = 0; git_vector_foreach(&data->conflicts, i, conflict) { + /* Both deleted: nothing to do */ if (conflict->ours == NULL && conflict->theirs == NULL) error = 0; @@ -1749,7 +1788,11 @@ static int checkout_create_conflicts(checkout_data *data) else if (S_ISLNK(conflict->theirs->mode)) error = checkout_write_entry(data, conflict, conflict->ours); - else + /* If any side is binary, write the ours side */ + else if (conflict->binary) + error = checkout_write_entry(data, conflict, conflict->ours); + + else if (!error) error = checkout_write_merge(data, conflict); if (error) diff --git a/src/merge.c b/src/merge.c index 3ac9167e3..124befc14 100644 --- a/src/merge.c +++ b/src/merge.c @@ -551,6 +551,10 @@ static int merge_conflict_resolve_automerge( strcmp(conflict->ancestor_entry.path, conflict->their_entry.path) != 0) return 0; + /* Reject binary conflicts */ + if (conflict->binary) + return 0; + if ((error = git_repository_odb(&odb, diff_list->repo)) < 0 || (error = git_merge_file_input_from_index_entry(&ancestor, diff_list->repo, &conflict->ancestor_entry)) < 0 || (error = git_merge_file_input_from_index_entry(&ours, diff_list->repo, &conflict->our_entry)) < 0 || @@ -1150,6 +1154,44 @@ GIT_INLINE(int) merge_diff_detect_type( return 0; } +GIT_INLINE(int) merge_diff_detect_binary( + git_repository *repo, + git_merge_diff *conflict) +{ + git_blob *ancestor_blob = NULL, *our_blob = NULL, *their_blob = NULL; + int error = 0; + + if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry)) { + if ((error = git_blob_lookup(&ancestor_blob, repo, &conflict->ancestor_entry.oid)) < 0) + goto done; + + conflict->binary = git_blob_is_binary(ancestor_blob); + } + + if (!conflict->binary && + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry)) { + if ((error = git_blob_lookup(&our_blob, repo, &conflict->our_entry.oid)) < 0) + goto done; + + conflict->binary = git_blob_is_binary(our_blob); + } + + if (!conflict->binary && + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry)) { + if ((error = git_blob_lookup(&their_blob, repo, &conflict->their_entry.oid)) < 0) + goto done; + + conflict->binary = git_blob_is_binary(their_blob); + } + +done: + git_blob_free(ancestor_blob); + git_blob_free(our_blob); + git_blob_free(their_blob); + + return error; +} + GIT_INLINE(int) index_entry_dup( git_index_entry *out, git_pool *pool, @@ -1221,6 +1263,7 @@ static int merge_diff_list_insert_conflict( if ((conflict = merge_diff_from_index_entries(diff_list, tree_items)) == NULL || merge_diff_detect_type(conflict) < 0 || merge_diff_detect_df_conflict(merge_df_data, conflict) < 0 || + merge_diff_detect_binary(diff_list->repo, conflict) < 0 || git_vector_insert(&diff_list->conflicts, conflict) < 0) return -1; diff --git a/src/merge.h b/src/merge.h index b240f6c44..dda023528 100644 --- a/src/merge.h +++ b/src/merge.h @@ -106,6 +106,8 @@ typedef struct { git_index_entry their_entry; git_delta_t their_status; + + int binary:1; } git_merge_diff; /** Internal structure for merge inputs */ diff --git a/tests/merge/workdir/simple.c b/tests/merge/workdir/simple.c index 2142fc4f9..d4f387a26 100644 --- a/tests/merge/workdir/simple.c +++ b/tests/merge/workdir/simple.c @@ -489,3 +489,40 @@ void test_merge_workdir_simple__unrelated_with_conflicts(void) git_merge_result_free(result); } +void test_merge_workdir_simple__binary(void) +{ + git_oid our_oid, their_oid, our_file_oid; + git_commit *our_commit; + git_merge_head *their_head; + git_merge_result *result; + const git_index_entry *binary_entry; + git_merge_opts opts = GIT_MERGE_OPTS_INIT; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "1c51d885170f57a0c4e8c69ff6363d91a5b51f85", 1, "binary" }, + { 0100644, "23ed141a6ae1e798b2f721afedbe947c119111ba", 2, "binary" }, + { 0100644, "836b8b82b26cab22eaaed8820877c76d6c8bca19", 3, "binary" }, + }; + + cl_git_pass(git_oid_fromstr(&our_oid, "cc338e4710c9b257106b8d16d82f86458d5beaf1")); + cl_git_pass(git_oid_fromstr(&their_oid, "ad01aebfdf2ac13145efafe3f9fcf798882f1730")); + + cl_git_pass(git_commit_lookup(&our_commit, repo, &our_oid)); + cl_git_pass(git_reset(repo, (git_object *)our_commit, GIT_RESET_HARD)); + + cl_git_pass(git_merge_head_from_oid(&their_head, repo, &their_oid)); + + cl_git_pass(git_merge(&result, repo, (const git_merge_head **)&their_head, 1, &opts)); + + cl_assert(merge_test_index(repo_index, merge_index_entries, 3)); + + cl_git_pass(git_index_add_bypath(repo_index, "binary")); + cl_assert((binary_entry = git_index_get_bypath(repo_index, "binary", 0)) != NULL); + + cl_git_pass(git_oid_fromstr(&our_file_oid, "23ed141a6ae1e798b2f721afedbe947c119111ba")); + cl_assert(git_oid_cmp(&binary_entry->oid, &our_file_oid) == 0); + + git_merge_head_free(their_head); + git_merge_result_free(result); + git_commit_free(our_commit); +} diff --git a/tests/resources/merge-resolve/.gitted/objects/11/aeee27ac45a8402c2fd5b875d66dd844e5df00 b/tests/resources/merge-resolve/.gitted/objects/11/aeee27ac45a8402c2fd5b875d66dd844e5df00 new file mode 100644 index 0000000000000000000000000000000000000000..90e729f6d414d57c5bb523246370e8ffc6790e29 GIT binary patch literal 51 zcmV-30L=e*0V^p=O;s>9VK6i>Ff%bxNXpDhEUIKsek&rC_3-(OP2UyQzuh;bMsT9w JE&wg05VhTO6$1bO literal 0 HcmV?d00001 diff --git a/tests/resources/merge-resolve/.gitted/objects/1c/51d885170f57a0c4e8c69ff6363d91a5b51f85 b/tests/resources/merge-resolve/.gitted/objects/1c/51d885170f57a0c4e8c69ff6363d91a5b51f85 new file mode 100644 index 0000000000000000000000000000000000000000..9a21e26c0a72e4e2221863abecc5e4e51db3d082 GIT binary patch literal 30 mcmb|9VK6i>Ff%bxNXpDhEUILX3B1uN&L6(u$ctn1znR%iT)I`h J6#yX^5B%a^6yg8? literal 0 HcmV?d00001 diff --git a/tests/resources/merge-resolve/.gitted/objects/6e/3b9eb35214d4e31ed5789afc7d520ac798ce55 b/tests/resources/merge-resolve/.gitted/objects/6e/3b9eb35214d4e31ed5789afc7d520ac798ce55 new file mode 100644 index 0000000000000000000000000000000000000000..c6100cb012e1d604a2d7ae0b47e80442f75c5735 GIT binary patch literal 51 zcmbqHvqAVHe6d<3@-YxwD_&{vHf8as0uef&HIc^ZK?O8SP)n#a zC#sN*QzE_R(uaJMPZ~u&m)`ci$txfBNB6eU=zFj8LcQH2U{nAYf|F+zloE$MMkoJ~ M5M0(NzIgIWH$$69`v3p{ literal 0 HcmV?d00001 diff --git a/tests/resources/merge-resolve/.gitted/objects/cc/338e4710c9b257106b8d16d82f86458d5beaf1 b/tests/resources/merge-resolve/.gitted/objects/cc/338e4710c9b257106b8d16d82f86458d5beaf1 new file mode 100644 index 0000000000000000000000000000000000000000..85b3b811231ae6ed3e0be481b449f08f48565827 GIT binary patch literal 159 zcmV;Q0AT-k0i}*h4gw(%1zmHBzJP}2Ghkwj8*ktRpu5S;0x=B6>x*Y_SE)t4N3GUv zfU$TOT?7!5h?tPb`4pWtWD5HngXd*oj?RhaqP2RZF3$lRtd2x>3E2=CTLS86oe&m| zrQ}2fvs<)E@3FQHcmAZ#@K{^j+Y>G_?T>DCqu%yb#)(?J0@|}iv>|vn>NxkNokxfK Nkx;_hP+yWiOHQzFOnLwS literal 0 HcmV?d00001 diff --git a/tests/resources/merge-resolve/.gitted/objects/d7/308cc367b2cc23f710834ec1fd8ffbacf1b460 b/tests/resources/merge-resolve/.gitted/objects/d7/308cc367b2cc23f710834ec1fd8ffbacf1b460 new file mode 100644 index 0000000000000000000000000000000000000000..b02cda4fa7c1521518c61b0aa8b2ed2b2c06688e GIT binary patch literal 132 zcmV-~0DJ#<0i}&g4#FT1KwWc+xqyZ#(1FAlH{QSt@R_Dv&`Bu9czf{-?q1&Fy)3nE z9niZ|Z_HqZ>$(ly__eo~zVDcDVAeKf2c~ mH#ubKmn`)LXo5yGjsl#u*IErb#-0C2sI={|ebg7XnmwTGK|;O& literal 0 HcmV?d00001