Quick Links

One of the regular error messages you're likely to encounter with Git is the warning that "you are in 'detached HEAD' state." You may have stumbled into this accidentally, but don't worry---it's a normal problem, and can easily be fixed once you understand what it means.

What Is The Git HEAD?

"HEAD" is simply an alias for your current working commit, much like your current directory on a command line. Whatever state your Git repository is in, HEAD always points to something, and new commits will be appended in front of the HEAD.

Usually, HEAD doesn't directly reference a single commit. It instead points at a branch, and indirectly references the latest commit in that branch. Whenever you "checkout" a new branch, Git switches the HEAD over to that branch. This allows you to make new commits that will be appended to the end of that branch.

However, you can also check out individual commits. What if you wanted to examine the repository at a specific point in time? That's one of the major upsides of Git, but it presents a slight problem with how Git structures things. Since new commits won't update a branch, any commits you make after moving the HEAD away will become detached from all the branch references, hence, "detached HEAD."

This can actually be fairly useful. Say you moved the HEAD back a few commits, and then made some experimental updates. You're basically making a new branch, which could get merged back into master later on.

You'll need to officially integrate it into the Git repo if you do decide to keep the changes, but as a tool for doing back-in-time modifications, having a detached HEAD isn't as scary as it sounds.

If You Got Here By Accident

It's very easy to end up here on accident, and be confused about the error message Git is complaining about despite having done nothing wrong. Luckily, it's incredibly easy to fix:

If you just checked out a commit, and haven't touched the repository otherwise (no new commits were made), you can simply move the HEAD back to where it belongs with

        git checkout
    

:

git checkout master

This is basically like running cd on Linux, except Git still associates cached commits and changes with the old HEAD, so you don't want to checkout if you have commits or changes that would be left hanging.

If you did have some changes, and want to just throw them away, you can hard reset back to master:

git reset --hard origin/master

git clean -d --force

If you want to save your commits though, you'll need to officially merge them back into Git's timeline.

If You Want To Save Your Changes

The first thing you'll want to do if you want to keep the changes you made while in a detached HEAD state is to make a new branch. This is because Git's garbage collector will clean up detached commits automatically, so you don't ever want to lose track of them.

git branch detached-branch

Then you can checkout this branch to move the HEAD so it is no longer detached, and instead pointed at this official new branch:

git checkout detached-branch

Once the changes are recorded, you have one of two options. This new branch is basically an ordinary feature branch, so you can either git merge or git rebase.

Merging is straightforward; checkout master, and merge the detached branch:

git checkout master

git merge detached-branch

This works well if you're integrating into a branch that needs approval, as is the case with pull requests and code reviews. You may need to go through your team's approval process rather than running these commands yourself.

If you do have access, like if you're merging back into a feature branch you're working on, a better method is to cherry pick the detached commits. Cherry picking basically copies a commit, and pastes it onto another branch. It's usually used for pulling out specific commits from a feature branch before the whole thing is ready, but in this case, cherry-picking can reconcile the detached branch without a merge.

In this example, the commit up above is detached. Rather than merging it, it's cherry-picked and moved onto the feature branch. This moves the HEAD and feature branch to point to the latest commit without a merge. Then, the original detached commit can be discarded.

First, you'll need to make the detached branch, and then checkout the feature branch to move the HEAD there:

git branch detached-branch

git checkout feature

Then run Git log to get a list of commits:

git log --pretty=format:"%h %s" --graph

Then you can cherry-pick a commit by its ID:

git cherry-pick 1da76d3

Then, once you've confirmed that the cherry-picked commits are applied properly, you can delete the detached branch, since the commits were copied and it is no longer used.

git branch -D detached-branch

Rebasing Instead of Merging

You could also do a rebase. Rebases are different from merges in that they rewrite the branch history, lifting up the detached commits and moving them to the front of the branch.

However, the problem with this is that you're still left with two branches, and you will still need to merge feature and detached-branch together, leaving you with a merge commit either way. But, it does leave the repository with a more linear Git history, which is preferable to running git merge if you have the authority to do so.