8

Looking through the source code for brackets-git (a git extension for Brackets), I see that ^! (caret bang) is being appended to the commit hash when calling git diff. See GitCli.js, line 754:

function getDiffOfFileFromCommit(hash, file) { return git(["diff", "--no-ext-diff", "--no-color", hash + "^!", "--", file]); } 

This translates to the following on the command line, using the file in question as an example:

$ git diff --no-ext-diff --no-color 1f9ea6e^! -- src/git/GitCli.js 

I know that ^ would refer to the parent of the commit. What does ^! do?

2
  • 4
    There's a good guide to all of the various ways of referring to commits in the docs for git rev-parse. Of interest in this case I believe: "r1^! includes commit r1 but excludes all of its parents." Commented Sep 3, 2014 at 18:57
  • From testing, the output seems identical to calling diff with the commit and all its parents as parameters. I don't know what git does when diffing multiple trees (from the code comments, it should be an error). Maybe it does some magic with the merge base of the parents? Commented Sep 3, 2014 at 19:59

1 Answer 1

8

commit^! is a range specifier which means: this commit, but none of its parents. It's equivalent to specifying: commit ^parent1 ^parent2 ^parentN.

For diff this does not make sense (you can only compare two trees) From testing the command seems to show the differences between the merge base of the parents and the last parent. I think git (mis)interprets the parameters similar to the range A...B which will show the differences between the merge-base A B and B (git diff parent1...parent2 will produce the same diff). Not sure what will happen in the case of an octopus-merge.

I might be wrong though, these are just assumptions I drew from testing with a repository and looking into the git code (builtin/diff.c).

Sign up to request clarification or add additional context in comments.

5 Comments

"The r1^@ notation means all parents of r1. r1^! includes commit r1 but excludes all of its parents."
@maartencls: yes, I know – see the first sentence of my answer. Ranges don't really make sense with git diff, since it only can work with endpoints. This range (commit but none of its parents) in particular is not guaranteed to have exactly two endpoints, so git gets confused
@maartencls Good to know. I always used gitrevisions. I hope the two pages are synced.
@knittl: for and ordinary non-merge commit A^! is A^..A, which for diff is equivalent to "A^ A".
@JakubNarębski, Thank you. Your comment is the correct answer.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.