Re: Different behaviour for --find-renames between git diff and git merge?
- From
Elijah Newren <newren@gmail.com>
- Date
- Dec 16, 2025, 19:44 UTC
- Message-ID
- <CABPp-BHTnP-3erFTJ23goreg=UJGWPwCwdN9LNKsVbB3Omjt9w@mail.gmail.com>
- In-Reply-To
- <61700785-5421-4fa8-8277-c0837b09a737@gmail.com>
Hi,
On Tue, Dec 16, 2025 at 5:15 AM Luca Balsanelli <lucabalsanelli@gmail.com> wrote:
>
[...]
Show 23 quoted lines
> 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
This is an interesting case where --[no-]rename-empty option applies (the same option you found a related commit for in a previous email in this thread):
$ git diff master~1 master
diff --git a/aaa b/dir/aaa similarity index 100% rename from aaa rename to dir/aaa $ git diff --no-rename-empty 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..e69de29 The merge machinery runs with the equivalent of --no-rename-empty: $ git -C ~/floss/git grep rename_empty merge-ort.c merge-ort.c: diff_opts.flags.rename_empty = 0; This comes from commit 4f7cb99ada26 (merge-recursive: don't detect renames of empty files, 2012-03-22), and the commit message there explains the rationale. (The name of the option and how it is set has changed since 2012, due to commit 0d1e0e7801bb (diff: make struct diff_flags members lowercase, 2017-10-31)). merge-ort copied that behavior from merge-recursive. So, although the merge machinery calls the same diff machinery that `git diff` uses, it does pass slightly different defaults. (There's a couple others too; I believe the differences include rename_empty, rename_limit, histogram vs myers, basename-guided similarity, and the possibility of cached renames in a sequence of commits being reapplied. Users are unlikely to see any of these typically, though you certainly did here.)