apply: plug the three-way merge logic in
When a patch does not apply to what we have, but we know the preimage the patch was made against, we apply the patch to the preimage to compute what the patch author wanted the result to look like, and attempt a three-way merge between the result and our version, using the intended preimage as the base version. When we are applying the patch using the index, we would additionally need to add the object names of these three blobs involved in the merge, which is not yet done in this step, but we add a field to "struct patch" so that later write-out step can use it. Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano committed
May 9, 2012 at 16:10 UTC
28ff051268463e93613998a017a10d3de45abbc0
1 file changed
+50
-3
builtin/apply.c
+50
-3
@@ -16,6 +16,8 @@
16
#include "dir.h"
17
#include "diff.h"
18
#include "parse-options.h"
19
+#include "xdiff-interface.h"
20
+#include "ll-merge.h"
21
22
/*
23
* --check turns on checking that the working tree matches the
@@ -194,12 +196,16 @@ struct patch {
196
unsigned int is_copy:1;
197
unsigned int is_rename:1;
198
unsigned int recount:1;
199
+ unsigned int conflicted_threeway:1;
200
struct fragment *fragments;
201
char *result;
202
size_t resultsize;
203
char old_sha1_prefix[41];
204
char new_sha1_prefix[41];
205
struct patch *next;
206
+
207
+ /* three-way fallback result */
208
+ unsigned char threeway_stage[3][20];
209
};
210
211
static void free_fragment_list(struct fragment *list)
@@ -3146,7 +3152,29 @@ static int three_way_merge(struct image *image,
3152
const unsigned char *ours,
3153
const unsigned char *theirs)
3154
{
3149
- return -1; /* for now */
3155
+ mmfile_t base_file, our_file, their_file;
3156
+ mmbuffer_t result = { NULL };
3157
+ int status;
3158
+
3159
+ read_mmblob(&base_file, base);
3160
+ read_mmblob(&our_file, ours);
3161
+ read_mmblob(&their_file, theirs);
3162
+ status = ll_merge(&result, path,
3163
+ &base_file, "base",
3164
+ &our_file, "ours",
3165
+ &their_file, "theirs", NULL);
3166
+ free(base_file.ptr);
3167
+ free(our_file.ptr);
3168
+ free(their_file.ptr);
3169
+ if (status < 0 || !result.ptr) {
3170
+ free(result.ptr);
3171
+ return -1;
3172
+ }
3173
+ clear_image(image);
3174
+ image->buf = result.ptr;
3175
+ image->len = result.size;
3176
+
3177
+ return status;
3178
}
3179
3180
static int try_threeway(struct image *image, struct patch *patch,
@@ -3155,6 +3183,7 @@ static int try_threeway(struct image *image, struct patch *patch,
3183
unsigned char pre_sha1[20], post_sha1[20], our_sha1[20];
3184
struct strbuf buf = STRBUF_INIT;
3185
size_t len;
3186
+ int status;
3187
char *img;
3188
struct image tmp_image;
3189
@@ -3167,6 +3196,9 @@ static int try_threeway(struct image *image, struct patch *patch,
3196
if (get_sha1(patch->old_sha1_prefix, pre_sha1) ||
3197
read_blob_object(&buf, pre_sha1, patch->old_mode))
3198
return error("repository lacks the necessary blob to fall back on 3-way merge.");
3199
+
3200
+ fprintf(stderr, "Falling back to three-way merge...\n");
3201
+
3202
img = strbuf_detach(&buf, &len);
3203
prepare_image(&tmp_image, img, len, 1);
3204
/* Apply the patch to get the post image */
@@ -3186,8 +3218,23 @@ static int try_threeway(struct image *image, struct patch *patch,
3218
clear_image(&tmp_image);
3219
3220
/* in-core three-way merge between post and our using pre as base */
3189
- return three_way_merge(image,
3190
- patch->new_name, pre_sha1, our_sha1, post_sha1);
3221
+ status = three_way_merge(image, patch->new_name,
3222
+ pre_sha1, our_sha1, post_sha1);
3223
+ if (status < 0) {
3224
+ fprintf(stderr, "Failed to fall back on three-way merge...\n");
3225
+ return status;
3226
+ }
3227
+
3228
+ if (status) {
3229
+ patch->conflicted_threeway = 1;
3230
+ hashcpy(patch->threeway_stage[0], pre_sha1);
3231
+ hashcpy(patch->threeway_stage[1], our_sha1);
3232
+ hashcpy(patch->threeway_stage[2], post_sha1);
3233
+ fprintf(stderr, "Applied patch to '%s' with conflicts.\n", patch->new_name);
3234
+ } else {
3235
+ fprintf(stderr, "Applied patch to '%s' cleanly.\n", patch->new_name);
3236
+ }
3237
+ return 0;
3238
}
3239
3240
static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)