DEV Community

Cover image for Git HEAD: It’s Not as Scary as It Sounds
Ugochukwu Nebolisa
Ugochukwu Nebolisa

Posted on

Git HEAD: It’s Not as Scary as It Sounds

Intro

Ever run a command and seen the message You are in 'detached HEAD' state? If you’re like me, your first instinct was probably to close the terminal and hope your computer didn't explode. But don't panic. HEAD is actually your best friend in Git.

What is Git HEAD

Simply put, HEAD is a pointer to your current location in your Git repository. Think of it as a "You Are Here" sticker on your project’s map.

More technically, HEAD is a reference that points to the current branch reference, which in turn points to the latest commit on that branch. When you make a new commit, Git updates your current branch to point to this new commit, and HEAD follows along.

You can see where HEAD is pointing at any time by running:

git log --oneline -1

Enter fullscreen mode Exit fullscreen mode

git oneline output

Or you can get the full details by running

cat .git/HEAD
Enter fullscreen mode Exit fullscreen mode

git/head output

In most cases, you will see something like ref: refs/heads/main, which means HEAD is pointing to the main branch (mine points to master). This is called a "symbolic reference" which means that HEAD points to a branch name, not directly to a commit.

How HEAD Moves When You Work

Understanding how HEAD moves is key to understanding Git itself. Let's look at the most common scenarios:

When You Make a Commit

When you create a new commit:

  1. Git creates a new commit object with your changes
  2. Git updates your current branch to point to this new commit
  3. HEAD (which points to your branch) automatically follows along

Remember our first commit?
git oneline output

We see that the HEAD was pointing to that very first commit. What if we add another one then run the same command git log --oneline -1

# Make a change and commit
git add .
git commit -m "new feature"

# We will see that HEAD has moved to that commit
git log --oneline -1
Enter fullscreen mode Exit fullscreen mode

git oneline output

We now see that HEAD points to the latest commit in our current branch.

What happens when we switch branches?

# Let's create and checkout a branch
git checkout -b feature-branch

# Verify which branch we are on
git branch

Enter fullscreen mode Exit fullscreen mode

Git branch output
We see that we are at our newly created branch. Let's now run cat .git/HEAD and see where our HEAD points to.

.git/HEAD output
Nice, we see that our head points to the current checkout branch.

HEAD, Working Directory, and Staging Area: What's the Difference?

HEAD represents your last committed state, the snapshot of your project as it was when you last committed (We've understood this one already).

The Working Directory is what you actually see in your file system right now. The files you are actively editing. Changes here are untracked by Git until you explicitly tell it about them.

The Staging Area (Index) is a middle ground. A "preparation zone" where you place changes that you intend to include in your next commit. When you run git add, you are moving changes from your working directory into the staging area.

Detached HEAD State

Have you seen this message before?
You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by switching back to a branch.

It's not as scary as it looks. Remember how we said HEAD normally points to a branch, which then points to a commit? In detached HEAD state, that middle step is skipped. HEAD points directly to a commit instead of a branch. So instead of HEAD to point to the branch the commit belongs to, it points directly to that commit instead of the branch.

How do you end up in a detached HEAD?
Simple, run the command

git checkout <commit ID/Hash>
Enter fullscreen mode Exit fullscreen mode

Detached HEAD

What happens when we run this command cat .git/HEAD again?

HEAD
We see that it return a commit hash instead of a branch name, meaning that our HEAD now points to the commit.

What can you do in a detached HEAD?

  1. You can simply make experimental changes and if you don't really need those changes, you can checkout to any available branches. Git will eventually garbage collect those commits and they will be lost. This is the only genuine risk of detached HEAD state.
  2. If you have made those experimental changes and you feel you would love to retain them, you can simply checkout a new branch from your current state git checkout -b <new-branch>.This "attaches" your detached HEAD commits to a real branch, so they won't be lost.
  3. What if you checkout to an available branch mistakenly? Does it mean that the changes you made in a detached HEAD is gone? Don't worry yet, Git keeps a log of everywhere HEAD has been. Run git reflog and we will get something like this:

git reflog

Find the commit hash of your lost work then run git checkout -b recovery-branch <commit-hash>

recovery

Wrapping Up

You now have a solid understanding of one of Git's most fundamental concepts. Before we finish, let's connect HEAD to a command you have probably seen or used before and now you will understand exactly why it works.

You may have seen this command suggested as a way to undo your last commit:

git reset HEAD~1
Enter fullscreen mode Exit fullscreen mode

Now that you understand HEAD, you know why this command works:

  • HEAD: your current commit (the one you just made)
  • ~1: "one commit before"
  • git reset HEAD~1: "move HEAD back one commit"

Git simply moves your branch pointer and HEAD along with it, back to the previous commit, effectively undoing your last commit while keeping your changes in the working directory.
The same logic applies to HEAD~2 (two commits back), HEAD~3, and so on. Once you see HEAD as a pointer you can do arithmetic on, a whole family of Git commands suddenly start to make sense.


Final Thoughts

Git HEAD is one of those concepts that quietly underpins almost everything you do in Git. Once you internalize that it is just a pointer,one that you can move, inspect, and reason about, commands that once felt daunting to understand suddenly becomes easy.

The next time you see a detached HEAD warning or reach for git reset, you will know exactly what's happening under the hood.

git commit -m "Happy commiting :)"

Top comments (0)