From: Luca Balsanelli <lucabalsanelli@gmail.com>
To: Elijah Newren <newren@gmail.com>
Cc: git@vger.kernel.org
Subject: Re: Different behaviour for --find-renames between git diff and git merge?
Date: Mon, 15 Dec 2025 15:02:09 +0100 [thread overview]
Message-ID: <d7135cd2-e577-4f96-8142-cd9c7cd6995d@gmail.com> (raw)
In-Reply-To: <CABPp-BH80R4LJDRKQnPmh5Am_HAcCgxWiA8vRoN8LgLRUMz+JQ@mail.gmail.com>
On 13/12/25 02:57, Elijah Newren wrote:
> On Fri, Dec 12, 2025 at 10:06 AM Luca Balsanelli
> <lucabalsanelli@gmail.com> wrote:
>> Hi,
>>
>> I'm scratching my head to understand why on the following case `git
>> diff` and `git merge` give a different interpretation about a rename.
> I don't see any difference...
Sorry, my email was not clear. There is still something that is not
convincing me though. I will reformulate my question at the end, after I
reply 'inline' to all the (true) considerations. I consider myself
decently educated on git, but probably I still miss some understanding
of the merge procedure.
>> git switch master
>> touch aaa
>> git add aaa
>> git commit -m 'aaa'
>>
>> git switch -c branch
>> echo -en 'A\nB\nC\n' > aaa
>> git add aaa
>> git commit -m 'A\nB\nC\n > aaa'
>>
>> git switch master
>> echo -en 'A\nB\n' > aaa
>> mkdir dir
>> mv aaa dir/
>> git add aaa dir/
>> git commit -m 'A\nB\n > aaa -> dir/'
>>
>> The `|merge.renames` config variable is true. Changing `git diff
>> --find-renames=50%` (the default) or `git merge -s ort -X
>> find-renames=50%` ||to something lower does not change the following.
>> |
>>
>> `git diff` prints
> Actually, it doesn't; more on that below...
I forgot to specify that I was intending to diff the two heads, that is
`master` and `branch`. So it was
git switch master
git diff branch
>> diff --git a/aaa b/dir/aaa
>> similarity index 71%
> Did you not follow your own recipe? Maybe you inserted an extra space
> or left off the 'n' in 'echo -en' when you ran this? The number
> should have been 66%.
I don't know what I did but there were additional newlines. So, yes, the
similarity index is 66% (which is still above to the default 50% to
detect renames for both `git diff` and `git merge`).
>> rename from aaa
>> rename to dir/aaa
>> index bbd2b90..986ad36 100644
>> --- a/aaa
>> +++ b/dir/aaa
>> @@ -1,4 +1,3 @@
>> A
>> B
>> -C
>>
>> that is the similarity index is 71% and it detects the rename.
> At this point, if you actually run `git diff` you see the following:
>
> $ git diff
> $
>
> i.e. nothing. I suspect you gave `git diff` additional arguments but
> didn't tell us. Let's look at a few options:
>
> $ git diff master~1 master
> diff --git a/aaa b/aaa
> deleted file mode 100644
> index e69de29..0000000
> diff --git a/dir/aaa b/dir/aaa
> new file mode 100644
> index 0000000..35d242b
> --- /dev/null
> +++ b/dir/aaa
> @@ -0,0 +1,2 @@
> +A
> +B
> $
>
> So, on master, aaa was deleted, and dir/aaa was added.
>
> $ git diff master~1 branch
> diff --git a/aaa b/aaa
> index e69de29..b1e6722 100644
> --- a/aaa
> +++ b/aaa
> @@ -0,0 +1,3 @@
> +A
> +B
> +C
> $
>
> On branch, aaa was modified.
>
> $ git diff branch master
> diff --git a/aaa b/dir/aaa
> similarity index 66%
> rename from aaa
> rename to dir/aaa
> index b1e6722..35d242b 100644
> --- a/aaa
> +++ b/dir/aaa
> @@ -1,3 +1,2 @@
> A
> B
> -C
> $
>
> So, only if you diff the endpoints of the two branches do you see a
> rename; if you look from the merge base to either branch, there isn't
> one.
Yes, the above is all true. As I said above, I forgot to specify the
argument: `git switch master; git diff branch`.
>> `git merge branch`, instead, gives
>>
>> CONFLICT (modify/delete): aaa deleted in HEAD and modified in
>> branch. Version branch of aaa left in tree.
>> Automatic merge failed; fix conflicts and then commit the result
> Yes, this exactly matches what diff showed above -- on HEAD (master),
> 'aaa' was deleted, and on branch, 'aaa' was modified.
>
>> Why it is that? I always supposed that the rename detection was the same
>> for `git diff`, `git merge`. Reading the documentation I do not find any
>> hint why `git diff` and `git merge` are behaving differently.
> Hope that helps...
I would expect that `git merge branch` would detect a rename and the
conflict resolved automatically. The 'ort' strategy (the default one),
"can detect and handle merges involving renames." and the default
similarity threshold is the same for `git diff` and `git merge`. I
understand that the merge procedure involves finding a merge base, but
still the rename should be detected between the two heads.
I was reading commit `90d43b07687fdc51d1f2fc14948df538dc45584b` of the
git source code (which I found using `git log --grep '--rename-empty'`).
It says (among other things)
This patch lets callers specify whether or not they interested in
using empty files as rename sources and destinations. The default is
"yes", keeping the original behavior. It works by detecting the
empty-blob sha1 for rename sources and destinations.
It is related, but I don't think it is relevant to this specific case.
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`?
next prev parent reply other threads:[~2025-12-15 14:02 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-12 18:04 Different behaviour for --find-renames between git diff and git merge? Luca Balsanelli
2025-12-13 1:57 ` Elijah Newren
2025-12-15 14:02 ` Luca Balsanelli [this message]
2025-12-16 0:57 ` Elijah Newren
2025-12-16 13:15 ` Luca Balsanelli
2025-12-16 19:44 ` Elijah Newren
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=d7135cd2-e577-4f96-8142-cd9c7cd6995d@gmail.com \
--to=lucabalsanelli@gmail.com \
--cc=git@vger.kernel.org \
--cc=newren@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).