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.
DESCRIPTION. git merge-base finds best common ancestor(s) between two commits to use in a three-way merge. One common ancestor is better than another common ancestor if the latter is an ancestor of the former. A common ancestor that does not have any better common ancestor is a best common ancestor, i.e. a merge base.
Git "First Parent" meaning When you use the git merge command to merge a branch/commit into your current branch, it joins their development histories together in a new commit. This new commit records both as its parents; the branch/commit you're merging in and the branch you are on when the merge occurs.
When working with Git, only one branch can be checked out at a time - and this is what's called the "HEAD" branch. Often, this is also referred to as the "active" or "current" branch. Git makes note of this current branch in a file located inside the Git repository, in . git/HEAD .
"Commit-ish" are identifiers that ultimately lead to a commit object. For example, tag -> commit. "Tree-ish" are identifiers that ultimately lead to tree (i.e. directory) objects.
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-parentThis 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)
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With