How do I diff the same file between two different commits on the same branch?
Asked Answered
A

11

1455

In Git, how could I compare the same file between two different commits (not contiguous) on the same branch (master for example)?

I'm searching for a compare feature like the one in Visual SourceSafe (VSS) or Team Foundation Server (TFS).
Is it possible in Git?

Asclepiadean answered 26/7, 2010 at 19:10 Comment(1)
If you need to do this in GitHub - check thisMatchmaker
A
1825

From the git-diff manpage:

git diff [--options] <commit> <commit> [--] [<path>...]

For instance, to see the difference for a file "main.c" between now and two commits back, here are three equivalent commands:

$ git diff HEAD^^ HEAD main.c
$ git diff HEAD^^..HEAD -- main.c
$ git diff HEAD~2 HEAD -- main.c
Amphigory answered 26/7, 2010 at 19:13 Comment(14)
The .. isn't really necessary, though it'll work with it (except in fairly old versions, maybe). You can also use git log or gitk to find SHA1s to use, should the two commits be very far apart. gitk also has a "diff selected -> this" and "diff this -> selected" in its context menu.Trismus
Will this work even if the file name was modified between the 2 commits?Luigi
So what is the purpose of the "--"Isochroous
@Isochroous The -- is useful e.g. when you have a file named -p. Good to use in scripts, only in rare cases needed in practice.Distributary
Note: you need to use paths relative to the root of the repo. Paths relative to the current working directory will not work.Moriah
git diff master..HEAD -- $(find your_search_folder/ -name '*.c') for diffing all .c files inside a directory.Phospholipide
The HEAD^^^ syntax means "compare to 3 repo commits" ago, not 3 "file commits" ago. A way round this is to specify a date e.g. git diff -w @{2016-01-01} filename The -w means ignore whitespace changes.Vapory
Assuming we're working with a single branch: suppose you've made a commit and then modified file.c. How would you compare the current state of the file to the state of the same file in the previous commit? (I ask because the arguments to the command expect <commit> <commit> and not <current changes yet to be committed> <commit>)Marchellemarcher
To @KevinWheeler - I'm actually seeing the opposite in both ubuntu and windows git. The path must be relative to the current directory, not the depot root. Do you still see the same behavior?Borroff
Does not work for me. Always shows me zero changes, but the file has changes.Mathematical
If there is a folder structure change between the commits, then you need to use git diff commit_hash_1:folder/file.ext commit_hash_2:new_folder/file.extDaubery
The man page linked doesn't mention HEAD~2 or even ~. Also, why does diff HEAD~2 HEAD~1 or diff HEAD~3 HEAD~2 etc. return nothing??Supermarket
Paths are relative: the command git diff A B c from folder /git-clone/a/b will give same result as git diff A B a/b/c from folder /git-cloneRessler
Usually you're comparing head to a different branch, so git diff OTHER_COMMIT filename is shorterMoia
B
378

You can also compare two different files in two different revisions, like this:

git diff <revision_1>:<file_1> <revision_2>:<file_2>

Bemuse answered 27/7, 2010 at 12:18 Comment(5)
note that it looks like if <file_1> and <file_2> are in the current directory, not on the top level git managed directory, one has to prepend ./ on Unix: <revision_1>:./filename_1Crookes
<revision>: can be ommitted, so you can diff with a file which was not committed yet.Pamilapammi
Note that on Windows one has to use '/' for file paths, not '\'.Barrus
Is there a way to perform this diff such that one of the two files is local? I.e. when your difftool is opened, the file isn't a copy in a temp directory. In the same vein as the difference between git diff HEAD..HEAD~1 and git diff HEAD~1Clericalism
Useful if you've renamed or moved a file.Thaumatrope
C
112

If you have configured the "difftool" you can use

git difftool revision_1:file_1 revision_2:file_2

Example: Comparing a file from its last commit to its previous commit on the same branch: Assuming that if you are in your project root folder

$git difftool HEAD:src/main/java/com.xyz.test/MyApp.java HEAD^:src/main/java/com.xyz.test/MyApp.java

You should have the following entries in your ~/.gitconfig or in project/.git/config file. Install the p4merge.

[merge]
    tool = p4merge
    keepBackup = false
[diff]
    tool = p4merge
    keepBackup = false
[difftool "p4merge"]
    path = C:/Program Files (x86)/Perforce/p4merge.exe
[mergetool]
    keepBackup = false
[difftool]
    keepBackup = false
[mergetool "p4merge"]
    path = C:/Program Files (x86)/Perforce/p4merge.exe
    cmd = p4merge.exe \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"

Note: If you are using Intellij Enterprise or Community Edition - It has a good tool for doing 3 way merge when doing a merging/rebasing

For simple diff you can right click->Git->Compare with revision enter image description here

Select the revision you are interested in

enter image description here

Intellij will show the diff.

enter image description here

Collect answered 3/1, 2012 at 11:45 Comment(0)
G
82

Check $ git log, copy the SHA-1 ID of the two different commits, and run the git diff command with those IDs. for example:

$ git diff (sha-id-one) (sha-id-two)
Garlaand answered 19/4, 2012 at 0:14 Comment(3)
If you want the diff for a specific file, add the path to it at the end of the command.Jehias
Also do a "git pull" to download the full tree info if the two commits are across diffrerent branches. Otherwise you will get a "fatal: bad object" error.Knelt
git diff (sha-id-one) (sha-id-two) -- filename.ext without the filename it will list diffs of all files in those two commits.Minimal
T
44

If you want to see all changes to the file between the two commits on a commit-by-commit basis, you can also do

git log -u $start_commit..$end_commit -- path/to/file

Traitorous answered 26/7, 2010 at 20:50 Comment(2)
What is "$start_commit" and "$end_commit"? Are they literal, or if not, can you provide an example?Adlee
Those are shell variables that contain the start and end revision, which can instead be sha1 literals or refsTraitorous
M
23

Here is a Perl script that prints out Git diff commands for a given file as found in a Git log command.

E.g.

git log pom.xml | perl gldiff.pl 3 pom.xml

Yields:

git diff 5cc287:pom.xml e8e420:pom.xml
git diff 3aa914:pom.xml 7476e1:pom.xml
git diff 422bfd:pom.xml f92ad8:pom.xml

which could then be cut and pasted in a shell window session or piped to /bin/sh.

Notes:

  1. the number (3 in this case) specifies how many lines to print
  2. the file (pom.xml in this case) must agree in both places (you could wrap it in a shell function to provide the same file in both places) or put it in a binary directory as a shell script

Code:

# gldiff.pl
use strict;

my $max  = shift;
my $file = shift;

die "not a number" unless $max =~ m/\d+/;
die "not a file"   unless -f $file;

my $count;
my @lines;

while (<>) {
    chomp;
    next unless s/^commit\s+(.*)//;
    my $commit = $1;
    push @lines, sprintf "%s:%s", substr($commit,0,6),$file;
    if (@lines == 2) {
        printf "git diff %s %s\n", @lines;
        @lines = ();
    }
    last if ++$count >= $max *2;
}
Modesta answered 11/7, 2013 at 22:24 Comment(0)
C
16

If you have several files or directories and want to compare non continuous commits, you could do this:

Make a temporary branch ("revision" in this example)

git checkout -b revision

Rewind to the first commit target

git reset --hard <commit_target>

Cherry picking on those commit interested

git cherry-pick <commit_interested> ...

Apply diff

git diff <commit-target>^

When you done

git branch -D revision
Calvo answered 25/8, 2012 at 14:8 Comment(1)
Thanks for this solution. It worked well for my use case. The only thing i would update is that when your done you can't delete the branch until you switch off of it.Inaptitude
P
15

If you want to make a diff with more than one file, with the method specified by @mipadi:

E.g. diff between HEAD and your master, to find all .coffee files:

git diff master..HEAD -- `find your_search_folder/ -name '*.coffee'`

This will recursively search your your_search_folder/ for all .coffee files and make a diff between them and their master versions.

Phospholipide answered 30/11, 2012 at 15:4 Comment(0)
H
13

Just another way to use Git's awesomeness...

git difftool HEAD HEAD@{N} /PATH/FILE.ext
Haleakala answered 2/8, 2012 at 20:13 Comment(1)
I defined an alias from this answer that works with bash: difftool-file = "!git difftool HEAD@{\"$2\"} HEAD \"$1\" #"Appoint
P
12

All the other responses are more complete, so upvote them. This one is just to remember that you can avoid knowing the id of the recent commit. Usually, I set my self in the branch that I want to compare and run diff tools knowing the old commit uid (You can use other notations):

git checkout master
git difftool 6f8bba my/file/relative/path.py

Also, check this other response here to set the tool you want git open to compare the file: Configuring diff tool with .gitconfig And to learn more about difftool, go to the difftool doc

Patronizing answered 11/8, 2020 at 17:0 Comment(2)
Cannot you use HEAD as an alias for the most recent commit ID? HEAD^ for the one before that, and HEAD^^ for the one before that, etc? Or do I misunderstand?Minimal
^^ don't work. but check this git-scm.com/book/en/v2/Git-Tools-Revision-Selection under ancestor selection :)Delastre
L
5

If you want a simple visual comparison on Windows such as you can get in Visual SourceSafe or Team Foundation Server (TFS), try this:

  • right-click on the file in File Explorer
  • select 'Git History'

Note: After upgrading to Windows 10 I have lost the Git context menu options. However, you can achieve the same thing using 'gitk' or 'gitk filename' in a command window.

Once you call 'Git History', the Git GUI tool will start, with a history of the file in the top left pane. Select one of the versions you would like to compare. Then right-click on the second version and choose either

Diff this -> selected

or

Diff selected -> this

Colour-coded differences will appear in the lower left-hand pane.

Links answered 8/1, 2015 at 14:35 Comment(1)
Note to downvoters: this is a simple solution, easy to implement and addresses the OP's issue. It works on Windows which the OP is clearly using (see references to TFS and VSS in the question).Links

© 2022 - 2024 — McMap. All rights reserved.