diff options
Diffstat (limited to 'builtin')
-rw-r--r-- | builtin/apply.c | 53 |
1 files changed, 50 insertions, 3 deletions
diff --git a/builtin/apply.c b/builtin/apply.c index 5a7201fc86..d84958b596 100644 --- a/builtin/apply.c +++ b/builtin/apply.c @@ -16,6 +16,8 @@ #include "dir.h" #include "diff.h" #include "parse-options.h" +#include "xdiff-interface.h" +#include "ll-merge.h" /* * --check turns on checking that the working tree matches the @@ -194,12 +196,16 @@ struct patch { unsigned int is_copy:1; unsigned int is_rename:1; unsigned int recount:1; + unsigned int conflicted_threeway:1; struct fragment *fragments; char *result; size_t resultsize; char old_sha1_prefix[41]; char new_sha1_prefix[41]; struct patch *next; + + /* three-way fallback result */ + unsigned char threeway_stage[3][20]; }; static void free_fragment_list(struct fragment *list) @@ -3146,7 +3152,29 @@ static int three_way_merge(struct image *image, const unsigned char *ours, const unsigned char *theirs) { - return -1; /* for now */ + mmfile_t base_file, our_file, their_file; + mmbuffer_t result = { NULL }; + int status; + + read_mmblob(&base_file, base); + read_mmblob(&our_file, ours); + read_mmblob(&their_file, theirs); + status = ll_merge(&result, path, + &base_file, "base", + &our_file, "ours", + &their_file, "theirs", NULL); + free(base_file.ptr); + free(our_file.ptr); + free(their_file.ptr); + if (status < 0 || !result.ptr) { + free(result.ptr); + return -1; + } + clear_image(image); + image->buf = result.ptr; + image->len = result.size; + + return status; } static int try_threeway(struct image *image, struct patch *patch, @@ -3155,6 +3183,7 @@ static int try_threeway(struct image *image, struct patch *patch, unsigned char pre_sha1[20], post_sha1[20], our_sha1[20]; struct strbuf buf = STRBUF_INIT; size_t len; + int status; char *img; struct image tmp_image; @@ -3167,6 +3196,9 @@ static int try_threeway(struct image *image, struct patch *patch, if (get_sha1(patch->old_sha1_prefix, pre_sha1) || read_blob_object(&buf, pre_sha1, patch->old_mode)) return error("repository lacks the necessary blob to fall back on 3-way merge."); + + fprintf(stderr, "Falling back to three-way merge...\n"); + img = strbuf_detach(&buf, &len); prepare_image(&tmp_image, img, len, 1); /* Apply the patch to get the post image */ @@ -3186,8 +3218,23 @@ static int try_threeway(struct image *image, struct patch *patch, clear_image(&tmp_image); /* in-core three-way merge between post and our using pre as base */ - return three_way_merge(image, - patch->new_name, pre_sha1, our_sha1, post_sha1); + status = three_way_merge(image, patch->new_name, + pre_sha1, our_sha1, post_sha1); + if (status < 0) { + fprintf(stderr, "Failed to fall back on three-way merge...\n"); + return status; + } + + if (status) { + patch->conflicted_threeway = 1; + hashcpy(patch->threeway_stage[0], pre_sha1); + hashcpy(patch->threeway_stage[1], our_sha1); + hashcpy(patch->threeway_stage[2], post_sha1); + fprintf(stderr, "Applied patch to '%s' with conflicts.\n", patch->new_name); + } else { + fprintf(stderr, "Applied patch to '%s' cleanly.\n", patch->new_name); + } + return 0; } static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce) |