Git always detects renames "after the fact", by comparing the two trees in question (or one tree and the index, for cases that don't include git merge
itself). (Linus Torvalds considers this a feature; see this SO question for instance.)
In any case, git merge
will run git's internal diff with merge detection enabled and the default similarity-index of 50%, unless you configure it otherwise.1 Similarly, git diff
has some defaults which are also configurable. If you run git diff --find-renames -M50%
manually between your merge-base and the upstream, you're probably fine (but see footnote 1 about configuring).
If git does not detect the rename, you may need to adjust the rename detection thresholds and/or increase the number of files that git should consider. The first of these is the rename-threshold
value in the -X
options (rename-threshold
first appeared in git 1.7.4). See the documentation for details.
1You can set merge.renameLimit
to the number of files to consider in terms of rename detection. If you do not set it, the current default is 1000 files (but the default has changed over time). Also, if you do not set it, merge uses diff.renameLimit
, so you can set just the second of these, and have both diff and merge use both values.
The way file rename detection works is a bit complex, but simple enough to describe by example. Suppose that git is comparing commit 12345
with commit 67890
, and in 12345
there are files with pathnames A
, B/C
, and D
; but in 67890
there are pathnames B/gronk
, B/C
, and D
. This means path A
is gone but new path B/gronk
has appeared. Git will then remember such paths (up to the rename limit value), and will compare the contents of 12345:A
with the contents of 67890:B/gronk
. If the files are "sufficiently similar", git will declare that 12345:A
was renamed to 67890:B/gronk
.
I'm not sure precisely how git decides that a file is 50%, or 75%, or whatever, similar/different. I have seen that similarity index is based on "chunks" rather than lines (even though the usual diff output is line-oriented), though.