LearnDevOpsHands-On Labs
Troubleshooting Matrix/You are in 'detached HEAD' state
GitHigh Severity

You are in 'detached HEAD' state

Fix detached HEAD: run git switch -c new-branch to keep your commits, or git switch main to leave. Covers recovering via reflog and why CI is detached.

Observed Error Signature / Log Pattern
You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard an

Incident Overview

Fix detached HEAD: run git switch -c new-branch to keep your commits, or git switch main to leave. Covers recovering via reflog and why CI is detached.

easy fix·5 min read

By Vishvesh Patel·DevOps Engineer·Updated 21 September 2026

BASHDiagnostic / remediation command
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.

Warning: you are leaving 1 commit behind, not connected to any of your branches

Do this first3 steps

Run these in order. Each one tells you what its output means before you change anything.

• Confirm you are detached and see where you are

"HEAD detached at <sha>" confirms it. Note the sha before doing anything else, because it is how you get back if you move away.

• If you made commits here, put them on a branch before leaving

This creates a branch at the current commit, so the work is no longer dangling. Do this before switching branches, or the commits become unreferenced.

• If you already left and lost them, find them in the reflog

Every position HEAD has held is recorded for about 90 days, including commits made while detached. Find the sha in the list and git branch rescue <sha> brings it back.

HEAD normally points at a branch, and the branch points at a commit. Detached means HEAD points straight at a commit, so there is no branch to advance. Commits made here belong to nothing, and switching away leaves them unreferenced.

It is not an error. It is a normal state that becomes a problem only if you commit and then leave.

BASHDiagnostic / remediation command
git status | head -3 && git log --oneline -1

How you get here

All three detach, because none of them is a local branch. origin/main catches people out: it is a pointer Git updates on fetch, not something you can commit to.

An interactive rebase also detaches while it replays commits, which is why git status looks alarming in the middle of one.

BASHDiagnostic / remediation command
git checkout a1b2c3d        # a commit
git checkout v1.4.2         # a tag
git checkout origin/main    # a remote-tracking ref

If you have made commits here

Give them a branch before you go anywhere:

Now they are referenced and safe. From there, merge or rebase as normal.

To confirm what you would be leaving:

BASHDiagnostic / remediation command
git switch -c rescue/my-work

If you already left

That is easy to scroll past. The reflog remembers anyway:

The reflog keeps unreachable entries for 90 days by default, and reachable ones indefinitely, so this works for anything recent. git config gc.reflogExpireUnreachable controls the window.

If the reflog does not have it:

That finds dangling commits directly in the object database. Slower, and it works when the reflog has been pruned.

BASHDiagnostic / remediation command
Warning: you are leaving 1 commit behind, not connected to any of your branches:
  a1b2c3d Fix the retry logic

Getting back without keeping anything

git switch - returns to the previous branch, like cd -.

BASHDiagnostic / remediation command
git switch -
git switch main

Why CI is always detached

Nearly every CI system checks out the exact commit that triggered the build, not a branch. That is deliberate: a branch could move between the trigger and the checkout, and the build must be of a specific, reproducible commit.

Which is why a pipeline that needs to push has to say where:

And why git describe --tags often fails there: actions/checkout and its equivalents default to a shallow clone with no tags.

fetch-depth: 0 is slower on a large repository, so only ask for it where you need history.

BASHDiagnostic / remediation command
git branch --show-current
# (empty)

Submodules are detached by design

The parent repository records an exact commit for each submodule, not a branch, so checking one out detaches. Committing inside a submodule without first switching to a branch is a common way to lose work.

The parent then records the new commit.

BASHDiagnostic / remediation command
cd vendor/lib
git status
# HEAD detached at a1b2c3d

Using it deliberately

Detached HEAD is the right tool for looking at history without disturbing anything:

git switch --detach is explicit about the intent, where git checkout is ambiguous between switching branches and moving to a commit. Since Git 2.23, switch and restore split those two jobs apart, and using them makes scripts clearer.

BASHDiagnostic / remediation command
git switch --detach v1.3.0
make test
git switch -

A checklist

Frequently Asked Questions

Is detached HEAD an error?

No, it is a normal state, and Git prints a long explanation rather than an error because of how often it confuses people. It simply means HEAD points directly at a commit instead of at a branch. Looking around, running tests and building at that commit are all perfectly safe. It becomes a problem only if you make commits and then switch away, because those commits have no branch pointing at them and become unreferenced.

How do I keep commits I made while detached?

Create a branch at your current position with git switch -c <name> before switching anywhere else. That gives the commits a reference and they behave like any other branch from then on. If you have already switched away, git reflog lists every position HEAD has held, including those commits; find the sha and run git branch <name> <sha>. Git's warning on leaving also prints the sha, which is worth reading rather than scrolling past.

How long do I have to recover lost commits?

The reflog keeps unreachable entries for 90 days by default, which covers almost every realistic case. After that git gc can prune them, though git fsck --lost-found may still find dangling objects in the repository until they are actually garbage collected. Both defaults are configurable through gc.reflogExpireUnreachable. Note the reflog is per clone and local, so it does not help if you deleted the whole repository directory.

Why is CI always in detached HEAD state?

Because CI checks out the exact commit that triggered the run rather than a branch, which guarantees the build is of a specific, reproducible tree. A branch could move between the webhook firing and the checkout completing, so building "the tip of main" would be ambiguous. The practical consequences are that git branch --show-current is empty, so pushes need git push origin HEAD:<branch>, and that the clone is usually shallow, so history-dependent commands need fetch-depth: 0.

Why is my submodule always detached?

Because the parent repository records a specific commit for each submodule rather than a branch, which is the whole point: it pins the dependency to an exact version. Checking out a submodule therefore lands on that commit with no branch. If you need to change something inside one, git switch to a branch first, commit and push there, then stage the submodule in the parent and commit that to record the new pointer. Committing inside a detached submodule is an easy way to lose work.

Reference and practice

Learn the underlying concept

Other Git errors

Free, comprehensive DevOps tutorials and learning roadmaps. Master Docker, Kubernetes, CI/CD, and more.

Get notified about new tutorials and features.

• Roadmaps

• Interview Prep

• Certifications

• Company

© 2026 DevOpsLesson. All rights reserved.

Need to practice this scenario?

Simulate this error condition and practice recovery commands safely in our in-browser terminal.

Open Git Sandbox