Note: git 2.9 (June2016) will improve quite a bit the "buggy" nature of git log --follow
:
See commit ca4e3ca (30 Mar 2016) by SZEDER Gábor (szeder
).
(Merged by Junio C Hamano -- gitster
-- in commit 26effb8, 13 Apr 2016)
diffcore: fix iteration order of identical files during rename detection
If the two paths 'dir/A/file
' and 'dir/B/file
' have identical content
and the parent directory is renamed, e.g. 'git mv dir other-dir
', then
diffcore
reports the following exact renames:
renamed: dir/B/file -> other-dir/A/file
renamed: dir/A/file -> other-dir/B/file
(note the inversion here: B/file -> A/file
, and A/file -> B/file
)
While technically not wrong, this is confusing not only for the user,
but also for git commands that make decisions based on rename
information, e.g. 'git log --follow other-dir/A/file
' follows
'dir/B/file
' past the rename.
This behavior is a side effect of commit v2.0.0-rc4~8^2~14
(diffcore-rename.c
: simplify finding exact renames, 2013-11-14): the
hashmap storing sources returns entries from the same bucket, i.e.
sources matching the current destination, in LIFO order.
Thus the iteration first examines 'other-dir/A/file
' and 'dir/B/file
' and, upon finding identical content and basename, reports an exact rename.
With Git 2.31 (Q1 2021), the file-level rename detection has been improved for diffcore
.
See commit 350410f (29 Dec 2020), and commit 9db2ac5, commit b970b4e, commit ac14de1, commit 5c72261, commit 81c4bf0, commit ad8a1be, commit 00b8ccc, commit 26a66a6 (11 Dec 2020) by Elijah Newren (newren
).
(Merged by Junio C Hamano -- gitster
-- in commit a5ac31b, 25 Jan 2021)
Signed-off-by: Elijah Newren
register_rename_src()
simply references the passed pair inside rename_src
.
In contrast, add_rename_dst()
did something entirely different for rename_dst
.
Instead of copying the passed pair, it made a copy of the second diff_filespec
from the passed pair, referenced it, and then set the diff_rename_dst
.pair field to NULL
.
Later, when a pairing is found, record_rename_pair()
allocated a full diff_filepair
via diff_queue()
and pointed its src
and dst
fields at the appropriate diff_filespecs
.
This contrast between register_rename_src()
for the rename_src
data structure and add_rename_dst()
for the rename_dst
data structure is oddly inconsistent and requires more memory and work than necessary.
[...]
This patch accelerated the setup time by about 65%, and final write back to the output queue time by about 50%, resulting in an overall drop of 3.5% on the execution time of rebasing a few dozen patches.
git mv oldfile newfile
doesn't cause the rename to be recorded at all - it's just the same as deleting one file and adding another. git only works out renames and copies from the state of the tree at each commit after the fact. – Stepdaughter/bin/mv oldfile newfile
), but then dogit add newfile; git rm oldfile
, the result is indistinguishable from that ofgit mv oldfile newfile
. – Stepdaughtergit log --follow
improves a bit with git 2.9 (June 2016): see my answer below – Margarito--color-moved
when youdiff
. – Shadbush