git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Why `git am -3` apply patches that don't normally apply?
@ 2022-07-03 12:11 Yuri Kanivetsky
  2022-07-04 19:23 ` Elijah Newren
  0 siblings, 1 reply; 4+ messages in thread
From: Yuri Kanivetsky @ 2022-07-03 12:11 UTC (permalink / raw)
  To: git

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. 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?

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)

    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

    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
    git --no-pager log --oneline --graph --all)

A couple of links, just in case, which have more information and show
where it comes from:

https://stackoverflow.com/a/25847019/52499
https://gist.github.com/x-yuri/9907d5b9cbf29e84d510902a776741df
https://gist.github.com/x-yuri/57d08f6afb10a89856d6e6a62abe30d4

Regards,
Yuri

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Why `git am -3` apply patches that don't normally apply?
  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
  2022-07-05 18:09   ` Junio C Hamano
  0 siblings, 1 reply; 4+ messages in thread
From: Elijah Newren @ 2022-07-04 19:23 UTC (permalink / raw)
  To: Yuri Kanivetsky; +Cc: Git Mailing List

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.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Why `git am -3` apply patches that don't normally apply?
  2022-07-04 19:23 ` Elijah Newren
@ 2022-07-05 18:09   ` Junio C Hamano
  2022-07-06  0:19     ` Yuri Kanivetsky
  0 siblings, 1 reply; 4+ messages in thread
From: Junio C Hamano @ 2022-07-05 18:09 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Yuri Kanivetsky, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> 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.

I suspect that we would need to update this part, as the order of
"fall back" was swapped sometime in the recent past (and we have
fixed a few bugs that were introduced as fallouts).

Your description on how -3 works when it does the three-way based on
the concrete example was very clear and easy to understand, by the
way.

Thanks for writing it up.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Why `git am -3` apply patches that don't normally apply?
  2022-07-05 18:09   ` Junio C Hamano
@ 2022-07-06  0:19     ` Yuri Kanivetsky
  0 siblings, 0 replies; 4+ messages in thread
From: Yuri Kanivetsky @ 2022-07-06  0:19 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Elijah Newren, Git Mailing List

Yep, thanks for the detailed explanations. It let me improve my answer
on Stack Overflow:

https://stackoverflow.com/questions/25846189/git-am-error-patch-does-not-apply/72797965#72797965

Although... it'll unlikely receive a lot of views :( But whatever, it
can't be helped.

Regards,
Yuri

On Tue, Jul 5, 2022 at 9:09 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> Elijah Newren <newren@gmail.com> writes:
>
> > 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.
>
> I suspect that we would need to update this part, as the order of
> "fall back" was swapped sometime in the recent past (and we have
> fixed a few bugs that were introduced as fallouts).
>
> Your description on how -3 works when it does the three-way based on
> the concrete example was very clear and easy to understand, by the
> way.
>
> Thanks for writing it up.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2022-07-06  0:19 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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
2022-07-05 18:09   ` Junio C Hamano
2022-07-06  0:19     ` Yuri Kanivetsky

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).