{"thread":{"id":"30796","subject":"[PATCH v3 01/19] apply: fix an incomplete comment in check_patch()","startedAt":"2012-06-13T19:32:41Z","lastAt":"2012-06-13T19:33:00Z","messageCount":20,"participants":["Junio C Hamano"],"isPatch":true,"patchVersion":3,"patchTotal":19},"messages":[{"id":"193583","messageId":"1339615980-19727-1-git-send-email-gitster@pobox.com","threadId":"30796","inReplyTo":null,"subject":"[PATCH v3 00/19] \"git apply --3way\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-13T19:32:41Z","receivedAt":"2012-06-13T19:32:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Here is the third round.  Previous ones are:\n\n    http://thread.gmane.org/gmane.comp.version-control.git/197538\n    http://thread.gmane.org/gmane.comp.version-control.git/197637\n\n\"git am -3\" is useful when you have to accept a patch submission to\na tree that has slightly been modified, but when you are reordeing\nyour own work, you would be picking some parts of a later commits to\nearlier codebase without wanting to make commits out of individual\nsteps.\n\nTeach \"git apply\" a similar \"-3\"way merge fallback option with this\nseries, and you can now apply your patches without having to reduce\ncontext.  As it will leave the conflicted halves in the index and\nlet you manually resolve conflicts in the working tree, \"--3way\"\nimplies \"--index\", and cannot be used with \"--cached\".\n\nNote that this does not call merge-recursive like \"am -3\" does, and\ndoes not implement renames (i.e. a patch wants to modify path A,\nyour codebase has the corresponding contents at path B---\"git am -3\"\nwill end up modifying path B, but the round of this series does\nnot).  It should be more or less straightforward to enhance it,\nthough.  Instead of aborting with \"preimage A does not exist in the\nindex nor the working tree\", after finding the necessary blob that\nthe patch author had at path A, you run the similarity algorithm\nwith the blob in your tree to find path B, update the \"struct patch\"\nto rewrite it to apply to path B, and let the existing code take\ncare of the rest.\n\nGiven that I started this early last month, even discounting the\nfact that I was looking at it only in the background, the whole\nthing would have been a bit too big for a student inexperienced to\nthe code base to swallow.  I would say that it would be a good\nbite-sized GSoC project next summer to build on this series and make\nit replace the \"am -3\" implementation (that means the above \"apply a\npatch to A to path B\" needs to be added), which lets us kill the\nugly \"--build-fake-ancestor\" hack.\n\nJunio C Hamano (19):\n  apply: fix an incomplete comment in check_patch()\n  apply: a bit more comments on PATH_TO_BE_DELETED\n  apply: clear_image() clears things a bit more\n  apply: refactor read_file_or_gitlink()\n  apply: factor out checkout_target() helper function\n  apply: split load_preimage() helper function out\n  apply: refactor \"previous patch\" logic\n  apply: further split load_preimage()\n  apply: move check_to_create_blob() closer to its sole caller\n  apply: move \"already exists\" logic to check_to_create()\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: move verify_index_match() higher\n  apply: --3way with add/add conflict\n  apply: register conflicted stages to the index\n  apply: allow rerere() upon --3way results\n  apply: document --3way option\n  apply --3way: tests\n\n Documentation/git-apply.txt |  11 +-\n builtin/apply.c             | 550 ++++++++++++++++++++++++++++++++++----------\n t/t4108-apply-threeway.sh   | 157 +++++++++++++\n t/t4117-apply-reject.sh     |   8 +\n 4 files changed, 608 insertions(+), 118 deletions(-)\n create mode 100755 t/t4108-apply-threeway.sh\n\n-- \n1.7.11.rc3.30.g3bdace2\n"},{"id":"193565","messageId":"1339615980-19727-2-git-send-email-gitster@pobox.com","threadId":"30796","inReplyTo":"1339615980-19727-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 01/19] apply: fix an incomplete comment in check_patch()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-13T19:32:42Z","receivedAt":"2012-06-13T19:32:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This check is not only about type-change (for which it would be\nsufficient to check only was_deleted()) but is also about a swap\nrename.  Otherwise to_be_deleted() check is not justified.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/apply.c | 24 +++++++++++++++---------\n 1 file changed, 15 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex 725712d..be4e3f3 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -3218,16 +3218,22 @@ static int check_patch(struct patch *patch)\n \t\treturn status;\n \told_name = patch->old_name;\n \n+\t/*\n+\t * A type-change diff is always split into a patch to\n+\t * delete old, immediately followed by a patch to\n+\t * create new (see diff.c::run_diff()); in such a case\n+\t * it is Ok that the entry to be deleted by the\n+\t * previous patch is still in the working tree and in\n+\t * the index.\n+\t *\n+\t * A patch to swap-rename between A and B would first rename\n+\t * A to B and then rename B to A.  While applying the first\n+\t * one, the presense of B should not stop A from renamed to B,\n+\t * as to_be_deleted() knows about the later rename.  Removal\n+\t * of B and rename from A to B will be handle the same way.\n+\t */\n \tif ((tpatch = in_fn_table(new_name)) &&\n-\t\t\t(was_deleted(tpatch) || to_be_deleted(tpatch)))\n-\t\t/*\n-\t\t * A type-change diff is always split into a patch to\n-\t\t * delete old, immediately followed by a patch to\n-\t\t * create new (see diff.c::run_diff()); in such a case\n-\t\t * it is Ok that the entry to be deleted by the\n-\t\t * previous patch is still in the working tree and in\n-\t\t * the index.\n-\t\t */\n+\t    (was_deleted(tpatch) || to_be_deleted(tpatch)))\n \t\tok_if_exists = 1;\n \telse\n \t\tok_if_exists = 0;\n-- \n1.7.11.rc3.30.g3bdace2\n"},{"id":"193566","messageId":"1339615980-19727-3-git-send-email-gitster@pobox.com","threadId":"30796","inReplyTo":"1339615980-19727-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 02/19] apply: a bit more comments on PATH_TO_BE_DELETED","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-13T19:32:43Z","receivedAt":"2012-06-13T19:32:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The code is littered with to_be_deleted() whose purpose is not so clear.\nDescribe where it matters.  Also remove an extra space before \"#define\"\nthat snuck in by mistake at 7fac0ee (builtin-apply: keep information about\nfiles to be deleted, 2009-04-11).\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/apply.c | 10 ++++++++--\n 1 file changed, 8 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex be4e3f3..8488c8e 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -2970,9 +2970,15 @@ static struct patch *in_fn_table(const char *name)\n  * item->util in the filename table records the status of the path.\n  * Usually it points at a patch (whose result records the contents\n  * of it after applying it), but it could be PATH_WAS_DELETED for a\n- * path that a previously applied patch has already removed.\n+ * path that a previously applied patch has already removed, or\n+ * PATH_TO_BE_DELETED for a path that a later patch would remove.\n+ *\n+ * The latter is needed to deal with a case where two paths A and B\n+ * are swapped by first renaming A to B and then renaming B to A;\n+ * moving A to B should not be prevented due to presense of B as we\n+ * will remove it in a later patch.\n  */\n- #define PATH_TO_BE_DELETED ((struct patch *) -2)\n+#define PATH_TO_BE_DELETED ((struct patch *) -2)\n #define PATH_WAS_DELETED ((struct patch *) -1)\n \n static int to_be_deleted(struct patch *patch)\n-- \n1.7.11.rc3.30.g3bdace2\n"},{"id":"193567","messageId":"1339615980-19727-4-git-send-email-gitster@pobox.com","threadId":"30796","inReplyTo":"1339615980-19727-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 03/19] apply: clear_image() clears things a bit more","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-13T19:32:44Z","receivedAt":"2012-06-13T19:32:44Z","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 8488c8e..e2b0942 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.11.rc3.30.g3bdace2\n"},{"id":"193581","messageId":"1339615980-19727-5-git-send-email-gitster@pobox.com","threadId":"30796","inReplyTo":"1339615980-19727-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 04/19] apply: refactor read_file_or_gitlink()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-13T19:32:45Z","receivedAt":"2012-06-13T19:32:45Z","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 e2b0942..3199691 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.11.rc3.30.g3bdace2\n"},{"id":"193584","messageId":"1339615980-19727-6-git-send-email-gitster@pobox.com","threadId":"30796","inReplyTo":"1339615980-19727-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 05/19] apply: factor out checkout_target() helper function","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-13T19:32:46Z","receivedAt":"2012-06-13T19:32:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"When a patch wants to touch a path, if the path exists in the index\nbut is missing in the working tree, \"git apply --index\" checks out\nthe file to the working tree from the index automatically and then\napplies the patch.\n\nSplit this logic out to a separate helper function.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/apply.c | 20 +++++++++++++-------\n 1 file changed, 13 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex 3199691..6a1fdc0 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -3034,6 +3034,18 @@ static void prepare_fn_table(struct patch *patch)\n \t}\n }\n \n+static int checkout_target(struct cache_entry *ce, struct stat *st)\n+{\n+\tstruct checkout costate;\n+\n+\tmemset(&costate, 0, sizeof(costate));\n+\tcostate.base_dir = \"\";\n+\tcostate.refresh_cache = 1;\n+\tif (checkout_entry(ce, &costate, NULL) || lstat(ce->name, st))\n+\t\treturn error(_(\"cannot checkout %s\"), ce->name);\n+\treturn 0;\n+}\n+\n static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n@@ -3163,13 +3175,7 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s\n \t\t}\n \t\t*ce = active_cache[pos];\n \t\tif (stat_ret < 0) {\n-\t\t\tstruct checkout costate;\n-\t\t\t/* checkout */\n-\t\t\tmemset(&costate, 0, sizeof(costate));\n-\t\t\tcostate.base_dir = \"\";\n-\t\t\tcostate.refresh_cache = 1;\n-\t\t\tif (checkout_entry(*ce, &costate, NULL) ||\n-\t\t\t    lstat(old_name, st))\n+\t\t\tif (checkout_target(*ce, st))\n \t\t\t\treturn -1;\n \t\t}\n \t\tif (!cached && verify_index_match(*ce, st))\n-- \n1.7.11.rc3.30.g3bdace2\n"},{"id":"193568","messageId":"1339615980-19727-7-git-send-email-gitster@pobox.com","threadId":"30796","inReplyTo":"1339615980-19727-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 06/19] apply: split load_preimage() helper function out","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-13T19:32:47Z","receivedAt":"2012-06-13T19: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 6a1fdc0..8496db5 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -3046,10 +3046,10 @@ static int checkout_target(struct cache_entry *ce, struct stat *st)\n \treturn 0;\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@@ -3086,7 +3086,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.11.rc3.30.g3bdace2\n"},{"id":"193569","messageId":"1339615980-19727-8-git-send-email-gitster@pobox.com","threadId":"30796","inReplyTo":"1339615980-19727-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 07/19] apply: refactor \"previous patch\" logic","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-13T19:32:48Z","receivedAt":"2012-06-13T19:32:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The code to grab the result of application of a previous patch in the\ninput was mixed with error message generation for a case where a later\npatch tries to modify contents of a path that has been removed.\n\nThe same code is duplicated elsewhere in the code.  Introduce a helper\nto clarify what is going on.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/apply.c | 76 +++++++++++++++++++++++++++++++++++++--------------------\n 1 file changed, 50 insertions(+), 26 deletions(-)\n\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex 8496db5..78dc1a8 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -3046,22 +3046,50 @@ static int checkout_target(struct cache_entry *ce, struct stat *st)\n \treturn 0;\n }\n \n+static struct patch *previous_patch(struct patch *patch, int *gone)\n+{\n+\tstruct patch *previous;\n+\n+\t*gone = 0;\n+\tif (patch->is_copy || patch->is_rename)\n+\t\treturn NULL; /* \"git\" patches do not depend on the order */\n+\n+\tprevious = in_fn_table(patch->old_name);\n+\tif (!previous)\n+\t\treturn NULL;\n+\n+\tif (to_be_deleted(previous))\n+\t\treturn NULL; /* the deletion hasn't happened yet */\n+\n+\tif (was_deleted(previous))\n+\t\t*gone = 1;\n+\n+\treturn previous;\n+}\n+\n+/*\n+ * We are about to apply \"patch\"; populate the \"image\" with the\n+ * current version we have, from the working tree or from the index,\n+ * depending on the situation e.g. --cached/--index.  If we are\n+ * applying a non-git patch that incrementally updates the tree,\n+ * we read from the result of a previous diff.\n+ */\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 \tsize_t len;\n \tchar *img;\n-\tstruct patch *tpatch;\n+\tstruct patch *previous;\n+\tint status;\n \n-\tif (!(patch->is_copy || patch->is_rename) &&\n-\t    (tpatch = in_fn_table(patch->old_name)) != NULL && !to_be_deleted(tpatch)) {\n-\t\tif (was_deleted(tpatch)) {\n-\t\t\treturn error(_(\"patch %s has been renamed/deleted\"),\n-\t\t\t\tpatch->old_name);\n-\t\t}\n+\tprevious = previous_patch(patch, &status);\n+\tif (status)\n+\t\treturn error(_(\"path %s has been renamed/deleted\"),\n+\t\t\t     patch->old_name);\n+\tif (previous) {\n \t\t/* We have a patched copy in memory; use that. */\n-\t\tstrbuf_add(&buf, tpatch->result, tpatch->resultsize);\n+\t\tstrbuf_add(&buf, previous->result, previous->resultsize);\n \t} else if (cached) {\n \t\tif (read_file_or_gitlink(ce, &buf))\n \t\t\treturn error(_(\"read of %s failed\"), patch->old_name);\n@@ -3143,39 +3171,35 @@ static int verify_index_match(struct cache_entry *ce, struct stat *st)\n \treturn ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);\n }\n \n+/*\n+ * If \"patch\" that we are looking at modifies or deletes what we have,\n+ * we would want it not to lose any local modification we have, either\n+ * in the working tree or in the index.\n+ */\n static int check_preimage(struct patch *patch, struct cache_entry **ce, struct stat *st)\n {\n \tconst char *old_name = patch->old_name;\n-\tstruct patch *tpatch = NULL;\n-\tint stat_ret = 0;\n+\tstruct patch *previous = NULL;\n+\tint stat_ret = 0, status;\n \tunsigned st_mode = 0;\n \n-\t/*\n-\t * Make sure that we do not have local modifications from the\n-\t * index when we are looking at the index.  Also make sure\n-\t * we have the preimage file to be patched in the work tree,\n-\t * unless --cached, which tells git to apply only in the index.\n-\t */\n \tif (!old_name)\n \t\treturn 0;\n \n \tassert(patch->is_new <= 0);\n+\tprevious = previous_patch(patch, &status);\n \n-\tif (!(patch->is_copy || patch->is_rename) &&\n-\t    (tpatch = in_fn_table(old_name)) != NULL && !to_be_deleted(tpatch)) {\n-\t\tif (was_deleted(tpatch))\n-\t\t\treturn error(_(\"%s: has been deleted/renamed\"), old_name);\n-\t\tst_mode = tpatch->new_mode;\n+\tif (status)\n+\t\treturn error(_(\"path %s has been renamed/deleted\"), old_name);\n+\tif (previous) {\n+\t\tst_mode = previous->new_mode;\n \t} else if (!cached) {\n \t\tstat_ret = lstat(old_name, st);\n \t\tif (stat_ret && errno != ENOENT)\n \t\t\treturn error(_(\"%s: %s\"), old_name, strerror(errno));\n \t}\n \n-\tif (to_be_deleted(tpatch))\n-\t\ttpatch = NULL;\n-\n-\tif (check_index && !tpatch) {\n+\tif (check_index && !previous) {\n \t\tint pos = cache_name_pos(old_name, strlen(old_name));\n \t\tif (pos < 0) {\n \t\t\tif (patch->is_new < 0)\n@@ -3197,7 +3221,7 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s\n \t\treturn error(_(\"%s: %s\"), old_name, strerror(errno));\n \t}\n \n-\tif (!cached && !tpatch)\n+\tif (!cached && !previous)\n \t\tst_mode = ce_mode_from_stat(*ce, st->st_mode);\n \n \tif (patch->is_new < 0)\n-- \n1.7.11.rc3.30.g3bdace2\n"},{"id":"193573","messageId":"1339615980-19727-9-git-send-email-gitster@pobox.com","threadId":"30796","inReplyTo":"1339615980-19727-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 08/19] apply: further split load_preimage()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-13T19:32:49Z","receivedAt":"2012-06-13T19:32:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"load_preimage() is very specific to grab the current contents for\nthe path given by patch->old_name.  Split the logic that grabs the\ncontents for a path out of it into a separate load_patch_target()\nfunction.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/apply.c | 59 ++++++++++++++++++++++++++++++++++++++-------------------\n 1 file changed, 40 insertions(+), 19 deletions(-)\n\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex 78dc1a8..35e9a9c 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -3067,6 +3067,31 @@ static struct patch *previous_patch(struct patch *patch, int *gone)\n \treturn previous;\n }\n \n+#define SUBMODULE_PATCH_WITHOUT_INDEX 1\n+\n+static int load_patch_target(struct strbuf *buf,\n+\t\t\t     struct cache_entry *ce,\n+\t\t\t     struct stat *st,\n+\t\t\t     const char *name,\n+\t\t\t     unsigned expected_mode)\n+{\n+\tif (cached) {\n+\t\tif (read_file_or_gitlink(ce, buf))\n+\t\t\treturn error(_(\"read of %s failed\"), name);\n+\t} else if (name) {\n+\t\tif (S_ISGITLINK(expected_mode)) {\n+\t\t\tif (ce)\n+\t\t\t\treturn read_file_or_gitlink(ce, buf);\n+\t\t\telse\n+\t\t\t\treturn SUBMODULE_PATCH_WITHOUT_INDEX;\n+\t\t} else {\n+\t\t\tif (read_old_data(st, name, buf))\n+\t\t\t\treturn error(_(\"read of %s failed\"), name);\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n /*\n  * We are about to apply \"patch\"; populate the \"image\" with the\n  * current version we have, from the working tree or from the index,\n@@ -3090,26 +3115,22 @@ static int load_preimage(struct image *image,\n \tif (previous) {\n \t\t/* We have a patched copy in memory; use that. */\n \t\tstrbuf_add(&buf, previous->result, previous->resultsize);\n-\t} else if (cached) {\n-\t\tif (read_file_or_gitlink(ce, &buf))\n+\t} else {\n+\t\tstatus = load_patch_target(&buf, ce, st,\n+\t\t\t\t\t   patch->old_name, patch->old_mode);\n+\t\tif (status < 0)\n+\t\t\treturn status;\n+\t\telse if (status == SUBMODULE_PATCH_WITHOUT_INDEX) {\n+\t\t\t/*\n+\t\t\t * There is no way to apply subproject\n+\t\t\t * patch without looking at the index.\n+\t\t\t * NEEDSWORK: shouldn't this be flagged\n+\t\t\t * as an error???\n+\t\t\t */\n+\t\t\tfree_fragment_list(patch->fragments);\n+\t\t\tpatch->fragments = NULL;\n+\t\t} else if (status) {\n \t\t\treturn error(_(\"read of %s failed\"), patch->old_name);\n-\t} else if (patch->old_name) {\n-\t\tif (S_ISGITLINK(patch->old_mode)) {\n-\t\t\tif (ce) {\n-\t\t\t\tread_file_or_gitlink(ce, &buf);\n-\t\t\t} else {\n-\t\t\t\t/*\n-\t\t\t\t * There is no way to apply subproject\n-\t\t\t\t * patch without looking at the index.\n-\t\t\t\t * NEEDSWORK: shouldn't this be flagged\n-\t\t\t\t * as an error???\n-\t\t\t\t */\n-\t\t\t\tfree_fragment_list(patch->fragments);\n-\t\t\t\tpatch->fragments = NULL;\n-\t\t\t}\n-\t\t} else {\n-\t\t\tif (read_old_data(st, patch->old_name, &buf))\n-\t\t\t\treturn error(_(\"read of %s failed\"), patch->old_name);\n \t\t}\n \t}\n \n-- \n1.7.11.rc3.30.g3bdace2\n"},{"id":"193582","messageId":"1339615980-19727-10-git-send-email-gitster@pobox.com","threadId":"30796","inReplyTo":"1339615980-19727-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 09/19] apply: move check_to_create_blob() closer to its sole caller","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-13T19:32:50Z","receivedAt":"2012-06-13T19:32:50Z","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 | 46 +++++++++++++++++++++++-----------------------\n 1 file changed, 23 insertions(+), 23 deletions(-)\n\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex 35e9a9c..6431178 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -3159,29 +3159,6 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *\n \treturn 0;\n }\n \n-static int check_to_create_blob(const char *new_name, int ok_if_exists)\n-{\n-\tstruct stat nst;\n-\tif (!lstat(new_name, &nst)) {\n-\t\tif (S_ISDIR(nst.st_mode) || ok_if_exists)\n-\t\t\treturn 0;\n-\t\t/*\n-\t\t * A leading component of new_name might be a symlink\n-\t\t * that is going to be removed with this patch, but\n-\t\t * still pointing at somewhere that has the path.\n-\t\t * In such a case, path \"new_name\" does not exist as\n-\t\t * far as git is concerned.\n-\t\t */\n-\t\tif (has_symlink_leading_path(new_name, strlen(new_name)))\n-\t\t\treturn 0;\n-\n-\t\treturn error(_(\"%s: already exists in working directory\"), new_name);\n-\t}\n-\telse if ((errno != ENOENT) && (errno != ENOTDIR))\n-\t\treturn error(\"%s: %s\", new_name, strerror(errno));\n-\treturn 0;\n-}\n-\n static int verify_index_match(struct cache_entry *ce, struct stat *st)\n {\n \tif (S_ISGITLINK(ce->ce_mode)) {\n@@ -3266,6 +3243,29 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s\n \treturn 0;\n }\n \n+static int check_to_create_blob(const char *new_name, int ok_if_exists)\n+{\n+\tstruct stat nst;\n+\tif (!lstat(new_name, &nst)) {\n+\t\tif (S_ISDIR(nst.st_mode) || ok_if_exists)\n+\t\t\treturn 0;\n+\t\t/*\n+\t\t * A leading component of new_name might be a symlink\n+\t\t * that is going to be removed with this patch, but\n+\t\t * still pointing at somewhere that has the path.\n+\t\t * In such a case, path \"new_name\" does not exist as\n+\t\t * far as git is concerned.\n+\t\t */\n+\t\tif (has_symlink_leading_path(new_name, strlen(new_name)))\n+\t\t\treturn 0;\n+\n+\t\treturn error(_(\"%s: already exists in working directory\"), new_name);\n+\t}\n+\telse if ((errno != ENOENT) && (errno != ENOTDIR))\n+\t\treturn error(\"%s: %s\", new_name, strerror(errno));\n+\treturn 0;\n+}\n+\n /*\n  * Check and apply the patch in-core; leave the result in patch->result\n  * for the caller to write it out to the final destination.\n-- \n1.7.11.rc3.30.g3bdace2\n"},{"id":"193572","messageId":"1339615980-19727-11-git-send-email-gitster@pobox.com","threadId":"30796","inReplyTo":"1339615980-19727-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 10/19] apply: move \"already exists\" logic to check_to_create()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-13T19:32:51Z","receivedAt":"2012-06-13T19:32:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The check_to_create_blob() function used to check only the case\nwhere we are applying to the working tree.  Rename the function to\ncheck_to_create() and make it also responsible for checking the case\nwhere we apply to the index.  Also make its caller responsible for\nissuing an error message.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/apply.c | 40 +++++++++++++++++++++++++++++-----------\n 1 file changed, 29 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex 6431178..c4166b3 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -3243,9 +3243,21 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s\n \treturn 0;\n }\n \n-static int check_to_create_blob(const char *new_name, int ok_if_exists)\n+\n+#define EXISTS_IN_INDEX 1\n+#define EXISTS_IN_WORKTREE 2\n+\n+static int check_to_create(const char *new_name, int ok_if_exists)\n {\n \tstruct stat nst;\n+\n+\tif (check_index &&\n+\t    cache_name_pos(new_name, strlen(new_name)) >= 0 &&\n+\t    !ok_if_exists)\n+\t\treturn EXISTS_IN_INDEX;\n+\tif (cached)\n+\t\treturn 0;\n+\n \tif (!lstat(new_name, &nst)) {\n \t\tif (S_ISDIR(nst.st_mode) || ok_if_exists)\n \t\t\treturn 0;\n@@ -3259,10 +3271,10 @@ static int check_to_create_blob(const char *new_name, int ok_if_exists)\n \t\tif (has_symlink_leading_path(new_name, strlen(new_name)))\n \t\t\treturn 0;\n \n-\t\treturn error(_(\"%s: already exists in working directory\"), new_name);\n-\t}\n-\telse if ((errno != ENOENT) && (errno != ENOTDIR))\n+\t\treturn EXISTS_IN_WORKTREE;\n+\t} else if ((errno != ENOENT) && (errno != ENOTDIR)) {\n \t\treturn error(\"%s: %s\", new_name, strerror(errno));\n+\t}\n \treturn 0;\n }\n \n@@ -3310,15 +3322,21 @@ static int check_patch(struct patch *patch)\n \n \tif (new_name &&\n \t    ((0 < patch->is_new) | (0 < patch->is_rename) | patch->is_copy)) {\n-\t\tif (check_index &&\n-\t\t    cache_name_pos(new_name, strlen(new_name)) >= 0 &&\n-\t\t    !ok_if_exists)\n+\t\tint err = check_to_create(new_name, ok_if_exists);\n+\n+\t\tswitch (err) {\n+\t\tcase 0:\n+\t\t\tbreak; /* happy */\n+\t\tcase EXISTS_IN_INDEX:\n \t\t\treturn error(_(\"%s: already exists in index\"), new_name);\n-\t\tif (!cached) {\n-\t\t\tint err = check_to_create_blob(new_name, ok_if_exists);\n-\t\t\tif (err)\n-\t\t\t\treturn err;\n+\t\t\tbreak;\n+\t\tcase EXISTS_IN_WORKTREE:\n+\t\t\treturn error(_(\"%s: already exists in working directory\"),\n+\t\t\t\t     new_name);\n+\t\tdefault:\n+\t\t\treturn err;\n \t\t}\n+\n \t\tif (!patch->new_mode) {\n \t\t\tif (0 < patch->is_new)\n \t\t\t\tpatch->new_mode = S_IFREG | 0644;\n-- \n1.7.11.rc3.30.g3bdace2\n"},{"id":"193571","messageId":"1339615980-19727-12-git-send-email-gitster@pobox.com","threadId":"30796","inReplyTo":"1339615980-19727-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 11/19] apply: accept -3/--3way command line option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-13T19:32:52Z","receivedAt":"2012-06-13T19:32:52Z","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 and\nmaking \"--3way\" imply \"--index\".\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/apply.c         | 25 +++++++++++++++++++++++--\n t/t4117-apply-reject.sh |  8 ++++++++\n 2 files changed, 31 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex c4166b3..509a297 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@@ -3139,6 +3140,12 @@ static int load_preimage(struct image *image,\n \treturn 0;\n }\n \n+static int try_threeway(struct image *image, struct patch *patch,\n+\t\t\tstruct 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@@ -3146,8 +3153,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, apply_fragments() returns 0 */\n+\t\tif (!threeway || try_threeway(&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@@ -4073,6 +4083,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@@ -4121,6 +4133,15 @@ 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+\tif (cached && threeway)\n+\t\tdie(\"--cached and --3way cannot be used together.\");\n+\tif (threeway) {\n+\t\tif (is_not_gitdir)\n+\t\t\tdie(_(\"--3way outside a repository\"));\n+\t\tcheck_index = 1;\n+\t}\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.11.rc3.30.g3bdace2\n"},{"id":"193570","messageId":"1339615980-19727-13-git-send-email-gitster@pobox.com","threadId":"30796","inReplyTo":"1339615980-19727-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 12/19] apply: fall back on three-way merge","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-13T19:32:53Z","receivedAt":"2012-06-13T19:32:53Z","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 | 46 +++++++++++++++++++++++++++++++++++++++++++++-\n 1 file changed, 45 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex 509a297..6936588 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -3140,10 +3140,54 @@ 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(struct image *image, struct patch *patch,\n \t\t\tstruct 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+\t/* post_sha1[] is theirs */\n+\twrite_sha1_file(tmp_image.buf, tmp_image.len, blob_type, post_sha1);\n+\tclear_image(&tmp_image);\n+\n+\t/* our_sha1[] is ours */\n+\tif (load_preimage(&tmp_image, patch, st, ce))\n+\t\treturn error(\"cannot read the current contents of '%s'\",\n+\t\t\t     patch->old_name);\n+\twrite_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.11.rc3.30.g3bdace2\n"},{"id":"193577","messageId":"1339615980-19727-14-git-send-email-gitster@pobox.com","threadId":"30796","inReplyTo":"1339615980-19727-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 13/19] apply: plug the three-way merge logic in","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-13T19:32:54Z","receivedAt":"2012-06-13T19:32:54Z","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 6936588..5ef8652 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@@ -3142,11 +3148,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 = { NULL };\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(struct image *image, struct patch *patch,\n@@ -3155,6 +3183,7 @@ static int try_threeway(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@@ -3167,6 +3196,9 @@ static int try_threeway(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@@ -3186,8 +3218,23 @@ static int try_threeway(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.11.rc3.30.g3bdace2\n"},{"id":"193579","messageId":"1339615980-19727-15-git-send-email-gitster@pobox.com","threadId":"30796","inReplyTo":"1339615980-19727-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 14/19] apply: move verify_index_match() higher","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-13T19:32:55Z","receivedAt":"2012-06-13T19:32:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"We will be adding another caller of this function in a later patch.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/apply.c | 20 ++++++++++----------\n 1 file changed, 10 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex 5ef8652..8bc4218 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -3074,6 +3074,16 @@ static struct patch *previous_patch(struct patch *patch, int *gone)\n \treturn previous;\n }\n \n+static int verify_index_match(struct cache_entry *ce, struct stat *st)\n+{\n+\tif (S_ISGITLINK(ce->ce_mode)) {\n+\t\tif (!S_ISDIR(st->st_mode))\n+\t\t\treturn -1;\n+\t\treturn 0;\n+\t}\n+\treturn ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);\n+}\n+\n #define SUBMODULE_PATCH_WITHOUT_INDEX 1\n \n static int load_patch_target(struct strbuf *buf,\n@@ -3260,16 +3270,6 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *\n \treturn 0;\n }\n \n-static int verify_index_match(struct cache_entry *ce, struct stat *st)\n-{\n-\tif (S_ISGITLINK(ce->ce_mode)) {\n-\t\tif (!S_ISDIR(st->st_mode))\n-\t\t\treturn -1;\n-\t\treturn 0;\n-\t}\n-\treturn ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);\n-}\n-\n /*\n  * If \"patch\" that we are looking at modifies or deletes what we have,\n  * we would want it not to lose any local modification we have, either\n-- \n1.7.11.rc3.30.g3bdace2\n"},{"id":"193580","messageId":"1339615980-19727-16-git-send-email-gitster@pobox.com","threadId":"30796","inReplyTo":"1339615980-19727-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 15/19] apply: --3way with add/add conflict","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-13T19:32:56Z","receivedAt":"2012-06-13T19:32:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"When a patch wants to create a path, but we already have it in our\ncurrent state, pretend as if the patch and we independently added\nthe same path and cause add/add conflict, so that the user can\nresolve it just like \"git merge\" in the same situation.\n\nFor that purpose, implement load_current() in terms of the\nload_patch_target() helper introduced earlier to read the current\ncontents from the path given by patch->new_name (patch->old_name is\nNULL for a creation patch).\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/apply.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++-------\n 1 file changed, 62 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex 8bc4218..c3b9f76 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -197,6 +197,7 @@ struct patch {\n \tunsigned int is_rename:1;\n \tunsigned int recount:1;\n \tunsigned int conflicted_threeway:1;\n+\tunsigned int direct_to_threeway:1;\n \tstruct fragment *fragments;\n \tchar *result;\n \tsize_t resultsize;\n@@ -3187,6 +3188,48 @@ static int three_way_merge(struct image *image,\n \treturn status;\n }\n \n+/*\n+ * When directly falling back to add/add three-way merge, we read from\n+ * the current contents of the new_name.  In no cases other than that\n+ * this function will be called.\n+ */\n+static int load_current(struct image *image, struct patch *patch)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tint status, pos;\n+\tsize_t len;\n+\tchar *img;\n+\tstruct stat st;\n+\tstruct cache_entry *ce;\n+\tchar *name = patch->new_name;\n+\tunsigned mode = patch->new_mode;\n+\n+\tif (!patch->is_new)\n+\t\tdie(\"BUG: patch to %s is not a creation\", patch->old_name);\n+\n+\tpos = cache_name_pos(name, strlen(name));\n+\tif (pos < 0)\n+\t\treturn error(_(\"%s: does not exist in index\"), name);\n+\tce = active_cache[pos];\n+\tif (lstat(name, &st)) {\n+\t\tif (errno != ENOENT)\n+\t\t\treturn error(_(\"%s: %s\"), name, strerror(errno));\n+\t\tif (checkout_target(ce, &st))\n+\t\t\treturn -1;\n+\t}\n+\tif (verify_index_match(ce, &st))\n+\t\treturn error(_(\"%s: does not match index\"), name);\n+\n+\tstatus = load_patch_target(&buf, ce, &st, name, mode);\n+\tif (status < 0)\n+\t\treturn status;\n+\telse if (status)\n+\t\treturn -1;\n+\timg = strbuf_detach(&buf, &len);\n+\tprepare_image(image, img, len, !patch->is_binary);\n+\treturn 0;\n+}\n+\n static int try_threeway(struct image *image, struct patch *patch,\n \t\t\tstruct stat *st, struct cache_entry *ce)\n {\n@@ -3198,13 +3241,15 @@ static int try_threeway(struct image *image, struct patch *patch,\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+\tif (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+\tif (patch->is_new)\n+\t\twrite_sha1_file(\"\", 0, blob_type, pre_sha1);\n+\telse if (get_sha1(patch->old_sha1_prefix, pre_sha1) ||\n+\t\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@@ -3221,9 +3266,15 @@ static int try_threeway(struct image *image, struct patch *patch,\n \tclear_image(&tmp_image);\n \n \t/* our_sha1[] is ours */\n-\tif (load_preimage(&tmp_image, patch, st, ce))\n-\t\treturn error(\"cannot read the current contents of '%s'\",\n-\t\t\t     patch->old_name);\n+\tif (patch->is_new) {\n+\t\tif (load_current(&tmp_image, patch))\n+\t\t\treturn error(\"cannot read the current contents of '%s'\",\n+\t\t\t\t     patch->new_name);\n+\t} else {\n+\t\tif (load_preimage(&tmp_image, patch, st, ce))\n+\t\t\treturn error(\"cannot read the current contents of '%s'\",\n+\t\t\t\t     patch->old_name);\n+\t}\n \twrite_sha1_file(tmp_image.buf, tmp_image.len, blob_type, our_sha1);\n \tclear_image(&tmp_image);\n \n@@ -3254,7 +3305,8 @@ 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+\tif (patch->direct_to_threeway ||\n+\t    apply_fragments(&image, patch) < 0) {\n \t\t/* Note: with --reject, apply_fragments() returns 0 */\n \t\tif (!threeway || try_threeway(&image, patch, st, ce) < 0)\n \t\t\treturn -1;\n@@ -3425,7 +3477,9 @@ static int check_patch(struct patch *patch)\n \t    ((0 < patch->is_new) | (0 < patch->is_rename) | patch->is_copy)) {\n \t\tint err = check_to_create(new_name, ok_if_exists);\n \n-\t\tswitch (err) {\n+\t\tif (err && threeway) {\n+\t\t\tpatch->direct_to_threeway = 1;\n+\t\t} else switch (err) {\n \t\tcase 0:\n \t\t\tbreak; /* happy */\n \t\tcase EXISTS_IN_INDEX:\n-- \n1.7.11.rc3.30.g3bdace2\n"},{"id":"193576","messageId":"1339615980-19727-17-git-send-email-gitster@pobox.com","threadId":"30796","inReplyTo":"1339615980-19727-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 16/19] apply: register conflicted stages to the index","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-13T19:32:57Z","receivedAt":"2012-06-13T19:32:57Z","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           | 65 +++++++++++++++++++++++++++++++++++----\n t/t4108-apply-threeway.sh | 78 +++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 137 insertions(+), 6 deletions(-)\n create mode 100755 t/t4108-apply-threeway.sh\n\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex c3b9f76..8afba92 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -3288,7 +3288,10 @@ static int try_threeway(struct image *image, struct patch *patch,\n \n \tif (status) {\n \t\tpatch->conflicted_threeway = 1;\n-\t\thashcpy(patch->threeway_stage[0], pre_sha1);\n+\t\tif (patch->is_new)\n+\t\t\thashclr(patch->threeway_stage[0]);\n+\t\telse\n+\t\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@@ -3846,6 +3849,32 @@ 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+\tstruct cache_entry *ce;\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+\n+\tremove_file_from_cache(patch->new_name);\n+\tfor (stage = 1; stage < 4; stage++) {\n+\t\tif (is_null_sha1(patch->threeway_stage[stage - 1]))\n+\t\t\tcontinue;\n+\t\tce = 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@@ -3856,7 +3885,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@@ -3958,6 +3991,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@@ -3966,12 +4000,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@@ -4094,8 +4144,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.11.rc3.30.g3bdace2\n"},{"id":"193574","messageId":"1339615980-19727-18-git-send-email-gitster@pobox.com","threadId":"30796","inReplyTo":"1339615980-19727-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 17/19] apply: allow rerere() upon --3way results","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-13T19:32:58Z","receivedAt":"2012-06-13T19:32:58Z","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 8afba92..d12f4f2 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@@ -4020,6 +4021,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.11.rc3.30.g3bdace2\n"},{"id":"193578","messageId":"1339615980-19727-19-git-send-email-gitster@pobox.com","threadId":"30796","inReplyTo":"1339615980-19727-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 18/19] apply: document --3way option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-13T19:32:59Z","receivedAt":"2012-06-13T19:32:59Z","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 | 11 ++++++++++-\n 1 file changed, 10 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt\nindex afd2c9a..634b84e 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,15 @@ 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.  This option implies the `--index` option, and is incompatible\n+\twith the `--reject` and the `--cached` options.\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.11.rc3.30.g3bdace2\n"},{"id":"193575","messageId":"1339615980-19727-20-git-send-email-gitster@pobox.com","threadId":"30796","inReplyTo":"1339615980-19727-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 19/19] apply --3way: tests","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-13T19:33:00Z","receivedAt":"2012-06-13T19:33:00Z","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 t/t4108-apply-threeway.sh | 54 +++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 54 insertions(+)\n\ndiff --git a/t/t4108-apply-threeway.sh b/t/t4108-apply-threeway.sh\nindex e6d4da6..fa5d4ef 100755\n--- a/t/t4108-apply-threeway.sh\n+++ b/t/t4108-apply-threeway.sh\n@@ -100,4 +100,58 @@ test_expect_success 'apply with --3way with rerere enabled' '\n \ttest_cmp expect one\n '\n \n+test_expect_success 'apply -3 with add/add conflict setup' '\n+\tgit reset --hard &&\n+\n+\tgit checkout -b adder &&\n+\tcreate_file 1 2 3 4 5 6 7 >three &&\n+\tcreate_file 1 2 3 4 5 6 7 >four &&\n+\tgit add three four &&\n+\tgit commit -m \"add three and four\" &&\n+\n+\tgit checkout -b another adder^ &&\n+\tcreate_file 1 2 3 4 5 6 7 >three &&\n+\tcreate_file 1 2 3 four 5 6 7 >four &&\n+\tgit add three four &&\n+\tgit commit -m \"add three and four\" &&\n+\n+\t# Merging another should be similar to applying this patch\n+\tgit diff adder...another >P.diff &&\n+\n+\tgit checkout adder^0 &&\n+\ttest_must_fail git merge --no-commit another &&\n+\tgit ls-files -s >expect.ls &&\n+\tgit diff HEAD | sanitize_conflicted_diff >expect.diff\n+'\n+\n+test_expect_success 'apply -3 with add/add conflict' '\n+\t# should fail to apply ...\n+\tgit reset --hard &&\n+\tgit checkout adder^0 &&\n+\ttest_must_fail git apply --index --3way P.diff &&\n+\t# ... and leave conflicts in the index and in the working tree\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_expect_success 'apply -3 with add/add conflict (dirty working tree)' '\n+\t# should fail to apply ...\n+\tgit reset --hard &&\n+\tgit checkout adder^0 &&\n+\techo >>four &&\n+\tcat four >four.save &&\n+\tcat three >three.save &&\n+\tgit ls-files -s >expect.ls &&\n+\ttest_must_fail git apply --index --3way P.diff &&\n+\t# ... and should not touch anything\n+\tgit ls-files -s >actual.ls &&\n+\ttest_cmp expect.ls actual.ls &&\n+\ttest_cmp four.save four &&\n+\ttest_cmp three.save three\n+'\n+\n test_done\n-- \n1.7.11.rc3.30.g3bdace2\n"}]}