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

Re: Different behaviour for --find-renames between git diff and git merge?

From
LBLuca Balsanelli <lucabalsanelli@gmail.com>
Date
Dec 16, 2025, 13:15 UTC
Message-ID
<61700785-5421-4fa8-8277-c0837b09a737@gmail.com>
In-Reply-To
<CABPp-BH1qgQNHJzJZ05Ckru2PdYxRnWfQ3xVPrqGG5F56bX1aw@mail.gmail.com>
On 16/12/25 01:57, Elijah Newren wrote:
Show 54 quoted lines
>> Even though the `git diff master~1 master` doesn't detect the rename
>> (the content changed too much compared to the empty file or one was
>> empty (although it says it defaults to include empty files as rename
>> source or destinarion)), the rename should be detected between the two
>> heads, even when merging. I tried to read at 'git/diffcore-rename.c' but
>> I'm not very good at C and it would require me a great effort to fully
>> understand it.
>>
>> So, why `git merge branch` is not detecting the rename and not resolving
>> the conflict automatically? Does it use a different diff machinery
>> compared to `git diff`?
> Merging never diffs the endpoints, and shouldn't either.  It basically
> does two diffs, each from the merge-base to the end-point in question.
>
> If you only diffed the endpoints, and one side renamed file A->B, how
> do you differentiate between A->B and B->A?  In other words, you may
> know there was a rename, but you can't tell what it was renamed from
> and which filename should be the final one.  You can only tell if you
> look at the merge-base and determine that the file started out named
> as A, and thus that B should be the final name.
>
> If you only diffed the endpoints, and one side renamed file A->B,
> while the other side renamed A->C, you'd be misled into thinking this
> was a normal rename (you'd only see e.g. B->C) and be unaware of the
> conflict, which is problematic.
>
> If you only diffed the endpoints, and one side renamed file A->B,
> while the other side renamed C->B, by diffing the endpoints you can't
> even tell there's a rename; you simply have a file named B that was
> totally rewritten.  But it gets subtly worse in special cases that
> might really confuse end users: if they modified A or C on the sides
> of history that didn't rename those files, those changes would not be
> propagated and combined with the ultimate B, and they'd be left to
> pick up the pieces and try to combine things.
>
> Further, it's just semantically wrong to diff the endpoints because of
> the underlying concept of a 3-way merge: If you were merging D & E and
> simply diffed D & E to do so, you won't know whether differing lines
> were added or removed by recent commits.  For example, you might
> notice an "import" or "include" statement that one side has that the
> other doesn't.  But did one side add that import statement?  Or did
> the other side remove it?  You can't tell by looking at the endpoints;
> you have to compare the endpoints to the merge-base to find out which
> things were added or removed.  So, fundamentally, a 3-way merge thinks
> in terms of diffing the merge-base to the endpoints, not diffing the
> endpoints.
>
>
> So, in summary, no, merge does not use a different diff machinery.
> You are just diffing the wrong commits to see what it sees.  Combine
> that with the fact that you have a funny special case where both sides
> drastically change the file in a way where the new versions happen to
> be similar to each other while not similar to the original, causes the
> behavior you are seeing.
Thank you. I understand.

Moreover, deepening the rename topic actually made me forget something about the merge topic. In fact, even if the rename was detected in some way or even if I didn't rename one side at all, the `git merge branch` would still be unable to resolve the conflict automatically, since both were modified in different ways, even if in similar ways. But similarity is not enough. This confounded me.

In the following example, I start from an empty file and I modify it on one side of the history and move (rename) it on the other side. The rename between `branch` and the merge base is detected. So, can you tell me why in the following case the rename is not detected during the merge?

    git switch -c master root
    touch aaa
    git add aaa
    git commit -m 'aaa'
    git switch -c branch
    echo -ne 'A\nB\nC\n' > aaa
    git add aaa
    git commit -m 'A\nB\nC\n > aaa'
    git switch master
    mkdir dir
    mv aaa dir/
    git add aaa dir/
    git commit -m 'aaa -> dir/'
    git merge --no-edit branch
Sorry if I'm pedant and thank you in advance.
Previous: Elijah NewrenNext: Elijah Newren
Message 5 of 6 in “Different behaviour for --find-renames between git diff and git merge?”
  1. Luca BalsanelliDec 12, 2025
  2. Elijah NewrenDec 13, 2025
  3. Luca BalsanelliDec 15, 2025
  4. Elijah NewrenDec 16, 2025
  5. Luca BalsanelliDec 16, 2025
  6. Elijah NewrenDec 16, 2025

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.