m35
m35

Reputation: 146

How to make git properly diff a replaced file

When diffing two revisions, how can I make git properly follow a history where a file was replaced?

Here is an example. I create a file [commit], move it [commit], then create another file with the same name [commit].

echo "original" > test.txt
git add .
git commit -m "First commit"
mv test.txt test2.txt
git add --all .
git commit -m "Rename"
echo "replace" > test.txt
git add .
git commit -m "Replace"

When diffing between HEAD^^ and HEAD, how can I make git realize that test.txt is really a brand new file? The best command I could find was something like git diff -M100% -C100% HEAD^^ but that doesn't produce the results I am looking for.

git diff -M100% -C100% HEAD^^
diff --git a/test.txt b/test.txt
index 4b48dee..6e8b374 100644
--- a/test.txt
+++ b/test.txt
@@ -1 +1 @@
-original
+replace
diff --git a/test.txt b/test2.txt
similarity index 100%
copy from test.txt
copy to test2.txt

Is there a better command to get this expected output?

diff --git a/test.txt b/test.txt
index 4b48dee..6e8b374 100644
--- /dev/null
+++ b/test.txt
@@ -0,0 +1 @@
+replace
diff --git a/test.txt b/test2.txt
similarity index 100%
copy from test.txt
copy to test2.txt

Upvotes: 0

Views: 1377

Answers (1)

torek
torek

Reputation: 488183

Unfortunately, there isn't. Git always does heuristic rename detection and, at least currently, regardless of any ancestry path computable from the commit DAG, when you give git diff two commits it simply compares them directly. In this case it is comparing HEAD^^ vs HEAD and both have a test.txt and the second has a test2.txt, so its heuristics say that while test2.txt may or may not be a copy of some other file, test.txt is not renamed.

(When comparing HEAD^^ vs HEAD^, there is no test.txt in HEAD^, so its rename detection code will see if perhaps test2.txt matches the previous test.txt. Hence if it scanned through the ancestry path leading from HEAD^^ through HEAD^ to HEAD, its current heuristics would detect the rename. But it doesn't do that. Or, if Git had the option to do a computationally-expensive O(n2) comparison between all files, rather than just those that have no counterparts on either "side" of the diff, that could also discover the rename as well; but again, it doesn't.)

Upvotes: 1

Related Questions