The 'fatal: bad object HEAD' error means Git can't resolve the commit HEAD points to, usually from corruption, interrupted operations, or cloud-synced .git folders. Recovery is normally via fetch or ref repair.
The "fatal: bad object HEAD" error means Git cannot find or read the commit object that HEAD is supposed to reference. In Git, HEAD is a special reference that points to the current commit (usually via a branch reference like refs/heads/main). When Git tries to resolve HEAD but finds that the underlying commit object is missing, corrupted, or unreadable, it reports this fatal error. Git stores all repository data as objects (commits, trees, blobs) in the .git/objects directory, with each object identified by a SHA-1 hash (newer Git supports SHA-256 repositories, but SHA-1 remains the default). HEAD typically contains either a symbolic reference (like "ref: refs/heads/main") or a direct commit hash. If the commit hash HEAD points to doesn't exist in the object database, or if the ref file is corrupted or empty, Git cannot determine the repository state and refuses to operate. This error is particularly alarming because it affects the core repository reference. Without a valid HEAD, most Git operations fail immediately. However, the error usually doesn't mean your committed history is lost — typically only Git's internal pointers need repair, and the underlying objects can be recovered from the remote, the reflog, or fsck.
First, check the extent of repository corruption:
# Check repository integrity
git fsck --full
# Check for unreachable objects that might help recovery
git fsck --unreachable --no-reflogsThis reports missing objects, dangling commits, and other integrity issues. Note the error messages — they guide your recovery approach. Also inspect what HEAD currently points to, since an empty or garbage value is a common cause:
cat .git/HEADA healthy HEAD looks like ref: refs/heads/main (or a 40-character SHA for a detached HEAD).
If you have a remote repository, fetching often resolves the issue by re-downloading missing objects:
# Fetch all branches from origin
git fetch origin
# Re-download objects even if Git thinks it already has them (Git 2.29+)
git fetch --refetch
# If the above fails, try fetching a specific branch
git fetch origin mainAfter fetching, try git status again. This is the safest fix and works in most cases where the corruption was caused by sync issues or interrupted operations, because it only adds objects without rewriting your local state.
Before changing anything, find the commit HEAD should point to. The reflog records recent HEAD positions:
# View recent HEAD positions (preferred — uses Git's own parser)
git reflog
# If git reflog itself fails, read the raw log
cat .git/logs/HEADEach line ends with a 40-character SHA. Identify the most recent commit you trust. Verify the object actually exists and is readable before relying on it:
git cat-file -t <commit-hash> # should print: commitIf this prints commit, the object is intact and you can repair the ref in the next step.
If a branch ref is empty or points to a missing object, repair it using Git's plumbing command rather than editing files by hand. git update-ref validates the hash and writes the ref atomically:
# Check what the branch ref currently holds
git rev-parse --verify refs/heads/main
# Point the branch at a known-good commit (validated, atomic)
git update-ref refs/heads/main <commit-hash>
# If HEAD itself is the problem, re-point it at the branch symbolically
git symbolic-ref HEAD refs/heads/mainPrefer git update-ref over echo <hash> > .git/refs/heads/main: the raw redirect skips validation, can write a malformed ref (trailing newline, wrong length, packed-ref conflicts), and silently makes corruption worse. Use the remote to find the correct hash if you are unsure:
git ls-remote origin mainOnce HEAD and the branch ref resolve correctly, your working tree may still be out of sync. To align it, prefer a non-destructive reset first:
# Move the branch pointer but KEEP your working changes
git reset --mixed <commit-hash>
git status # review what changedOnly if you are certain you have no uncommitted work to keep should you use a hard reset, which permanently discards all uncommitted changes in tracked files:
# DESTRUCTIVE: discards uncommitted changes — back them up first
git stash push -u # save anything uncommitted just in case
git reset --hard <commit-hash>Always inspect git status and stash or commit important changes before running git reset --hard.
If the problem is with the remote tracking HEAD (common after a default-branch rename such as master to main):
# Auto-detect and set the remote HEAD
git remote set-head origin --auto
# Clean up stale remote-tracking references
git remote prune originThis updates refs/remotes/origin/HEAD to match the remote's actual default branch.
If the .git directory is severely corrupted but you have a remote and want to preserve your working files:
# Back up the existing .git folder first — do not delete it
mv .git .git.backup
# Reinitialize and reconnect the remote
git init
git remote add origin <your-remote-url>
# Fetch all data and restore your branch
git fetch origin
git checkout mainThis keeps your working-directory files intact while replacing corrupted Git metadata. Afterward, check .git.backup for any uncommitted work (for example with git fsck --lost-found run against it) before deleting the backup.
As an alternative last resort, clone fresh and copy your working files across:
# Clone the repository to a new location
git clone <your-remote-url> repo-fresh
# Copy your current working files, excluding the corrupted .git
rsync -av --exclude='.git' ./ ../repo-fresh/
cd ../repo-fresh
git statusReview git status in the fresh clone to see which files differ, then commit the changes you want to keep. Keep the original corrupted directory until you have confirmed nothing was lost.
The git-repair tool (part of the git-annex project) can automate fsck-driven recovery:
# Install (Debian/Ubuntu)
sudo apt install git-repair
# Install (macOS)
brew install git-repair
# Run automated repair
git-repairgit-repair runs fsck and attempts various automated fixes, fetching from remotes where possible. It has a --force mode that proceeds even when data may be lost — avoid it unless you have first backed up the .git folder and exhausted the safer steps above.
### Understanding Git objects and HEAD
Git's object database stores four object types:
- Blobs: file contents
- Trees: directory structures
- Commits: snapshots with metadata and parent references
- Tags: named references to objects
HEAD lives in .git/HEAD and normally holds a symbolic reference like ref: refs/heads/main. The branch file (.git/refs/heads/main) then holds the commit's SHA-1 hash. Note that refs may also be stored in .git/packed-refs rather than as loose files, so editing loose ref files by hand can be unreliable — another reason to prefer git update-ref / git symbolic-ref. When any link in this chain is broken, you get "bad object HEAD".
### Preventing future corruption
Avoid syncing live .git folders with cloud services — they sync files mid-write and create conflicting copies, the single most common cause of this error. Use a Git host (GitHub, GitLab, Bitbucket) for synchronization instead of Dropbox/OneDrive/iCloud. If a repo must live inside a synced folder, exclude .git from sync.
Tune garbage collection to keep loose objects in check:
git config --global gc.auto 256
git config --global gc.autoPackLimit 50### Recovering uncommitted changes
If you had uncommitted work before corruption:
# Staged content still tracked in the index
git ls-files -s
# Saved stashes
git stash list
# Dangling blobs/commits recovered by fsck
git fsck --lost-found
ls .git/lost-found/### WSL and Windows-specific issues
When using Git in WSL against repositories on Windows drives (/mnt/c), filesystem translation and permission handling between NTFS and WSL2 can lead to corruption. Keep repositories on the native Linux filesystem (~/) and set line-ending handling explicitly:
git config --global core.autocrlf inputssh: Could not resolve hostname github.com: Name or service not known
How to fix 'ssh: Could not resolve hostname github.com: Name or service not known' in Git
error: insufficient permission for adding an object to repository database .git/objects
How to fix "insufficient permission for adding an object to repository database" in Git
fatal: could not create work tree dir 'repo': Permission denied
How to fix "could not create work tree dir: Permission denied" in Git
warning: refname 'feature' is ambiguous
How to fix 'warning: refname is ambiguous' in Git
Smudge error: Error downloading object: The requested URL returned error
How to fix Git LFS 'Smudge error: Error downloading object' error