git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Elijah Newren <newren@gmail.com>
To: Yuri Kanivetsky <yuri.kanivetsky@gmail.com>
Cc: Git Mailing List <git@vger.kernel.org>
Subject: Re: Why `git am -3` apply patches that don't normally apply?
Date: Mon, 4 Jul 2022 12:23:49 -0700	[thread overview]
Message-ID: <CABPp-BEkEKQZR=1duxSS4AVv9u5tnPk5CaLCM_fQWPbAqfSMxw@mail.gmail.com> (raw)
In-Reply-To: <CAMhVC3Z92hBsK0FbE4E_LV1CSxjR1zmu+MO8=iwR02BKqnwgUA@mail.gmail.com>

On Sun, Jul 3, 2022 at 6:09 AM Yuri Kanivetsky
<yuri.kanivetsky@gmail.com> wrote:
>
> Hi,
>
> From what I can see w/o `-3` `git am` follows the `patch`'es behavior.
> And the `patch`'es behavior is if there are lines in a patch that
> doesn't match the lines in the source file, it fails. For example, a
> source file:
>
> 11
> 2
> 3
>
> A patch:
>
>  1
>  2
> -3
> +33
>
> But `git am -3` will apply such a patch.

Will apply the changes, but they might result in conflicts; it depends
on what you apply it to.

> That is, `patch` sees that
> the first line changed and that prevents it from applying the patch,
> but `git am -3` decides that it's okay. Why is that?

Because `git am -3` is doing a three-way merge, as requested, where it
is no longer using a patch with changes and a context region but
instead has three full files that it can three-way merge.  Let's dive
into your example to explain...

> A script that reproduces the issue:
>
>     set -eux
>
>     mkdir a
>     (cd a
>     git init
>     echo '1
>     2
>     3' > a
>     git add a
>     git commit -m 1,2,3
>     sed -Ei 's/3/33/' a
>     git add a
>     git commit -m '3 -> 33'
>     git format-patch -1 HEAD)

So you have a repository with two commits.  Also, format-patch puts
references to the before-and-after blob hashes of the file 'a' into
the diff.

>     mkdir b
>     (cd b
>     git init
>     echo '11
>     2
>     3' > a
>     git add a
>     git commit -m 11,2,3
>
>     git remote add a ../a
>     git fetch a

So 'b' is a repository with 3 commits; 1 that you added to it
directly, and 2 that you fetched into it from your other repository.

If you had not done the fetch from 'a' into 'b', attempting to "git am
-3" the patch you created earlier would fail.

>     cat a
>     cat ../a/0001-3-33.patch
>     git --no-pager log --oneline --graph --all
>     git am "$@" ../a/0001-3-33.patch  # try it w/ and w/o -3

As per the documentation of -3:

        When the patch does not apply cleanly, fall back on
        3-way merge if the patch records the identity of blobs
        it is supposed to apply to and we have those blobs
        available locally.

format-patch records the identity of the blobs, and your fetch made
sure your 'b' repository has them.  So, it knows the base version of
the file has the following complete contents
    1
    2
    3
and the version from the patch has the following complete contents
    1
    2
    33
The version in HEAD you are using in the three-way merge has the
following contents
    11
    2
    3
Note that here we are not dealing with limited context, but with the
full copies of the files.  Now, doing a three-way merge, we see that
the line with '2' is common in all three versions.  The first line was
changed from 1->11 on the HEAD side (and left alone on the other
side), and the last line was changed from 3->33 on the other side
(while being left alone on the HEAD side).  The three-way merge of
these is simply
    11
    2
    33

So `git am -3` succeeds without conflicts for this case.

  reply	other threads:[~2022-07-04 19:24 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-07-03 12:11 Why `git am -3` apply patches that don't normally apply? Yuri Kanivetsky
2022-07-04 19:23 ` Elijah Newren [this message]
2022-07-05 18:09   ` Junio C Hamano
2022-07-06  0:19     ` Yuri Kanivetsky

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CABPp-BEkEKQZR=1duxSS4AVv9u5tnPk5CaLCM_fQWPbAqfSMxw@mail.gmail.com' \
    --to=newren@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=yuri.kanivetsky@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).