Detached HEAD State
Detached HEAD mein kaam karo toh branch banao, nahi toh commits gayab ho jayengi.
HEAD is Git's way of knowing "where you are right now". It is a pointer.
Normally, HEAD points to a BRANCH NAME (like main or feature), and the branch points to a commit.
This is a two-level pointer: HEAD → branch → commit.
When you commit, Git updates the branch pointer to the new commit. HEAD follows because it points to the branch.
You can see where HEAD points: cat .git/HEAD shows "ref: refs/heads/main".
This two-level system is what makes branching work — HEAD follows whichever branch you are on.
# Normal HEAD: points to a branch
cat .git/HEAD
# ref: refs/heads/main
# The branch points to a commit
cat .git/refs/heads/main
# a1b2c3d4e5f6...
# Chain: HEAD → main → a1b2c3d
# When you commit:
git commit --allow-empty -m "new commit"
# Git creates new commit, updates main to point to it
# HEAD still points to main → main points to new commit
# This is the normal flow
# Verify
cat .git/refs/heads/main
# f6e5d4c3b2a1... (different hash — branch moved forward)Detached HEAD happens when HEAD points directly to a COMMIT HASH instead of a branch name.
Common causes: git checkout <hash>, git checkout v1.0 (tag), git rebase, git bisect.
Git explicitly warns you: "You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, but any commits you make will be abandoned if you switch to another branch."
You are not STUCK — you can freely explore, read code, and even make commits.
The key issue: if you make commits in detached HEAD and then switch away, those commits have no branch pointing to them.
# Enter detached HEAD by checking out a commit hash
git log --oneline
# c3d4e5f (HEAD -> main) third commit
# b2c3d4e second commit
# a1b2c3d first commit
git checkout b2c3d4e
# Note: switching to 'b2c3d4e'.
# You are in 'detached HEAD' state.
cat .git/HEAD
# b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1
# (raw hash, NOT "ref: refs/heads/main")
# Other ways to enter detached HEAD:
git checkout v1.0 # checking out a tag
git checkout HEAD~3 # checking out a relative ref
git rebase main # during rebase, HEAD is detached
git bisect start # during bisect, HEAD is detachedYou CAN make commits in detached HEAD. Git allows it. The commits are real objects stored in .git/objects/.
The problem: when you switch away (e.g., git checkout main), no branch points to those commits.
They become "unreachable" — not visible in git log, not on any branch.
Git warns you when you leave: "Warning: you left behind X commits."
These unreachable commits survive for ~90 days in the reflog, then get garbage collected.
If you want to KEEP the commits, you must create a branch before switching away.
# In detached HEAD state
git checkout HEAD~1
# Make some commits
echo "experimental feature" > new.js
git add . && git commit -m "experimental"
# d4e5f6g (HEAD, detached) experimental
echo "more work" >> new.js
git add . && git commit -m "more experimental"
# e5f6g7h (HEAD, detached) more experimental
# Switch back to main
git checkout main
# Warning: you left behind 2 commits
# (those commits are now unreachable!)
# They're NOT in git log
git log --oneline
# c3d4e5f (HEAD -> main) third commit
# b2c3d4e second commit
# a1b2c3d first commit
# (experimental commits are MISSING!)Method 1: Create a branch BEFORE switching away. git branch <name> or git checkout -b <name>.
Method 2: If you already switched away, use reflog to find the commits and create a branch.
Method 3: If reflog expired, use git fsck --lost-found to find dangling commits.
Best practice: if you accidentally commit in detached HEAD, create a branch IMMEDIATELY.
git switch - or git checkout - returns to your previous branch.
# Method 1: Create branch BEFORE leaving detached HEAD
git checkout HEAD~1
echo "work" > file.txt && git add . && git commit -m "my work"
# Save it!
git branch save-my-work # creates branch pointing here
# OR
git checkout -b save-my-work # create branch AND switch to it
# Now your commits are on a branch — safe!
# Method 2: Already left detached HEAD? Use reflog
git checkout main
# "Warning: you left behind 1 commit"
git reflog | head -5
# e5f6g7h HEAD@{1}: commit: my work ← there it is!
# d4e5f6g HEAD@{2}: checkout: moving from main to HEAD~1
# Create branch from the lost commit
git branch recovered e5f6g7h
# Or cherry-pick it onto your current branch
git cherry-pick e5f6g7h
# Method 3: Reflog expired? Find dangling commits
git fsck --lost-found
# dangling commit e5f6g7h...
git branch recovered e5f6g7h
git bisect uses detached HEAD to check out each commit for testing.
Checking out a tag: git checkout v1.0.0 puts you in detached HEAD so you can examine that release.
CI/CD systems often check out specific commit hashes, which creates detached HEAD.
Some Git operations (like git commit-tree) are designed to work in detached mode.
Best practice: use detached HEAD for READING code, not WRITING code. If you need to write, create a branch first.
# Use case 1: Inspect an old release
git checkout v1.0.0
# Detached HEAD at v1.0.0
# Read code, run tests, check behavior
# Don't commit — just explore
git checkout main # return to present
# Use case 2: git bisect (automated)
git bisect start
git bisect bad HEAD
git bisect good v1.0.0
# Git checks out middle commit (detached HEAD)
# You test, mark good/bad, Git checks out next commit
# When found: git bisect reset
# Use case 3: CI/CD checkout
# GitHub Actions often checks out a specific commit
# If CI needs to commit (e.g., auto-format), it must:
git checkout -b ci-format # attach HEAD to a branch
# Quick escape from detached HEAD:
git switch - # return to previous branch
git checkout - # same thing (older syntax)
git switch main # go to a specific branch
git checkout -b <branch-name> immediately. This creates a branch from your current position and attaches HEAD to it. Now your commits are on a branch and will not be lost when you switch away.Lo kar liya — Key Points:
- ✅ HEAD normally points to a branch name, which points to a commit — HEAD → branch → commit
- ✅ Detached HEAD occurs when HEAD points directly to a commit hash instead of a branch name
- ✅ Common causes: checking out a commit hash, checking out a tag, git rebase, git bisect
- ✅ Commits made in detached HEAD are real but become unreachable when you switch to a branch
- ✅ To save work from detached HEAD: create a branch with git branch
or git checkout -b - ✅ If you already switched away: use git reflog to find the lost commits and create a branch from them
- ✅ Detached HEAD is useful for exploring old versions — just don't make commits you want to keep without creating a branch
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login