Git Under the Hood, Part 2: Referencing Commits

Amir Ebrahimi Fard
Data Management for Researchers
3 min readJul 26, 2021

--

**This article is inspired by [1]***

Photo by Ian Tuck on Unsplash

There are two approaches to reference commits in a Git tree: (i) absolute referencing, and (ii) relative referencing. With absolute referencing, different commits can be referenced via their unique identifiers (SHA-1 code, branch, or tag name). The other way of referring to commits is by relative referencing, which is defined relative to a baseline or starting point. The baseline could be any commit and is specified by a SHA-1 identifier, branch/tag name, or HEAD pointer. Multiple ways of working with both referencing approaches are shown in Figure 1.

Figure 1: Different ways of referencing commits in Git.

Among the relative referencing approaches, the “caret parent (^) and Tilda spec (~)” are the most widely used. These two symbols ^ and ~ enable movement within the Git tree. Placing the ~ symbol after HEAD means “move one step backward in the tree”. For example, HEAD~ refers to the parent commit of HEAD and HEAD~~ refers to the grandparent commit of HEAD. We can also specify a number (n) after the ~ to move to the nth ancestor of the commit (e.g., HEAD~1 is equivalent to HEAD~ or HEAD~2 is equivalent to HEAD~~). However, this can be problematic when there are multiple branches in the Git tree. For instance, when a commit is the result of merging multiple branches¹[2], how can we refer to each parent commit? To answer this, we first need to further refine the definition of ~. Although we can say that ~ refers to the parent commit, the more precise definition would be that it refers to the first parent commit. The first parent is on the branch you were on when you ran git merge, while the second parent is on the branch that was merged in, thus ~ always refers to the commit of the first parent. In order to visit other parents, we use the ^ symbol. If a commit has five parents (for example, five branches were merged), HEAD^ refers to the first parent, HEAD^^ refers to the second parent and so on and so forth. Similar to ~, instead of repeating the ^ symbol five times, we could use HEAD ^ 5.

These two symbols can also be combined to explore every possible commit in the Git tree. Figure 2 illustrates ways of using the combination of those two symbols in several examples. Please note that in this diagram only some of the possible combinations are demonstrated.

Figure 2: Relative referencing in a hypothetical Git tree.

Previously, HEAD was introduced as a pointer to the most recent commit. Although most of the time HEAD does that, sometimes we want to move the HEAD pointer to earlier commits using git checkout <commit_reference> to make changes or check information. This would lead to the detached HEAD state, meaning HEAD is not pointing to the most recent commit but some earlier commit. To exit the detached HEAD state, we use the git checkout master command.

Footnotes

  1. git merge can merge more than one commit (i.e., two or more) into the current branch

--

--

Amir Ebrahimi Fard
Data Management for Researchers

Postdoc Researcher on AI Explainability - Interested in the intersection of data, algorithm, and society.