Why does the the ^!
reverse the diff for merge commit?
From Other ^ Parent Shorthand Notations
The
r1^!
notation includes commitr1
but excludes all of its parents. By itself, this notation denotes the single commitr1
.
This correctly shows me the diff for a non-merge commit.
$ git diff <commit>^!
But for a merge commit, the diff is reversed.
$ git diff <merge-commit>^!
I get similar results for difftool
.
Why so?
The short answer is that it is a bug.
You can see what git diff
effectively sees by using git rev-parse
. Here's the ^!
suffix applied to an ordinary commit:
$ git rev-parse 699d47e1d^!
699d47e1d2777ad1c2a867671e35daa821769f29
^4aaf5b0b21ac1fc294066593ac5243b3eaff897b
and here it is applied to a merge commit:
$ git rev-parse 117ddefdb^!
117ddefdb4dfd9b40ae60967a7327754d8ce7a87
^5e5a7cd9327cdbe6b50b5a0ead9b2ee5fb30789c
^699d47e1d2777ad1c2a867671e35daa821769f29
When you supply the compressed notation to git diff
, Git passes it through the same expansion code that git rev-parse
uses. Instead of printing it out, though, git diff
then tries to back-interpret the result. If there are two commit hashes (with various flags) it runs a diff between the two named commits. If there are three or more, it does something different.
Related (but not quite the same): What is the difference between `git diff topic1 topic2 ^master` and `git diff topic1..topic2 ^master`?