6

I know I can find dozens of questions about the difference between HEAD^ and HEAD~

  • ~ specifies ancestors
  • ^ specifies parents

My question is about the difference of meaning of parents and ancestors. for me parent is the same as ancestor.

What is the logical difference between parent and ancestor?

What's the difference between HEAD^ and HEAD~ in Git? doesn't answer my question, my question is about the logical meaning of the two terms.

Melad Basilius
  • 3,847
  • 10
  • 44
  • 81
  • 2
    Possible duplicate of [What's the difference between HEAD^ and HEAD~ in Git?](https://stackoverflow.com/questions/2221658/whats-the-difference-between-head-and-head-in-git) – jonrsharpe Apr 10 '19 at 07:31
  • 1
    The answers on the duplicate *do* answer the question, describing what parents and ancestors mean. – jonrsharpe Apr 10 '19 at 07:33
  • Strictly speaking, `~` and `^` can be used to specify a commit itself. Both `HEAD~0` and `HEAD^0` are equal to `HEAD`. From a certain angle, we can say a commit is its own 0th parent or ancestor. Besides, if `foo` is an annotated tag that points at a commit. `foo^0` is the commit object while `foo` is the tag object. – ElpieKay Apr 10 '19 at 08:02

2 Answers2

9

The difference is a bit of a vertical vs horizontal matter.

In Git, commits are a type of linked list, each commit has a reference to a parent commit, or to multiple parent commits.

Accessing a parent, or a grand-parent, is done with ~:

  • ~ is the direct parent of a commit,
  • ~2 (or ~~) is the grand-parent
  • and so on

This is the vertical side, if you look at a log, using ~ will make you go down through the commits.

Now, when you merge two branches, it makes a merge commit. A merge commit, by definition, is merging two, or more, branches together. So the merge commit will have two or more parents.

From the merge commit, if you want to access different parents, you use ^ (it actually looks like a merge of two branches).

So consider this part of log:

*   39a2f899 (HEAD)
|\  
| * e2e7d241 (BRANCH)
| * caf13dc1
| * 609a9715
|/  
*   663e09ff

If you want to access the parent commit of BRANCH, you would do BRANCH~, or e2e7d241~, which would give caf13dc1. Now if you want to access the parent of HEAD, and do HEAD~, it will give you 663e09ff (the commit before the branch started).

But if you want to access the chain of commits of the merged branch, that's where ^ comes in the game, you would do HEAD^2, to say the "second parent of HEAD" (not the parent's parent).

You can of course combine them, in the same graph, HEAD^2~ is the parent (~) of the second parent (^2) of HEAD, which is caf13dc1

Incidentally, every commit has at least 1 parent, so commit^ is always the same as commit~. On the other hand, if a commit has a single parent (it is not a merge commit), commit^2 will return an error.

To sum up, you access different parents of a merge with ^ and you access generations of commits with ~.

It can be illustrated as follow with a more complex merge (of 4 branches merged at once):

----------> use ^ to go through the parents of the merge
|
|   *-----.   6af2936d
|   |\ \ \ \  
|   | | | | * 20d6fb23 BRANCH1
|   | | | * | e589d446 BRANCH2
|   | | | * | ec6088bd
|   | | | |/  
|   | | * | 38dcecfa BRANCH3
|   | | |/  
|   | * | 698c3daa BRANCH4
|   | |/  
|   |/  
|   *   2d97958e
|   |\  
|   | * 8989f1d3
|   | * d907cb7a
|   |/  
|   *   af368002
V
use ~ to go this way (through the ancestors)
padawin
  • 4,230
  • 15
  • 19
2

In short

"parents" means the direct parents only, i.e. the commits whose SHA-1 is explicitly stated in a given commit's definition.

"ancestors" refers to a commit's parents and their parents, recursively.

Romain Valeri
  • 19,645
  • 3
  • 36
  • 61