Git Detached HEAD: How to Get Back to a Branch, Keep Your Commits
What “detached HEAD” means
Normally HEAD points at a branch name, and the branch points at a commit. In a detached HEAD state, HEAD points straight at a commit. You are not on any branch.
Git’s own glossary says the same thing: you checked out a commit that isn’t necessarily the tip of any branch. It is not an error. Git lets you look around, edit files and even commit. The only catch is that new commits have no branch name holding on to them.
How you ended up here
Checking out anything that is not a local branch detaches HEAD. According to the git-checkout manual, if the name is not a branch but is a valid commit, your HEAD becomes “detached”.
| What you ran | Why HEAD is detached |
|---|---|
| git checkout v2.0 | A tag points at a fixed commit, not a branch. |
| git checkout 36d587c | A commit hash is a commit, not a branch. |
| git checkout origin/main | A remote-tracking branch is not a local branch. |
| git checkout HEAD~3 or git checkout main^^ | You asked for an older commit by position. |
| git switch –detach or git checkout –detach | You asked for it on purpose. |
| A rebase that stopped on a conflict | Git replays your commits while HEAD is detached. git branch shows (no branch, rebasing topic). |
How to check whether you are detached
- git status starts with HEAD detached at v1.0 instead of On branch main. After you make commits it says HEAD detached from v1.0.
- git branch lists * (HEAD detached at v1.0) as the current line.
- git branch –show-current prints nothing at all. That makes it handy in scripts.
When you switch, Git also prints a long note that begins “You are in ‘detached HEAD’ state.” It repeats the two fixes below. If you find it noisy, git config advice.detachedHead false turns it off, according to the git-config manual.
Which fix do you need?
The right command depends on one question: did you make commits while detached, and do you want them?
| Your situation | What to run |
|---|---|
| You only looked around, no commits | git switch main (or git switch – to jump back to where you were) |
| You made commits and want to keep them | git switch -c my-new-branch |
| You made commits and want to throw them away | git switch main. Git warns you first, but the switch still happens. |
| You already switched away and want the commits back | git reflog, then git branch rescue <hash> |
| You are in the middle of a rebase | Resolve the conflict and continue, or run git rebase –abort |
Just looking around: go back
If you never committed, there is nothing to save. Switch to the branch you want:
git switch main
If you don’t remember the branch name, git switch – returns to the previous branch. It is the shortcut Git itself suggests in the detached HEAD note, as long as you haven’t switched around since.
You made commits and want to keep them
Give those commits a branch name while you are still detached:
git switch -c my-new-branch
This creates the branch at your current commit and moves HEAD onto it. You are no longer detached, and your commits are safe. The manual lists two more ways to attach a name: git branch foo creates the branch but leaves HEAD detached, and git tag foo creates a tag and also leaves HEAD detached.
If you want those commits on an existing branch like main, create the new branch first, switch to main, then merge the new branch into it.
You made commits and don’t want them
Just switch to a branch. In my test with Git 2.50.1, Git warned “you are leaving 2 commits behind, not connected to any of your branches”, listed both commits by hash, and then switched anyway. The warning ends with a command you can copy:
git branch <new-branch-name> e264e2e
That last line is useful even if you ignore the rest. Run it with a real name and you have your commits back.
You already switched away and lost them
The commits are not gone yet. git reflog lists where HEAD has been, newest first. This is the output from the same test:
| Entry | What it records |
|---|---|
| HEAD@{0}: checkout: moving from e264e2e… to main | The switch that left the commits behind |
| e264e2e HEAD@{1}: commit: e2 | Your last commit while detached |
| 284e642 HEAD@{2}: commit: e1 | Your first commit while detached |
| 36d587c HEAD@{3}: checkout: moving from main to v1.0 | The moment you detached |
Find the last commit you made (here e264e2e) and point a branch at it:
git branch rescue e264e2e
The manual also shows git reflog -2 HEAD to see just the last two places HEAD pointed to. Don’t wait too long. The git-checkout manual says commits that nothing refers to will eventually be deleted by Git’s garbage collection. For reflog entries that are no longer reachable, git-reflog says the default expiry is 30 days (gc.reflogExpireUnreachable). For reachable entries it is 90 days (gc.reflogExpire).
Push and pull errors while detached
Both commands need a branch to work with, so they stop. These are the messages I got with Git 2.50.1:
| Command | Message |
|---|---|
| git push | fatal: You are not currently on a branch. It suggests git push origin HEAD:<name-of-remote-branch>. |
| git pull | You are not currently on a branch. followed by a request to name a branch. |
The simplest fix is the one you already know. Run git switch -c my-new-branch, then git push -u origin my-new-branch. Pushing straight from HEAD works, but you end up with a remote branch and no local branch for it.
Commands that ask about the current branch, such as git branch –set-upstream-to, can’t work either. The glossary notes there is no real current branch to ask.
How to avoid detaching by accident
- To work on a remote branch, use its short name. git switch feature does not detach. If feature doesn’t exist locally but exists on exactly one remote, Git creates a local branch from it. git checkout origin/feature is the one that detaches.
- To inspect an old commit, use –detach on purpose. git switch –detach HEAD~3 says what you mean. If the experiment turns out well, git switch -c good-surprises keeps it, as the git-switch manual shows.
- Uncommitted changes come along. Switching does not require a clean working tree. Git only refuses when the switch would overwrite your local changes.
Old and new commands side by side
You will see both styles in answers online. The manual lists them together.
| Goal | git switch | git checkout |
|---|---|---|
| Go to a branch | git switch main | git checkout main |
| Create a branch and go to it | git switch -c foo | git checkout -b foo |
| Detach on purpose | git switch –detach v2.0 | git checkout –detach v2.0 |
| Go back to the previous branch | git switch – | git checkout – |