Checking out a commit

Suppose we want to see the snapshot of the complete project at a certain point in time. We can checkout a specific commit, and Git will restore our project to that point in time.

git checkout commit_hash

When we run this, Git will throw a message saying that we are in 'detached HEAD' state.

Checking out a commit 1
Checking out a commit 2

Imagine the image to our left represents our repository. The way Git can keep track of things is by using pointers. If your background is not in software engineering, just think about pointers like...well...that...things that point to other things. An instruction a program needs (in this case Git) that tells him where he needs to go to find something. Each commit points to its previous commit.

All the commits that we've created so far are part of the master branch. Side note here: Git started calling this branch the main branch in mid-2020, but there are still lots (probably most) repositories that haven't been changed yet.


The way Git keeps track of the different branches is with pointers too. So, in this example, the master branch (i.e. the pointer that tells Git where the master branch is) is pointing at our last commit.

Checking out a commit 3
Checking out a commit 4

Because we can work in different branches, Git also needs to know in which branch we are working on. To do this, Git uses another pointer called HEAD.

This is why when we run, for example, git log --oneline the last commit (the first one shown) starts with (HEAD -> master). That's just Git's way of telling us that the master branch is pointing to our last commit and that we are currently (the HEAD) pointing to it.

Checking out a commit 5
Checking out a commit 6

So, long story short, what that 'detached HEAD' state message is telling us is that our HEAD is not attached to a branch anymore, but pointing to a specific commit.

You can see this in the image to the right. While master is at commit 8eec1d2, HEAD is at commit fa1b75e (the one we checked out to). Also, notice that Git Bash no longer says (master), but is instead displaying the commit hash.


Side note here. When inspecting the log while in a detached HEAD we need to add the --all option. Otherwise, Git will only show us the commits prior to the commit where our HEAD is at.

Checking out a commit 7
Checking out a commit 8

One very important consequence of this that we need to always keep in mind is that we shouldn't create new commits in this state. If we do so, that new commit will point to our old commit, and our HEAD will now point to the new commit.

But once we move our HEAD back to the master (or any other branch), this commit will not be reachable from any commit or pointer. It's a dead commit. Git checks for commits like this and deletes them. So all changes left there will be lost.

Checking out a commit 9
Checking out a commit 10

To take the HEAD back to the master we just run

git checkout master