I have a repository where a number of files have been renamed from .html to .php and further edited in a number of commits since my last pull. Using git diff
to shows all the html
contents removed and all the php
content added. Is there a neat way to have git diff
detect the renames (something like git log --follow
does), or directly compare different filenames across different commits (something like the solution in Git: How to diff two different files in different branches? , but for commits)?
You can run the git diff HEAD command to compare the both staged and unstaged changes with your last commit. You can also run the git diff <branch_name1> <branch_name2> command to compare the changes from the first branch with changes from the second branch. Order does matter when you're comparing branches.
To see the changes between two commits, you can use git diff ID1.. ID2 , where ID1 and ID2 identify the two commits you're interested in, and the connector .. is a pair of dots. For example, git diff abc123.. def456 shows the differences between the commits abc123 and def456 , while git diff HEAD~1..
The second command that you can use to compare branch differences is “log.” git log will show you all of the commit differences between the branches you specify, and, aside from the term diff being replaced with log, the syntax is exactly the same as the previous command.
You can always compare 2 files in 2 different commits:
git diff commit1:file1_path commit2:file2_path
As said previously, the format needed is:
$ git diff commit1:file1_path commit2:file2_path
But there are a couple gotchas:
XXX$ git diff file1_path commit2:file2_path
This will not work, even if file1_path is in HEAD
; if you want to specify a commit for one file you must specify it for both. This will attempt to interpret "commit2:file2_path" as a file path with the first directory it steps into being, e.g., HEAD^:foo/
. This will rarely exist so it generally gives an informative error message. (Note: @philh says that git diff commit1:file1_path file2_path
works fine, but I haven't confirmed that myself.)
file1_path
format: The paths given will be treated as relative to the repository's root. Absolute paths are not permitted, and relative paths must be explicit. For a concrete example; say your directory structure looks like the below, and your working directory is ~/repo/proj
:
~/repo .git proj tests foo bar.sh utils baz quux.sh
If you are trying to compare HEAD^:(...)/bar.sh
to HEAD:(...)/quux.sh
, the only permissible paths for bar.sh
are:
proj/tests/foo/bar.sh
./tests/foo/bar.sh
The explicit relative path with ./
works, but the more common implicit path tests/foo/bar.sh
will not work. That version will sometimes fail silently - I think this is based on the format used in the other arguments but I'm not sure. Absolute paths will also not work; ~/repo/proj/tests/foo/bar.sh
and /home/username/repo/proj/tests/foo/bar.sh
will fail. AFAICT that will never fail silently.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With