This series teaches "git apply" the same "three-way merge fallback" logic that makes "am -3" so useful when flipping patches around. For people who do not know how "am -3" magic works, the basic idea goes like this: 0) Suppose you have this history leading to commit E: O---A---B---...---E 1) Also suppose you have a patch that is based on an older version; it no longer applies to the version of the file you have. The patch would apply cleanly to the file in an older version, say A, and would result in file in a fictitious version X: X / O---A---B---...---E You can think of X as a commit where this patch was taken from, but there may not be any such commit in your object database. 2) A useful observation to make here is that the result of applying such a patch to your current version should look similar to the result of merging X and E: X-------------M merge! / / O---A---B---...---E And this feature works exactly like that. - After trying and failing to apply the patch text, we inspect our object database and see if there is a blob object that matches what is recorded on the "index" line of the patch as its preimage. We may not have such a blob object, and we give up in such a case. - And then we try to apply the patch text to that blob. This also could fail, as the patch author could have tweaked the patch text after producing the patch with "git diff" without adjusting the "index" line. Again we simply give up in such a case. - When we successfully apply the patch to the older blob, the result would be what would appear in the fictitious commit X in the above picture. We then try the usual file-level three-way merge between X and E using A as the base version. This could cleanly merge, in which case we successfully applied the patch. Or this could conflict, in which case we record the conflicted stages in the index, just like a conflicted "merge" or an "am -3" does, and leave the conflict markers in the result. I've wanted to see this for the past few years, and even suggested that this is a good bite-sized GSoC project, but unfortunately nobody bit it; you have to do it yourself if you really want it, I guess. Note that this iteration still does not do a few things: - We probably should call into the rerere machinery to have it help the user deal with the conflicts. - The "--threeway" option probably should be made explicitly incompatible with the "--reject" option (implement it when the command line is parsed). - It might make sense to make "--threeway" imply "--index", but it is not strictly necessary (see the second test case in t4108). - Documentation updates are missing. - "am -3" should be rewritten by using this. That in turn means that the "--build-fake-ancestor" option of "git apply" will lose the only and the last in-tree user, but we may not be able to drop it immediately as there may be out-of-tree users. On the other hand, any out-of-tree user that uses the "--build-fake-ancestor" option is reimplementing the three-way fallback on their own, and they can be updated to use the new "--threeway" option of "git apply". - Once this proves useful, it may deserve to use short-and-sweet "-3" option. Junio C Hamano (8): apply: reformat comment apply: accept --threeway command line option apply: split load_preimage() helper function out apply: clear_image() clears things a bit more apply: refactor read_file_or_gitlink() apply: fall back on three-way merge apply: plug the three-way merge logic in apply: register conflicted stages to the index builtin/apply.c | 198 +++++++++++++++++++++++++++++++++++++++++----- t/t4108-apply-threeway.sh | 78 ++++++++++++++++++ 2 files changed, 257 insertions(+), 19 deletions(-) create mode 100755 t/t4108-apply-threeway.sh -- 1.7.10.1.562.gfc79b1c -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html