HEAD
HEAD is actually "the current commit". Think of it as "."
In simple case, you could think of the HEAD as the "current branch". When you switch branches with
git checkout
, the HEAD revision changes to point to the tip of the new branch.
You can see what HEAD points to by doing:
$ cat .git/HEAD
ref: refs/heads/master
However, it is possible for HEAD to refer to a specific revision that is not associated with a branch name. This situation is called a detached HEAD.
Therefore, HEAD could be the same as master, see (1)-(3), but if you check out another branch, well, it's not, see (4).
(1)
$ git checkout master
$ git log -1 --format="%H" HEAD
123abc
$ git log -1 --format="%H" origin/master
123abc
They are the same!
$ git diff origin/master
Of course their content is the same.
(2)
$ echo "foo" > foo
$ git add foo
$ git commit -m "Foo the thingy"
$ git log -1 --format="%H" HEAD
321bca
$ git log -1 --format="%H" origin/master
123abc
Now they're different!
(3)
$ git push origin master
$ git log -1 --format="%H" HEAD
321bca
$ git log -1 --format="%H" origin/master
321bca
And now we have pushed our latest commit and they both point to the same.
(4)
$ git checkout -b newbranch
$ echo "baz" > baz
$ git add baz
$ git commit -m "Baz the thingy with the stuff"
$ git branch -a
master
* new_branch
origin/master
$ git log -1 --format="%H"
789def
$ git log -1 --format="%H" master
321bca
git log -1 --format="%H" origin/master
321bca
git log -1 --format="%H" origin/new_branch
unknown revision or path not in the working tree.
Of course not. We haven't pushed new_branch to origin, it is only on our local machine
The "strange notation" (HEAD^ and HEAD~1) is simply a shorthand for specifying commits, without having to use a hash name like 3ebe3f6.
HEAD~ is short for HEAD~1 and means the commit's first parent. HEAD~2 means the commit's first parent's first parent. Think of HEAD~n as "n commits before HEAD" or "the nth generation ancestor of HEAD".
HEAD^ (or HEAD^1) also means the commit's first parent. HEAD^2 means the commit's second parent. Remember, a normal merge commit has two parents - the first parent is the merged-into commit, and the second parent is the commit that was merged. In general, merges can actually have arbitrarily many parents (octopus merges).
The ^ and ~ operators can be strung together