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

Re: Merge commit diff results are confusing and inconsistent

From
RDRobert Dailey <rcdailey.lists@gmail.com>
Date
May 7, 2019, 14:10 UTC
Message-ID
<CAHd499BkdpsA2BdB0Hsv3xXzpMyMzW8CSuYf2gQX0Jf7OoYBGw@mail.gmail.com>
In-Reply-To
<874l67i1ie.fsf@evledraar.gmail.com>
On Mon, May 6, 2019 at 6:52 PM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
Show 87 quoted lines
> Maybe an example helps, let's say you have two paint buckets, one with
> red paint, one with yellow paint. You mix them. What happens?
>
>     (
>         rm -rf /tmp/git &&
>         git init /tmp/git &&
>         cd /tmp/git &&
>         git checkout -b red &&
>
>         echo red >color.txt &&
>         git add color.txt &&
>         git commit -m"red" &&
>
>         git checkout --orphan green &&
>         git reset --hard &&
>         echo green >color.txt &&
>         git add color.txt &&
>         git commit -m"green" &&
>
>         git merge --allow-unrelated-histories red;
>         echo yellow >color.txt &&
>         git add color.txt &&
>         git commit -m"red + green = yellow"
>     )
>
> I *think* what you're alluding to is trying to discover some sort of
> change to whatever the default merge resolution would have been, which
> in this case would be closer to:
>
>     (echo green && echo red) >color.txt
>
> But it's important to understand that the whole business of suggesting
> how you should merge is just sugar that isn't in any way represented in
> the object model that makes it into the repository.
>
> In that model we just had one branch with "color.txt" containing "red",
> and another with "green". Then we merged the two together and that
> commit merged two histories together, did something to yield an end
> result, and now the "color.txt" file contains "yellow".
>
> But what single thing can you look at to describe how you ended up with
> "yellow"? There isn't such a single thing, I just know that I have a
> commit with two parents:
>
>     $ git cat-file -p HEAD
>     tree 6318a50d67e6de533498a4a0c9f46360cff6908a
>     parent 2332fc6b40c1cbf9f5daf809f09eb4defdd2ce30
>     parent 1707f13d2d236d61ac7496962ecebc50ffff5be3
>
> And that if I diff against the 1st parent we went from green to yellow:
>
>     $ git diff HEAD^1..HEAD
>     diff --git a/color.txt b/color.txt
>     index a5b73ed..d1ed081 100644
>     --- a/color.txt
>     +++ b/color.txt
>     @@ -1 +1 @@
>     -green
>     +yellow
>
> And the other from red to yellow:
>
>     $ git diff HEAD^2..HEAD
>     diff --git a/color.txt b/color.txt
>     index a9d1386..d1ed081 100644
>     --- a/color.txt
>     +++ b/color.txt
>     @@ -1 +1 @@
>     -red
>     +yellow
>
> To the extent that we can show a single diff at all that's diff-tree's
> --cc option:
>
>     $ git diff-tree --cc HEAD
>     e89ef1f780d7c979c18cc0f03fd74c560466ef03
>     diff --cc color.txt
>     index a5b73ed,a9d1386..d1ed081
>     --- a/color.txt
>     +++ b/color.txt
>     @@@ -1,1 -1,1 +1,1 @@@
>     - green
>      -red
>     ++yellow
>
> Sometimes it makes things better, sometimes it's just more
> confusing. It's what "git show" will use to render merge commits.
Your example is very helpful. I understand what you're saying for
conflicted lines. But the "whatever the default merge resolution would
have been" doesn't exist, because there's no reality where line 1 in
color.txt can be something "automatic" (i.e. deduced by git). The only
reality for the merge commit is some hand-edited replacement to line
1. So there is no "diff what I see with some alternate reality".

The majority use case I'm interested in is seeing net-positive changes that happen in merge commits. Normally I take for granted that merge commits have nothing meaningful in them (meaningful here defined as something unexpected for a merge commit). But what if someone makes a poor decision and does some crazy refactoring in 1 file and amends it into a merge commit? Let's also say that these changes are done to a file that wasn't modified in any parent (say a unrelated.txt next to your color.txt). Since neither parent cares about that file for the purposes of the merge, I am trying to make sense of a revision specification that can be used to see what they did to that file.

Even ignoring that issue, the more concerning observation of mine is that `diff @^!` produces any output at all. If you exclude both parents, why do I see a diff for parent 2 (I see the complete diff of the branch that was merged in)?

Again, thank you for your example, you definitely made things very clear for me. I see where the confusion is. And I think --cc is a good way to get more context. At this point I'm just concerned about the @^! behavior with merge commits & diff.

Previous: Ævar Arnfjörð BjarmasonNext: Robert Dailey
Message 6 of 12 in “Merge commit diff results are confusing and inconsistent”
  1. Robert DaileyMay 3, 2019
  2. Eckhard MaaßMay 3, 2019
  3. Robert DaileyMay 6, 2019
  4. Eckhard MaaßMay 6, 2019
  5. Ævar Arnfjörð BjarmasonMay 6, 2019
  6. Robert DaileyMay 7, 2019
  7. Robert DaileyMay 7, 2019
  8. Denton LiuMay 7, 2019
  9. Eckhard MaaßMay 7, 2019
  10. Ævar Arnfjörð BjarmasonMay 7, 2019
  11. Elijah NewrenMay 7, 2019
  12. Philip OakleyMay 11, 2019

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.