[git] What's the difference between HEAD^ and HEAD~ in Git?

When I specify an ancestor commit object in Git, I'm confused between HEAD^ and HEAD~.

Both have a "numbered" version like HEAD^3 and HEAD~2.

They seem very similar or the same to me, but are there any differences between the tilde and the caret?

This question is related to git

The answer is


My two cents...

enter image description here


If you're wondering whether to type HEAD^ or HEAD~ in your command, just use either:

They're both names for the same commit - the first parent of the current commit.

Likewise with master~ and master^ - both names for the first parent of master.

In the same way as 2 + 2 and 2 x 2 are both 4 - they're different ways of getting there, but the answer is the same.

This answers the question: What's the difference between HEAD^ and HEAD~ in Git?

If you just did a merge (so your current commit has more than one parent), or you're still interested in how the caret and tilde work, see the other answers (which I won't duplicate here) for an in-depth explanation, as well as how to use them repeatedly (e.g.HEAD~~~), or with numbers (e.g.HEAD^2). Otherwise, I hope this answer saves you some time.


  • HEAD~ specifies the first parent on a "branch"

  • HEAD^ allows you to select a specific parent of the commit

An Example:

If you want to follow a side branch, you have to specify something like

master~209^2~15

HEAD^^^ is the same as HEAD~3, selecting the third commit before HEAD

HEAD^2 specifies the second head in a merge commit


~ this means parent.

^ if it has parents of two or more, like merge commit, we can select second of parent or another.

so if just one thing like (HEAD~ or HEAD^), it has same results.


It is worth noting that git also has a syntax for tracking "from-where-you-came"/"want-to-go-back-now" - for example, HEAD@{1} will reference the place from where you jumped to new commit location.

Basically HEAD@{} variables capture the history of HEAD movement, and you can decide to use a particular head by looking into reflogs of git using the command git reflog.

Example:

0aee51f HEAD@{0}: reset: moving to HEAD@{5}
290e035 HEAD@{1}: reset: moving to HEAD@{7}
0aee51f HEAD@{2}: reset: moving to HEAD@{3}
290e035 HEAD@{3}: reset: moving to HEAD@{3}
9e77426 HEAD@{4}: reset: moving to HEAD@{3}
290e035 HEAD@{5}: reset: moving to HEAD@{3}
0aee51f HEAD@{6}: reset: moving to HEAD@{3}
290e035 HEAD@{7}: reset: moving to HEAD@{3}
9e77426 HEAD@{8}: reset: moving to HEAD@{3}
290e035 HEAD@{9}: reset: moving to HEAD@{1}
0aee51f HEAD@{10}: reset: moving to HEAD@{4}
290e035 HEAD@{11}: reset: moving to HEAD^
9e77426 HEAD@{12}: reset: moving to HEAD^
eb48179 HEAD@{13}: reset: moving to HEAD~
f916d93 HEAD@{14}: reset: moving to HEAD~
0aee51f HEAD@{15}: reset: moving to HEAD@{5}
f19fd9b HEAD@{16}: reset: moving to HEAD~1
290e035 HEAD@{17}: reset: moving to HEAD~2
eb48179 HEAD@{18}: reset: moving to HEAD~2
0aee51f HEAD@{19}: reset: moving to HEAD@{5}
eb48179 HEAD@{20}: reset: moving to HEAD~2
0aee51f HEAD@{21}: reset: moving to HEAD@{1}
f916d93 HEAD@{22}: reset: moving to HEAD@{1}
0aee51f HEAD@{23}: reset: moving to HEAD@{1}
f916d93 HEAD@{24}: reset: moving to HEAD^
0aee51f HEAD@{25}: commit (amend): 3rd commmit
35a7332 HEAD@{26}: checkout: moving from temp2_new_br to temp2_new_br
35a7332 HEAD@{27}: commit (amend): 3rd commmit
72c0be8 HEAD@{28}: commit (amend): 3rd commmit

An example could be that I did local-commits a->b->c->d and then I went back discarding 2 commits to check my code - git reset HEAD~2 - and then after that I want to move my HEAD back to d - git reset HEAD@{1}.


Both ~ and ^ on their own refer to the parent of the commit (~~ and ^^ both refer to the grandparent commit, etc.) But they differ in meaning when they are used with numbers:

  • ~2 means up two levels in the hierarchy, via the first parent if a commit has more than one parent

  • ^2 means the second parent where a commit has more than one parent (i.e. because it's a merge)

These can be combined, so HEAD~2^3 means HEAD's grandparent commit's third parent commit.


actual example of the difference between HEAD~ and HEAD^

HEAD^ VS HEAD~


Here's a very good explanation taken verbatim from http://www.paulboxley.com/blog/2011/06/git-caret-and-tilde :

ref~ is shorthand for ref~1 and means the commit's first parent. ref~2 means the commit's first parent's first parent. ref~3 means the commit's first parent's first parent's first parent. And so on.

ref^ is shorthand for ref^1 and means the commit's first parent. But where the two differ is that ref^2 means the commit's second parent (remember, commits can have two parents when they are a merge).

The ^ and ~ operators can be combined.

enter image description here


TLDR

~ is what you want most of the time, it references past commits to the current branch

^ references parents (git-merge creates a 2nd parent or more)

A~ is always the same as A^
A~~ is always the same as A^^, and so on
A~2 is not the same as A^2 however,
because ~2 is shorthand for ~~
while ^2 is not shorthand for anything, it means the 2nd parent


Simply put, for the first level of parentage (ancestry, inheritance, lineage, etc.) HEAD^ and HEAD~ both point to the same commit, which is (located) one parent above the HEAD (commit).

Furthermore, HEAD^ = HEAD^1 = HEAD~ = HEAD~1. But HEAD^^ != HEAD^2 != HEAD~2. Yet HEAD^^ = HEAD~2. Read on.

Beyond the first level of parentage, things get trickier, especially if the working branch/master branch has had merges (from other branches). There is also the matter of syntax with the caret, HEAD^^ = HEAD~2 (they're equivalent) BUT HEAD^^ != HEAD^2 (they're two different things entirely).

Each/the caret refers to the HEAD's first parent, which is why carets stringed together are equivalent to tilde expressions, because they refer to the first parent's (first parent's) first parents, etc., etc. based strictly on the number on connected carets or on the number following the tilde (either way, they both mean the same thing), i.e. stay with the first parent and go up x generations.

HEAD~2 (or HEAD^^) refers to the commit that is two levels of ancestry up/above the current commit (the HEAD) in the hierarchy, meaning the HEAD's grandparent commit.

HEAD^2, on the other hand, refers NOT to the first parent's second parent's commit, but simply to the second parent's commit. That is because the caret means the parent of the commit, and the number following signifies which/what parent commit is referred to (the first parent, in the case when the caret is not followed by a number [because it is shorthand for the number being 1, meaning the first parent]). Unlike the caret, the number that follows afterwards does not imply another level of hierarchy upwards, but rather it implies how many levels sideways, into the hierarchy, one needs to go find the correct parent (commit). Unlike the number in a tilde expression, it is only one parent up in the hierarchy, regardless of the number (immediately) proceeding the caret. Instead of upward, the caret's trailing number counts sideways for parents across the hierarchy [at a level of parents upwards that is equivalent to the number of consecutive carets].

So HEAD^3 is equal to the third parent of the HEAD commit (NOT the great-grandparent, which is what HEAD^^^ AND HEAD~3 would be...).


The difference between HEAD^ and HEAD~ is well described by the illustration (by Jon Loeliger) found on http://www.kernel.org/pub/software/scm/git/docs/git-rev-parse.html.

This documentation can be a bit obscure to beginners so I've reproduced that illustration below:

G   H   I   J
 \ /     \ /
  D   E   F
   \  |  / \
    \ | /   |
     \|/    |
      B     C
       \   /
        \ /
         A
A =      = A^0
B = A^   = A^1     = A~1
C = A^2
D = A^^  = A^1^1   = A~2
E = B^2  = A^^2
F = B^3  = A^^3
G = A^^^ = A^1^1^1 = A~3
H = D^2  = B^^2    = A^^^2  = A~2^2
I = F^   = B^3^    = A^^3^
J = F^2  = B^3^2   = A^^3^2

^ BRANCH Selector
git checkout HEAD^2
Selects the 2nd branch of a (merge) commit by moving onto the selected branch (one step backwards on the commit-tree)

~ COMMIT Selector
git checkout HEAD~2
Moves 2 commits backwards on the default/selected branch


Defining both ~ and ^ relative refs as PARENT selectors is far the dominant definition published everywhere on the internet I have come across so far - including the official Git Book. Yes they are PARENT selectors, but the problem with this "explanation" is that it is completely against our goal: which is how to distinguish the two... :)

The other problem is when we are encouraged to use the ^ BRANCH selector for COMMIT selection (aka HEAD^ === HEAD~).
Again, yes, you can use it this way, but this is not its designed purpose. The ^ BRANCH selector's backwards move behaviour is a side effect not its purpose.

At merged commits only, can a number be assigned to the ^ BRANCH selector. Thus its full capacity can only be utilised where there is a need for selecting among branches. And the most straightforward way to express a selection in a fork is by stepping onto the selected path / branch - that's for the one step backwards on the commit-tree. It is a side effect only, not its main purpose.


Simplistically:

  • ~ specifies ancestors
  • ^ specifies parents

You can specify one or more branches when merging. Then a commit has two or more parents and then ^ is useful to indicate parents.

Suppose you are on branch A and you have two more branches: B and C.

On each branch the three last commits are:

  • A: A1, A2, A3
  • B: B1, B2, B3
  • C: C1, C3, C3

If now on branch A you execute the command:

git merge B C

then you are combining three branches together (here your merge commit has three parents)

and

~ indicates the n'th ancestor in the first branch, so

  • HEAD~ indicates A3
  • HEAD~2 indicates A2
  • HEAD~3 indicates A1

^ indicates the n'th parent, so

  • HEAD^ indicates A3
  • HEAD^2 indicates B3
  • HEAD^3 indicates C3

The next use of ~ or ^ next to each other is in the context of the commit designated by previous characters.

Notice 1:

  • HEAD~3 is always equal to: HEAD~~~ and to: HEAD^^^ (every indicates A1),

        and generally:

  • HEAD~n is always equal to: HEAD~...~ (n times ~) and to: HEAD^...^ (n times ^).

Notice 2:

  • HEAD^3 is not the same as HEAD^^^ (the first indicates C3 and the second indicates A1),

        and generally:

  • HEAD^1 is the same as HEAD^,
  • but for n > 1: HEAD^n is always not the same as HEAD^...^ (n times ~).

The ^<n> format allows you to select the nth parent of the commit (relevant in merges). The ~<n> format allows you to select the nth ancestor commit, always following the first parent. See git-rev-parse's documentation for some examples.