I merge branch A to branch B:
git checkout A
git merge B
a conflict happens, in a file c.txt
. I resolve it by editing c.txt
file. Now, before approving the changes with git add c.txt
I would like to see them. I.e. to see the difference between c.txt
and branch A. How to do it?
If I simply use git diff c.txt
it shows much more than the changes I want. It seems to show both, changes from branch B and changes from branch A (comparing to their common original commit). I.e. result is different from git add c.txt; git diff --cached c.txt
.
What exactly does git diff c.txt
shows me when c.txt
is marked as in conflict?
TL;DR: you probably want git diff HEAD:c.txt c.txt
.
While the file is marked "conflicted", there are multiple "higher stage" entries for the file in Git's index. In fact, this is what it means for the file to be conflicted in the first place: a non-conflicted file is in "stage zero" in Git's index, and a conflicted file has stage 1, 2, and/or 3 entries (typically all three).
When the file is in this conflicted state, git diff
performs a combined diff on the file.
Using git add
on the file erases the higher-stage entries, leaving you with a single stage-zero (non-conflicted) file, which is why it stops showing up that way.
Now, before approving the changes with git add c.txt I would like to see them. I.e. to see the difference between c.txt and branch A. How to do it?
I don't normally bother with this (I just read the combined diff, or git add
the file and then can see what I want without anything fancier—remember, you can still access the other versions of the file; only the merge base version is hard-ish to find), but you can do this. You must pick out which two copies of c.txt
you want compared:
branch A
): that's A:c.txt
.HEAD
commit, one in the MERGE_HEAD
commit, three in Git's index, and one in your working tree. The tricky part is naming each of these, but we can use the gitrevisions syntax for most of this. As with A:c.txt
, HEAD:c.txt
and MERGE_HEAD:c.txt
work for selecting those versions; :1:c.txt
selects the merge base version; :2:c.txt
selects the --ours
version (copied from HEAD
so should match HEAD:c.txt
), and :3:c.txt
selects the --theirs
version (copied from MERGE_HEAD
).Thus, if you wanted, e.g., to see how HEAD:c.txt
differs from MERGE_HEAD:c.txt
, you can just run git diff HEAD:c.txt MERGE_HEAD:c.txt
(or git diff :2:c.txt :3:c.txt
).
That doesn't help with the one you probably care about the most, though. What about the copy of c.txt
in your working tree, as edited to produce the combined file? Fortunately, we can name that one with just the file name, c.txt
.
In some cases, this file name might resemble a branch name, tricking Git. If that's the case, make sure you remember that --
always tells Git: after this, everything is a file name, or at least, not an option and probably not a branch name. So if the file isn't named c.txt
but rather main
, and:
git diff HEAD:main main
does the wrong thing, use:
git diff HEAD:main -- main
(note that HEAD:main
isn't going to be mistaken for a branch name and the --
should go between these).
If you wanted to compare the in-tree c.txt
to the branch-A c.txt
, both:
git diff c.txt A:c.txt
and:
git diff A:c.txt c.txt
work. The order of the two arguments determines which file is the "before" or left-side one, and which one is the "after" or right-side one, which in turn determines which lines are deleted and which lines are added.
In most cases, if the diff you asked for is "backwards" from the order you meant, you can simply swap the arguments. But for:
git diff HEAD:main -- main
there is a problem: you can't swap these. Here, git diff -R
comes to the rescue: the -R
flag means swap the sides. So git diff -R HEAD:main -- main
does the trick: the main
file winds up on the left, and the HEAD:main
file winds up on the right.