What is HEAD in Git?

HEAD answers the question: Where am I right now in the repository? It is a pointer to the currently checked out branch or commit, which in turn contains an immutable snapshot of your entire code base at a given time.

What is HEAD in Git?
Photo by Fallon Michael / Unsplash

HEAD answers the question: Where am I right now in the repository? It is a pointer to the currently checked out branch or commit, which in turn contains an immutable snapshot of your entire code base at a given time. Whichever commit HEAD is referencing, directly (using the hash) or by reference (using a branch), it'll always be the commit on which any local changes are based.

Ok, but what does all of this even mean? In this post I'll explain the above statement in more detail using illustrations, showcasing how HEAD operates.

Attached & detached state

First of all, it's important to know that the HEAD pointer can be in either of two states: attached or detached. Default state is attached, where any manipulation to the history is automatically recorded to the branch HEAD is currently referencing. In detached state, experimental changes can be made without impacting any existing branch, as HEAD is referencing the underlying commit directly and is not "attached" to a particular branch.

Still confusing? Don't worry! Take a look at below illustration, showcasing the two states in a side-by-side comparison. Note that our history only contains two commits (C0 & C1), and one branch (master) with its remote counterpart (o/master).

History with HEAD in attached state on the left, and detached on the right. In attached state, C1 is referenced via the local master branch, and in detached – straight through its hash "14ko3".

On the left hand side, HEAD is in default attached state where any changes are automatically recorded to a branch; in this particular case the local master branch. On the right, HEAD is in the slightly more uncommon detached state, referencing the commit using its unique hash 14ko3 directly.

It's important to understand that regardless of how the underlying commit is referenced (directly or by reference), its content is automatically unpacked and mirrored to your local Working Tree (e.g. the files and folders on your computer) upon checkout. In the above example the local Working Tree would be identical in both cases; containing the snapshot of 14ko3.

Now that we know how HEAD can point to commits directly or by reference, let's see what happens if we manipulate the history by creating a new commit (C2) on top of C1. Again, with the two states side-by-side for easy comparison.

On the left, C2 committed in attached state with master branch automatically following. On the right, C2 committed in detached state leaving all other branches as is.

As you can see above, in both cases the new commit C2 got created through a commit operation. The main difference being that in attached state the change is automatically recorded in the master branch, whereas in detached state the change did not impact any existing branch and master remains referencing C1.

Similar things would have happened if a rollback operation would have been used, such as reset, but that's a case suitable for a coming blog post!

Now, let's look at how to know what HEAD is currently referencing.

What is HEAD referencing?

As already mentioned, most of the time your HEAD reference will be pointing to a branch, and hence be in attached state. Whenever a new commit is created on the branch, HEAD will automatically follow. But, in some cases and during some procedures you‘ll find yourself with HEAD in detached state, where it directly references a commit rather than a branch.

For example, every time you explicitly checkout a commit using its hash, or if you checkout a tag, HEAD will go into detached state. There are also other operations such as interactive rebase that might leave you with HEAD in detached state.

Whenever you want to know which state HEAD is currently in, and what it's referencing, the simplest way is to type $ git status in your terminal. Git will then let you know the status of your entire Working Tree including Index (Staging area), but also the state of HEAD.

Below is a short sequence showing how Git always tries to inform you of your current status of HEAD. In the example a commit is first checked out using its hash (t57lk), leaving HEAD in detached state.

$ git checkout t57lk
Switching to 't57lk', you are now in 'detached HEAD' state.

$ git status
HEAD detached at t57lk

Another easy way to inspect what HEAD is pointing to is using the command $ git show HEAD --oneline. It will tell you what HEAD is currently referencing, but also list all other branches that are also referencing the same commit; notice HEAD -> master within the parenthesis on the final line below, indicating that HEAD is pointing to master – hence, indirectly indicating that HEAD is in attached state.

$ git checkout master
Switched to branch 'master'

$ git show HEAD --oneline
t57lk (HEAD -> master, o/master) C2

You are in 'detached HEAD' state

A lot of git beginners believe the message You are in 'detached HEAD' state to be an error, when in reality, as we've just seen, it just describes the state your HEAD pointer is in. “Recovering” from a detached HEAD state is simple, just switch back to an existing branch or create a new one from where you’re currently at.

Explicitly inspecting the HEAD pointer (overkill)

If you ever want to explicitly see what HEAD is referencing you can always inspect the .git/HEAD file, which is the actual file git uses internally to manage HEAD. The file contains the name of the branch or commit hash depending on if HEAD is detached or not.

Explicitly inspecting HEAD is generally something you would never do, but for educational purposes it can be good to be aware of. In below example cat is used, but you can of course view the file using your regular text editor instead.

$ cat .git/HEAD
ref: refs/heads/master
Content of .git/HEAD file when in attached state, in this case referencing the master branch.
$ cat .git/HEAD
t57lk60b4b4aece5915caf5c68d12f560a9fe3e4
Content of .git/HEAD file when in detached state, in this case referencing a commit hash explicitly.

@ — the new HEAD alias

Since version 1.8.4 of Git, the @ symbol can be used interchangeably with HEAD, for convenience. For example, instead of typing $ git show HEAD --oneline, you can instead write $ git show @ --oneline.


Conclusion

So why is the concept of HEAD with its two states so important to understand?

Basically, with a good understanding of the HEAD pointer you're able to swiftly navigate the history of your repository and perform operations you see fit. Never again will you be lost in time, or misinterpret the information detached HEAD for an error!

Below is a short cheat sheet illustrating the HEAD concept, download it for your own reference. =)

Cheat sheet illustrating the HEAD concept, highlighting the two states: attached & detached.

To fully understand how HEAD works, it's important to also understand the relation between HEAD, Working Tree and Index (Staging area). A deep dive in this interrelation is under way and will be published in a coming post shortly!


Now that you know what HEAD is and how it operates, I hope you feel more confident in navigating the history of your repository.

Thanks for reading and good luck improving your source code management skills!

📫 If you'd like more pieces like this, make sure to sign up on the news feed so you don't miss anything!

☝️ Any questions or suggestions, try reaching me on Twitter – @Stjaertfena