{"thread":{"id":"30501","subject":"[PATCH v2 0/9] \"git apply --3way\"","startedAt":"2012-05-10T22:32:44Z","lastAt":"2012-05-10T22:32:53Z","messageCount":10,"participants":["Junio C Hamano"],"isPatch":true,"patchVersion":2,"patchTotal":9},"messages":[{"id":"191359","messageId":"1336689173-15822-1-git-send-email-gitster@pobox.com","threadId":"30501","inReplyTo":null,"subject":"[PATCH v2 0/9] \"git apply --3way\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-10T22:32:44Z","receivedAt":"2012-05-10T22:32:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Here is its second round.  Changes from the previous one are:\n\n - The series has been reordered to have refactoring patches early.\n\n - The option name is corrected to \"--3way\" and also takes short-and-sweet\n   \"-3\" to parallel \"am\".\n\n - An invocation to ask \"--3way\" together with \"--reject\" is rejected.\n\n - The rerere machinery is given a chance to work on the resulting\n   conflicts.\n\n - The option is now documented.\n\nThere are minor things that I still find suboptimal, but as a standalone\nnew feature, I consider it more or less good to go otherwise.\n\nHere are some things people might be interested in enhancing (hint, hint):\n\n - Buffer error() messages from the first pass (i.e. attempting to apply\n   to your current version) if the command is running under --3way mode,\n   and show them if it turns out that we cannot fall back to the three-way\n   logic (e.g. when the preimage on which the patch was allegedly based is\n   not available, or the patch fails to apply to such a preimage).\n   Otherwise discard the error messages from the first pass and show only\n   the messages from the three-way merge phase.\n\n - Probably support add/add conflicts.  Note that this is prevented much\n   earlier in the codepath and some surgery is needed to allow us to skip\n   the first pass and go directly to the three-way codepath.\n\n - Similarly, a patch that attempts to delete a path that you no longer\n   have is rejected early in the codepath. I have a hunch that it is not\n   worth worrying about, because we do not know what we removed and cannot\n   tell if what they removed is compatible with our earlier removal.\n\nJunio C Hamano (9):\n  apply: clear_image() clears things a bit more\n  apply: refactor read_file_or_gitlink()\n  apply: split load_preimage() helper function out\n  apply: accept -3/--3way command line option\n  apply: fall back on three-way merge\n  apply: plug the three-way merge logic in\n  apply: register conflicted stages to the index\n  apply: allow rerere() upon --3way results\n  apply: document --3way option\n\n Documentation/git-apply.txt |  10 ++-\n builtin/apply.c             | 202 +++++++++++++++++++++++++++++++++++++++-----\n t/t4108-apply-threeway.sh   | 103 ++++++++++++++++++++++\n t/t4117-apply-reject.sh     |   8 ++\n 4 files changed, 303 insertions(+), 20 deletions(-)\n create mode 100755 t/t4108-apply-threeway.sh\n\n-- \n1.7.10.1.574.g840b38f\n"},{"id":"191368","messageId":"1336689173-15822-2-git-send-email-gitster@pobox.com","threadId":"30501","inReplyTo":"1336689173-15822-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 1/9] apply: clear_image() clears things a bit more","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-10T22:32:45Z","receivedAt":"2012-05-10T22:32:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The clear_image() function did not clear the line table in the image\nstructure; this does not matter for the current callers, as the function\nis only called from the codepaths that deal with binary patches where the\nline table is never populated, and the codepaths that do populate the line\ntable free it themselves.\n\nBut it will start to matter when we introduce a codepath to retry a failed\npatch, so make sure it clears and frees everything.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/apply.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex 725712d..99b1608 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -371,8 +371,8 @@ static void prepare_image(struct image *image, char *buf, size_t len,\n static void clear_image(struct image *image)\n {\n \tfree(image->buf);\n-\timage->buf = NULL;\n-\timage->len = 0;\n+\tfree(image->line_allocated);\n+\tmemset(image, 0, sizeof(*image));\n }\n \n /* fmt must contain _one_ %s and no other substitution */\n-- \n1.7.10.1.574.g840b38f\n"},{"id":"191360","messageId":"1336689173-15822-3-git-send-email-gitster@pobox.com","threadId":"30501","inReplyTo":"1336689173-15822-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 2/9] apply: refactor read_file_or_gitlink()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-10T22:32:46Z","receivedAt":"2012-05-10T22:32:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Reading a blob out of the object store does not have to require that the\ncaller has a cache entry for it.\n\nCreate a read_blob_object() helper function that takes the object name and\nmode, and use it to reimplement the original function as a thin wrapper to\nit.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/apply.c | 18 +++++++++++-------\n 1 file changed, 11 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex 99b1608..ca330e3 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -2930,20 +2930,17 @@ static int apply_fragments(struct image *img, struct patch *patch)\n \treturn 0;\n }\n \n-static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)\n+static int read_blob_object(struct strbuf *buf, const unsigned char *sha1, unsigned mode)\n {\n-\tif (!ce)\n-\t\treturn 0;\n-\n-\tif (S_ISGITLINK(ce->ce_mode)) {\n+\tif (S_ISGITLINK(mode)) {\n \t\tstrbuf_grow(buf, 100);\n-\t\tstrbuf_addf(buf, \"Subproject commit %s\\n\", sha1_to_hex(ce->sha1));\n+\t\tstrbuf_addf(buf, \"Subproject commit %s\\n\", sha1_to_hex(sha1));\n \t} else {\n \t\tenum object_type type;\n \t\tunsigned long sz;\n \t\tchar *result;\n \n-\t\tresult = read_sha1_file(ce->sha1, &type, &sz);\n+\t\tresult = read_sha1_file(sha1, &type, &sz);\n \t\tif (!result)\n \t\t\treturn -1;\n \t\t/* XXX read_sha1_file NUL-terminates */\n@@ -2952,6 +2949,13 @@ static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)\n \treturn 0;\n }\n \n+static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)\n+{\n+\tif (!ce)\n+\t\treturn 0;\n+\treturn read_blob_object(buf, ce->sha1, ce->ce_mode);\n+}\n+\n static struct patch *in_fn_table(const char *name)\n {\n \tstruct string_list_item *item;\n-- \n1.7.10.1.574.g840b38f\n"},{"id":"191361","messageId":"1336689173-15822-4-git-send-email-gitster@pobox.com","threadId":"30501","inReplyTo":"1336689173-15822-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 3/9] apply: split load_preimage() helper function out","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-10T22:32:47Z","receivedAt":"2012-05-10T22:32:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The function apply_data() gets a patch for a single path, reads the\npreimage in core, and applies the change represented in the patch.\n\nSeparate out the first part that reads the preimage into a separate\nhelper function load_preimage().\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/apply.c | 15 ++++++++++++---\n 1 file changed, 12 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex ca330e3..2a31023 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -3028,10 +3028,10 @@ static void prepare_fn_table(struct patch *patch)\n \t}\n }\n \n-static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)\n+static int load_preimage(struct image *image,\n+\t\t\t struct patch *patch, struct stat *st, struct cache_entry *ce)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n-\tstruct image image;\n \tsize_t len;\n \tchar *img;\n \tstruct patch *tpatch;\n@@ -3068,7 +3068,16 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *\n \t}\n \n \timg = strbuf_detach(&buf, &len);\n-\tprepare_image(&image, img, len, !patch->is_binary);\n+\tprepare_image(image, img, len, !patch->is_binary);\n+\treturn 0;\n+}\n+\n+static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)\n+{\n+\tstruct image image;\n+\n+\tif (load_preimage(&image, patch, st, ce) < 0)\n+\t\treturn -1;\n \n \tif (apply_fragments(&image, patch) < 0)\n \t\treturn -1; /* note with --reject this succeeds. */\n-- \n1.7.10.1.574.g840b38f\n"},{"id":"191366","messageId":"1336689173-15822-5-git-send-email-gitster@pobox.com","threadId":"30501","inReplyTo":"1336689173-15822-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 4/9] apply: accept -3/--3way command line option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-10T22:32:48Z","receivedAt":"2012-05-10T22:32:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This is the beginning of teaching the three-way merge fallback logic \"git\nam -3\" uses to the underlying \"git apply\".  It only implements the command\nline parsing part, and does not do anything interesting yet, other than\nmaking sure that \"--reject\" and \"--3way\" are not given together.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/apply.c         | 19 +++++++++++++++++--\n t/t4117-apply-reject.sh |  8 ++++++++\n 2 files changed, 25 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex 2a31023..fcd5bdf 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -46,6 +46,7 @@ static int apply_with_reject;\n static int apply_verbosely;\n static int allow_overlap;\n static int no_add;\n+static int threeway;\n static const char *fake_ancestor;\n static int line_termination = '\\n';\n static unsigned int p_context = UINT_MAX;\n@@ -3072,6 +3073,12 @@ static int load_preimage(struct image *image,\n \treturn 0;\n }\n \n+static int try_threeway_fallback(struct image *image, struct patch *patch,\n+\t\t\t\t struct stat *st, struct cache_entry *ce)\n+{\n+\treturn -1; /* for now */\n+}\n+\n static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)\n {\n \tstruct image image;\n@@ -3079,8 +3086,11 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *\n \tif (load_preimage(&image, patch, st, ce) < 0)\n \t\treturn -1;\n \n-\tif (apply_fragments(&image, patch) < 0)\n-\t\treturn -1; /* note with --reject this succeeds. */\n+\tif (apply_fragments(&image, patch) < 0) {\n+\t\t/* Note: with --reject, the above call succeeds. */\n+\t\tif (!threeway || try_threeway_fallback(&image, patch, st, ce) < 0)\n+\t\t\treturn -1;\n+\t}\n \tpatch->result = image.buf;\n \tpatch->resultsize = image.len;\n \tadd_to_fn_table(patch);\n@@ -3992,6 +4002,8 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)\n \t\t\t\"apply a patch without touching the working tree\"),\n \t\tOPT_BOOLEAN(0, \"apply\", &force_apply,\n \t\t\t\"also apply the patch (use with --stat/--summary/--check)\"),\n+\t\tOPT_BOOL('3', \"3way\", &threeway,\n+\t\t\t \"attempt three-way merge if a patch does not apply\"),\n \t\tOPT_FILENAME(0, \"build-fake-ancestor\", &fake_ancestor,\n \t\t\t\"build a temporary index based on embedded index information\"),\n \t\t{ OPTION_CALLBACK, 'z', NULL, NULL, NULL,\n@@ -4040,6 +4052,9 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)\n \targc = parse_options(argc, argv, prefix, builtin_apply_options,\n \t\t\tapply_usage, 0);\n \n+\tif (apply_with_reject && threeway)\n+\t\tdie(\"--reject and --3way cannot be used together.\");\n+\n \tif (apply_with_reject)\n \t\tapply = apply_verbosely = 1;\n \tif (!force_apply && (diffstat || numstat || summary || check || fake_ancestor))\ndiff --git a/t/t4117-apply-reject.sh b/t/t4117-apply-reject.sh\nindex e9ccd16..8e15ecb 100755\n--- a/t/t4117-apply-reject.sh\n+++ b/t/t4117-apply-reject.sh\n@@ -46,6 +46,14 @@ test_expect_success setup '\n \tcat file1 >saved.file1\n '\n \n+test_expect_success 'apply --reject is incompatible with --3way' '\n+\ttest_when_finished \"cat saved.file1 >file1\" &&\n+\tgit diff >patch.0 &&\n+\tgit checkout file1 &&\n+\ttest_must_fail git apply --reject --3way patch.0 &&\n+\tgit diff --exit-code\n+'\n+\n test_expect_success 'apply without --reject should fail' '\n \n \tif git apply patch.1\n-- \n1.7.10.1.574.g840b38f\n"},{"id":"191367","messageId":"1336689173-15822-6-git-send-email-gitster@pobox.com","threadId":"30501","inReplyTo":"1336689173-15822-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 5/9] apply: fall back on three-way merge","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-10T22:32:49Z","receivedAt":"2012-05-10T22:32:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Grab the preimage blob the patch claims to be based on out of the object\nstore, apply the patch, and then call three-way-merge function.  This step\nstill does not plug the actual three-way merge logic yet, but we are\ngetting there.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/apply.c | 43 ++++++++++++++++++++++++++++++++++++++++++-\n 1 file changed, 42 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex fcd5bdf..1fe178f 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -3073,10 +3073,51 @@ static int load_preimage(struct image *image,\n \treturn 0;\n }\n \n+static int three_way_merge(struct image *image,\n+\t\t\t   char *path,\n+\t\t\t   unsigned char *base,\n+\t\t\t   unsigned char *ours,\n+\t\t\t   unsigned char *theirs)\n+{\n+\treturn -1; /* for now */\n+}\n+\n static int try_threeway_fallback(struct image *image, struct patch *patch,\n \t\t\t\t struct stat *st, struct cache_entry *ce)\n {\n-\treturn -1; /* for now */\n+\tunsigned char pre_sha1[20], post_sha1[20], our_sha1[20];\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tsize_t len;\n+\tchar *img;\n+\tstruct image tmp_image;\n+\n+\t/* No point falling back to 3-way merge in these cases */\n+\tif (patch->is_new || patch->is_delete ||\n+\t    S_ISGITLINK(patch->old_mode) || S_ISGITLINK(patch->new_mode))\n+\t\treturn -1;\n+\n+\t/* Preimage the patch was prepared for */\n+\tif (get_sha1(patch->old_sha1_prefix, pre_sha1) ||\n+\t    read_blob_object(&buf, pre_sha1, patch->old_mode))\n+\t\treturn error(\"repository lacks the necessary blob to fall back on 3-way merge.\");\n+\timg = strbuf_detach(&buf, &len);\n+\tprepare_image(&tmp_image, img, len, 1);\n+\t/* Apply the patch to get the post image */\n+\tif (apply_fragments(&tmp_image, patch) < 0) {\n+\t\tclear_image(&tmp_image);\n+\t\treturn -1;\n+\t}\n+\thash_sha1_file(tmp_image.buf, tmp_image.len, blob_type, post_sha1);\n+\tclear_image(&tmp_image);\n+\n+\t/* pre_sha1[] is common, post_sha1[] is theirs */\n+\tload_preimage(&tmp_image, patch, st, ce);\n+\thash_sha1_file(tmp_image.buf, tmp_image.len, blob_type, our_sha1);\n+\tclear_image(&tmp_image);\n+\n+\t/* in-core three-way merge between post and our using pre as base */\n+\treturn three_way_merge(image,\n+\t\t\t       patch->new_name, pre_sha1, our_sha1, post_sha1);\n }\n \n static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)\n-- \n1.7.10.1.574.g840b38f\n"},{"id":"191364","messageId":"1336689173-15822-7-git-send-email-gitster@pobox.com","threadId":"30501","inReplyTo":"1336689173-15822-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 6/9] apply: plug the three-way merge logic in","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-10T22:32:50Z","receivedAt":"2012-05-10T22:32:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"When a patch does not apply to what we have, but we know the preimage the\npatch was made against, we apply the patch to the preimage to compute what\nthe patch author wanted the result to look like, and attempt a three-way\nmerge between the result and our version, using the intended preimage as\nthe base version.\n\nWhen we are applying the patch using the index, we would additionally need\nto add the object names of these three blobs involved in the merge, which\nis not yet done in this step, but we add a field to \"struct patch\" so that\nlater write-out step can use it.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/apply.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++------\n 1 file changed, 53 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex 1fe178f..ac53ecf 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -16,6 +16,8 @@\n #include \"dir.h\"\n #include \"diff.h\"\n #include \"parse-options.h\"\n+#include \"xdiff-interface.h\"\n+#include \"ll-merge.h\"\n \n /*\n  *  --check turns on checking that the working tree matches the\n@@ -194,12 +196,16 @@ struct patch {\n \tunsigned int is_copy:1;\n \tunsigned int is_rename:1;\n \tunsigned int recount:1;\n+\tunsigned int conflicted_threeway:1;\n \tstruct fragment *fragments;\n \tchar *result;\n \tsize_t resultsize;\n \tchar old_sha1_prefix[41];\n \tchar new_sha1_prefix[41];\n \tstruct patch *next;\n+\n+\t/* three-way fallback result */\n+\tunsigned char threeway_stage[3][20];\n };\n \n static void free_fragment_list(struct fragment *list)\n@@ -3075,11 +3081,33 @@ static int load_preimage(struct image *image,\n \n static int three_way_merge(struct image *image,\n \t\t\t   char *path,\n-\t\t\t   unsigned char *base,\n-\t\t\t   unsigned char *ours,\n-\t\t\t   unsigned char *theirs)\n+\t\t\t   const unsigned char *base,\n+\t\t\t   const unsigned char *ours,\n+\t\t\t   const unsigned char *theirs)\n {\n-\treturn -1; /* for now */\n+\tmmfile_t base_file, our_file, their_file;\n+\tmmbuffer_t result = { 0 };\n+\tint status;\n+\n+\tread_mmblob(&base_file, base);\n+\tread_mmblob(&our_file, ours);\n+\tread_mmblob(&their_file, theirs);\n+\tstatus = ll_merge(&result, path,\n+\t\t\t  &base_file, \"base\",\n+\t\t\t  &our_file, \"ours\",\n+\t\t\t  &their_file, \"theirs\", NULL);\n+\tfree(base_file.ptr);\n+\tfree(our_file.ptr);\n+\tfree(their_file.ptr);\n+\tif (status < 0 || !result.ptr) {\n+\t\tfree(result.ptr);\n+\t\treturn -1;\n+\t}\n+\tclear_image(image);\n+\timage->buf = result.ptr;\n+\timage->len = result.size;\n+\n+\treturn status;\n }\n \n static int try_threeway_fallback(struct image *image, struct patch *patch,\n@@ -3088,6 +3116,7 @@ static int try_threeway_fallback(struct image *image, struct patch *patch,\n \tunsigned char pre_sha1[20], post_sha1[20], our_sha1[20];\n \tstruct strbuf buf = STRBUF_INIT;\n \tsize_t len;\n+\tint status;\n \tchar *img;\n \tstruct image tmp_image;\n \n@@ -3100,6 +3129,9 @@ static int try_threeway_fallback(struct image *image, struct patch *patch,\n \tif (get_sha1(patch->old_sha1_prefix, pre_sha1) ||\n \t    read_blob_object(&buf, pre_sha1, patch->old_mode))\n \t\treturn error(\"repository lacks the necessary blob to fall back on 3-way merge.\");\n+\n+\tfprintf(stderr, \"Falling back to three-way merge...\\n\");\n+\n \timg = strbuf_detach(&buf, &len);\n \tprepare_image(&tmp_image, img, len, 1);\n \t/* Apply the patch to get the post image */\n@@ -3116,8 +3148,23 @@ static int try_threeway_fallback(struct image *image, struct patch *patch,\n \tclear_image(&tmp_image);\n \n \t/* in-core three-way merge between post and our using pre as base */\n-\treturn three_way_merge(image,\n-\t\t\t       patch->new_name, pre_sha1, our_sha1, post_sha1);\n+\tstatus = three_way_merge(image, patch->new_name,\n+\t\t\t\t pre_sha1, our_sha1, post_sha1);\n+\tif (status < 0) {\n+\t\tfprintf(stderr, \"Failed to fall back on three-way merge...\\n\");\n+\t\treturn status;\n+\t}\n+\n+\tif (status) {\n+\t\tpatch->conflicted_threeway = 1;\n+\t\thashcpy(patch->threeway_stage[0], pre_sha1);\n+\t\thashcpy(patch->threeway_stage[1], our_sha1);\n+\t\thashcpy(patch->threeway_stage[2], post_sha1);\n+\t\tfprintf(stderr, \"Applied patch to '%s' with conflicts.\\n\", patch->new_name);\n+\t} else {\n+\t\tfprintf(stderr, \"Applied patch to '%s' cleanly.\\n\", patch->new_name);\n+\t}\n+\treturn 0;\n }\n \n static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)\n-- \n1.7.10.1.574.g840b38f\n"},{"id":"191362","messageId":"1336689173-15822-8-git-send-email-gitster@pobox.com","threadId":"30501","inReplyTo":"1336689173-15822-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 7/9] apply: register conflicted stages to the index","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-10T22:32:51Z","receivedAt":"2012-05-10T22:32:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Now we have all the necessary logic to fall back on three-way merge when\nthe patch does not cleanly apply, insert the conflicted entries to the\nindex as appropriate.  This obviously triggers only when the \"--index\"\noption is used.\n\nWhen we fall back to three-way merge and some of the merges fail, just\nlike the case where the \"--reject\" option was specified and we had to\nwrite some \"*.rej\" files out for unapplicable patches, exit the command\nwith non-zero status without showing the diffstat and summary.  Otherwise\nthey would make the list of problematic paths scroll off the display.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/apply.c           | 55 ++++++++++++++++++++++++++++++---\n t/t4108-apply-threeway.sh | 78 +++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 128 insertions(+), 5 deletions(-)\n create mode 100755 t/t4108-apply-threeway.sh\n\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex ac53ecf..9f376b5 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -3708,6 +3708,27 @@ static void create_one_file(char *path, unsigned mode, const char *buf, unsigned\n \tdie_errno(_(\"unable to write file '%s' mode %o\"), path, mode);\n }\n \n+static void add_conflicted_stages_file(struct patch *patch)\n+{\n+\tint stage, namelen;\n+\tunsigned ce_size, mode;\n+\n+\tif (!update_index)\n+\t\treturn;\n+\tnamelen = strlen(patch->new_name);\n+\tce_size = cache_entry_size(namelen);\n+\tmode = patch->new_mode ? patch->new_mode : (S_IFREG | 0644);\n+\tfor (stage = 1; stage < 4; stage++) {\n+\t\tstruct cache_entry *ce = xcalloc(1, ce_size);\n+\t\tmemcpy(ce->name, patch->new_name, namelen);\n+\t\tce->ce_mode = create_ce_mode(mode);\n+\t\tce->ce_flags = create_ce_flags(namelen, stage);\n+\t\thashcpy(ce->sha1, patch->threeway_stage[stage - 1]);\n+\t\tif (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0)\n+\t\t\tdie(_(\"unable to add cache entry for %s\"), patch->new_name);\n+\t}\n+}\n+\n static void create_file(struct patch *patch)\n {\n \tchar *path = patch->new_name;\n@@ -3718,7 +3739,11 @@ static void create_file(struct patch *patch)\n \tif (!mode)\n \t\tmode = S_IFREG | 0644;\n \tcreate_one_file(path, mode, buf, size);\n-\tadd_index_file(path, mode, buf, size);\n+\n+\tif (patch->conflicted_threeway)\n+\t\tadd_conflicted_stages_file(patch);\n+\telse\n+\t\tadd_index_file(path, mode, buf, size);\n }\n \n /* phase zero is to remove, phase one is to create */\n@@ -3820,6 +3845,7 @@ static int write_out_results(struct patch *list)\n \tint phase;\n \tint errs = 0;\n \tstruct patch *l;\n+\tstruct string_list cpath = STRING_LIST_INIT_DUP;\n \n \tfor (phase = 0; phase < 2; phase++) {\n \t\tl = list;\n@@ -3828,12 +3854,28 @@ static int write_out_results(struct patch *list)\n \t\t\t\terrs = 1;\n \t\t\telse {\n \t\t\t\twrite_out_one_result(l, phase);\n-\t\t\t\tif (phase == 1 && write_out_one_reject(l))\n-\t\t\t\t\terrs = 1;\n+\t\t\t\tif (phase == 1) {\n+\t\t\t\t\tif (write_out_one_reject(l))\n+\t\t\t\t\t\terrs = 1;\n+\t\t\t\t\tif (l->conflicted_threeway) {\n+\t\t\t\t\t\tstring_list_append(&cpath, l->new_name);\n+\t\t\t\t\t\terrs = 1;\n+\t\t\t\t\t}\n+\t\t\t\t}\n \t\t\t}\n \t\t\tl = l->next;\n \t\t}\n \t}\n+\n+\tif (cpath.nr) {\n+\t\tstruct string_list_item *item;\n+\n+\t\tsort_string_list(&cpath);\n+\t\tfor_each_string_list_item(item, &cpath)\n+\t\t\tfprintf(stderr, \"U %s\\n\", item->string);\n+\t\tstring_list_clear(&cpath, 0);\n+\t}\n+\n \treturn errs;\n }\n \n@@ -3956,8 +3998,11 @@ static int apply_patch(int fd, const char *filename, int options)\n \t    !apply_with_reject)\n \t\texit(1);\n \n-\tif (apply && write_out_results(list))\n-\t\texit(1);\n+\tif (apply && write_out_results(list)) {\n+\t\tif (apply_with_reject)\n+\t\t\texit(1);\n+\t\treturn 1;\n+\t}\n \n \tif (fake_ancestor)\n \t\tbuild_fake_ancestor(list, fake_ancestor);\ndiff --git a/t/t4108-apply-threeway.sh b/t/t4108-apply-threeway.sh\nnew file mode 100755\nindex 0000000..475dfb5\n--- /dev/null\n+++ b/t/t4108-apply-threeway.sh\n@@ -0,0 +1,78 @@\n+#!/bin/sh\n+\n+test_description='git apply --3way'\n+\n+. ./test-lib.sh\n+\n+create_file () {\n+\tfor i\n+\tdo\n+\t\techo \"$i\"\n+\tdone\n+}\n+\n+sanitize_conflicted_diff () {\n+\tsed -e '\n+\t\t/^index /d\n+\t\ts/^\\(+[<>][<>][<>][<>]*\\) .*/\\1/\n+\t'\n+}\n+\n+test_expect_success setup '\n+\ttest_tick &&\n+\tcreate_file >one 1 2 3 4 5 6 7 &&\n+\tcat one >two &&\n+\tgit add one two &&\n+\tgit commit -m initial &&\n+\n+\tgit branch side &&\n+\n+\ttest_tick &&\n+\tcreate_file >one 1 two 3 4 5 six 7 &&\n+\tcreate_file >two 1 two 3 4 5 6 7 &&\n+\tgit commit -a -m master &&\n+\n+\tgit checkout side &&\n+\tcreate_file >one 1 2 3 4 five 6 7 &&\n+\tcreate_file >two 1 2 3 4 five 6 7 &&\n+\tgit commit -a -m side &&\n+\n+\tgit checkout master\n+'\n+\n+test_expect_success 'apply without --3way' '\n+\tgit diff side^ side >P.diff &&\n+\n+\t# should fail to apply\n+\tgit reset --hard &&\n+\tgit checkout master^0 &&\n+\ttest_must_fail git apply --index P.diff &&\n+\t# should leave things intact\n+\tgit diff-files --exit-code &&\n+\tgit diff-index --exit-code --cached HEAD\n+'\n+\n+test_expect_success 'apply with --3way' '\n+\t# Merging side should be similar to applying this patch\n+\tgit diff ...side >P.diff &&\n+\n+\t# The corresponding conflicted merge\n+\tgit reset --hard &&\n+\tgit checkout master^0 &&\n+\ttest_must_fail git merge --no-commit side &&\n+\tgit ls-files -s >expect.ls &&\n+\tgit diff HEAD | sanitize_conflicted_diff >expect.diff &&\n+\n+\t# should fail to apply\n+\tgit reset --hard &&\n+\tgit checkout master^0 &&\n+\ttest_must_fail git apply --index --3way P.diff &&\n+\tgit ls-files -s >actual.ls &&\n+\tgit diff HEAD | sanitize_conflicted_diff >actual.diff &&\n+\n+\t# The result should resemble the corresponding merge\n+\ttest_cmp expect.ls actual.ls &&\n+\ttest_cmp expect.diff actual.diff\n+'\n+\n+test_done\n-- \n1.7.10.1.574.g840b38f\n"},{"id":"191365","messageId":"1336689173-15822-9-git-send-email-gitster@pobox.com","threadId":"30501","inReplyTo":"1336689173-15822-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 8/9] apply: allow rerere() upon --3way results","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-10T22:32:52Z","receivedAt":"2012-05-10T22:32:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/apply.c           |  3 +++\n t/t4108-apply-threeway.sh | 25 +++++++++++++++++++++++++\n 2 files changed, 28 insertions(+)\n\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex 9f376b5..502c1bf1 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -18,6 +18,7 @@\n #include \"parse-options.h\"\n #include \"xdiff-interface.h\"\n #include \"ll-merge.h\"\n+#include \"rerere.h\"\n \n /*\n  *  --check turns on checking that the working tree matches the\n@@ -3874,6 +3875,8 @@ static int write_out_results(struct patch *list)\n \t\tfor_each_string_list_item(item, &cpath)\n \t\t\tfprintf(stderr, \"U %s\\n\", item->string);\n \t\tstring_list_clear(&cpath, 0);\n+\n+\t\trerere(0);\n \t}\n \n \treturn errs;\ndiff --git a/t/t4108-apply-threeway.sh b/t/t4108-apply-threeway.sh\nindex 475dfb5..e6d4da6 100755\n--- a/t/t4108-apply-threeway.sh\n+++ b/t/t4108-apply-threeway.sh\n@@ -75,4 +75,29 @@ test_expect_success 'apply with --3way' '\n \ttest_cmp expect.diff actual.diff\n '\n \n+test_expect_success 'apply with --3way with rerere enabled' '\n+\tgit config rerere.enabled true &&\n+\n+\t# Merging side should be similar to applying this patch\n+\tgit diff ...side >P.diff &&\n+\n+\t# The corresponding conflicted merge\n+\tgit reset --hard &&\n+\tgit checkout master^0 &&\n+\ttest_must_fail git merge --no-commit side &&\n+\n+\t# Manually resolve and record the resolution\n+\tcreate_file 1 two 3 4 five six 7 >one &&\n+\tgit rerere &&\n+\tcat one >expect &&\n+\n+\t# should fail to apply\n+\tgit reset --hard &&\n+\tgit checkout master^0 &&\n+\ttest_must_fail git apply --index --3way P.diff &&\n+\n+\t# but rerere should have replayed the recorded resolution\n+\ttest_cmp expect one\n+'\n+\n test_done\n-- \n1.7.10.1.574.g840b38f\n"},{"id":"191363","messageId":"1336689173-15822-10-git-send-email-gitster@pobox.com","threadId":"30501","inReplyTo":"1336689173-15822-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 9/9] apply: document --3way option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-10T22:32:53Z","receivedAt":"2012-05-10T22:32:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/git-apply.txt | 10 +++++++++-\n 1 file changed, 9 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt\nindex afd2c9a..354ff95 100644\n--- a/Documentation/git-apply.txt\n+++ b/Documentation/git-apply.txt\n@@ -9,7 +9,7 @@ git-apply - Apply a patch to files and/or to the index\n SYNOPSIS\n --------\n [verse]\n-'git apply' [--stat] [--numstat] [--summary] [--check] [--index]\n+'git apply' [--stat] [--numstat] [--summary] [--check] [--index] [--3way]\n \t  [--apply] [--no-add] [--build-fake-ancestor=<file>] [-R | --reverse]\n \t  [--allow-binary-replacement | --binary] [--reject] [-z]\n \t  [-p<n>] [-C<n>] [--inaccurate-eof] [--recount] [--cached]\n@@ -72,6 +72,14 @@ OPTIONS\n \tcached data, apply the patch, and store the result in the index\n \twithout using the working tree. This implies `--index`.\n \n+-3::\n+--3way::\n+\tWhen the patch does not apply cleanly, fall back on 3-way merge if\n+\tthe patch records the identity of blobs it is supposed to apply to,\n+\tand we have those blobs available locally, possibly leaving the\n+\tconflict markers in the files in the working tree for the user to\n+\tresolve.\n+\n --build-fake-ancestor=<file>::\n \tNewer 'git diff' output has embedded 'index information'\n \tfor each blob to help identify the original version that\n-- \n1.7.10.1.574.g840b38f\n"}]}