git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 0/8] "git apply --threeway"

From
Junio C Hamano <gitster@pobox.com>
Date
May 10, 2012, 06:02 UTC
Message-ID
<1336629745-22436-1-git-send-email-gitster@pobox.com>

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
Next: Junio C Hamano
Message 1 of 19 in “"git apply --threeway"”
  1. 0/8 "git apply --threeway"Junio C Hamano, May 10, 2012
  2. 1/8 apply: reformat commentJunio C Hamano, May 10, 2012
  3. 2/8 apply: accept --threeway command line optionJunio C Hamano, May 10, 2012
  4. Nguyen Thai Ngoc DuyMay 10, 2012
  5. Junio C HamanoMay 10, 2012
  6. 3/8 apply: split load_preimage() helper function outJunio C Hamano, May 10, 2012
  7. 4/8 apply: clear_image() clears things a bit moreJunio C Hamano, May 10, 2012
  8. 5/8 apply: refactor read_file_or_gitlink()Junio C Hamano, May 10, 2012
  9. 6/8 apply: fall back on three-way mergeJunio C Hamano, May 10, 2012
  10. Matthieu MoyMay 10, 2012
  11. Junio C HamanoMay 10, 2012
  12. Matthieu MoyMay 10, 2012
  13. Jeff KingMay 10, 2012
  14. Junio C HamanoMay 10, 2012
  15. Jeff KingMay 10, 2012
  16. 7/8 apply: plug the three-way merge logic inJunio C Hamano, May 10, 2012
  17. 8/8 apply: register conflicted stages to the indexJunio C Hamano, May 10, 2012
  18. Matthieu MoyMay 10, 2012
  19. Junio C HamanoMay 10, 2012

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.