147

I moved a file using git mv. Now I would like to do a diff on the new file to compare it with the old file (with the old, now non-existent name).

How do I do this?

Randall
  • 2,859
  • 1
  • 21
  • 24
dr jerry
  • 9,768
  • 24
  • 79
  • 122
  • 6
    Soon (git 2.9, June 2016), a simple `git diff -- yourRenamedFile` will be enough. See [my answer below](http://stackoverflow.com/a/36435527/6309) – VonC Apr 05 '16 at 19:38
  • @VonC don't you still need to include both the old and new filenames? – TTT Feb 25 '22 at 18:25
  • @TTT Not when doing a diff a the tree or commit level (instead of the file itself) – VonC Feb 25 '22 at 18:36

6 Answers6

157

You need to use -M to let git autodetect the moved file when diffing. Using just git diff as knittl mentioned does not work for me.

So simply: git diff -M should do it.

The documentation for this switch is:

-M[<n>], --find-renames[=<n>]
       Detect renames. If n is specified, it is a threshold on the similarity index 
       (i.e. amount of addition/deletions compared to the file’s size). For example, 
       -M90% means git should consider a delete/add pair to be a rename if more than
       90% of the file hasn’t changed.
Zitrax
  • 19,036
  • 20
  • 88
  • 110
  • 8
    Lifesaver! My git diffs are so much better now. 1) Is it safe to always use this option? 2) Can I add this option as default behaviour to my `~/.gitconfig`? – kevinarpe Nov 15 '15 at 07:47
  • 8
    Note that rename detection works only when both old and new files appear in the collection of files processed by `git diff`. Running `git diff -M` on a single (renamed) file doesn't report a rename. – Leon Oct 25 '17 at 10:38
  • 1
    This doesn't work for me, but `git log --follow -- file_after_move.txt` works well. It shows the whole history, including before the move. Any ideas? I am running `git version 2.11.0.windows.1`. – bouvierr May 04 '18 at 19:30
  • 1
    The `-C` option for detecting copies is useful and similar. I used it with `-M` for looking at a diff where I had refactored one file into two (with neither name matching the original). – cp.engr Jul 19 '18 at 19:19
  • But... How to do difftool? e.g. vim? – Robin Hsu Mar 20 '23 at 23:22
106

In addition to what knittl wrote, you can always use:

git diff HEAD:./oldfilename newfilename

where HEAD:./oldfilename means oldfilename in the last commit (in HEAD), relative to current directory.

If you don't have new enough git, you would have to use instead:

git diff HEAD:path/to/oldfilename newfilename
Community
  • 1
  • 1
Jakub Narębski
  • 309,089
  • 65
  • 217
  • 230
  • 11
    Thanks for this. You can also specify a specific commit instead of head, i.e. `git diff 39fa7c77e85c51d43ea0cf30d33aec8721812e9e:./oldfilename newfilename` – Chris Bloom Feb 29 '12 at 19:00
  • 11
    In case it's unclear, you can also specify branch names or any other reference, such as: `git diff branch:old/filen.name newfilename` – jricher Sep 25 '13 at 15:29
  • The first form works for me, if you `cd` to the directory and do not add `--` before the `commit:path` pair. Git appears to be very picky with syntax here. – dhardy Nov 28 '16 at 14:48
  • 1
    @dhardy The `:` syntax is an object identifier, something Git-ish; after `--` Git expects filenames only. – Jakub Narębski Nov 29 '16 at 22:18
  • This syntax worked for me where -M just showed the entire file as having been changed - `git version 2.30.1 (Apple Git-130)`. It worked with or without the leading `./`. - Thanks. – Ed Randall Jun 23 '21 at 08:44
23

With git 2.9 (June 2016), you won't have to add -M anymore. git diff uses -M by default.

See commit 5404c11, commit 9501d19, commit a9276a6, commit f07fc9e, commit 62df1e6 (25 Feb 2016) by Matthieu Moy (moy).
(Merged by Junio C Hamano -- gitster -- in commit 5d2a30d, 03 Apr 2016)

diff: activate diff.renames by default

Rename detection is a very convenient feature, and new users shouldn't have to dig in the documentation to benefit from it.

Potential objections to activating rename detection are that it sometimes fail, and it is sometimes slow. But rename detection is already activated by default in several cases like "git status" and "git merge", so activating diff.renames does not fundamentally change the situation. When the rename detection fails, it now fails consistently between "git diff" and "git status".

This setting does not affect plumbing commands, hence well-written scripts will not be affected.

The new tests for this feature are here.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
4

For whatever reason using HEAD:./oldfilename (or absolute path) didn’t work for me, but HEAD:oldfilename did (thanks cmn):

git diff HEAD:oldfilename newfilename
git diff 2a80f45:oldfilename f65f3b3:newfilename

HTH

Oli Studholme
  • 2,600
  • 22
  • 16
2

git diff -M activates rename detection as others have said (and as @VonC pointed out, it is activated by default from git 2.9). But if you have a large changeset, inexact rename detection may still get turned off again. Git will display a warning like the following, which is easy to miss amidst the diff you are viewing:

warning: inexact rename detection was skipped due to too many files.
warning: you may want to set your diff.renameLimit variable to at least 450 and retry the command.

In that case, set the configuration option as suggested by git, for example

git config diff.renamelimit 450

and re-run your diff command.

mindriot
  • 5,413
  • 1
  • 25
  • 34
-6

simply run git diff without any arguments, or git diff -- newfilename. git is smart enough to compare the right files/contents (i.e. original content before rename with altered content after rename)

knittl
  • 246,190
  • 53
  • 318
  • 364
  • 2
    git is absolutely not smart enough in most cases. Simply `git mv`ing a single file and then comparing the staged state to another otherwise-identical branch will produce the "everything was deleted and recreated again" diff unless `-M` is used. – Reinderien May 12 '15 at 17:00