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

前端 未结 16 1837
醉酒成梦
醉酒成梦 2020-11-22 10:43

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

Both have a \"numbered\" version like HEAD^3<

相关标签:
16条回答
  • 2020-11-22 11:13

    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.

    0 讨论(0)
  • 2020-11-22 11:15

    ^ 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.

    0 讨论(0)
  • 2020-11-22 11:19

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

    HEAD^2 specifies the second head in a merge commit

    0 讨论(0)
  • 2020-11-22 11:21

    actual example of the difference between HEAD~ and HEAD^

    0 讨论(0)
  • 2020-11-22 11:22

    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...).

    0 讨论(0)
  • 2020-11-22 11:24

    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.

    0 讨论(0)
提交回复
热议问题