How to Recover from a Corrupted Git Repository

Published: (March 29, 2026 at 05:20 PM EDT)
6 min read
Source: Dev.to

Source: Dev.to

1. What Actually Broke?

Git stores everything as objects in .git/objects/:

  • blobs – file contents
  • trees – directories
  • commits – snapshots
  • tags – references

Each object is named by its SHA‑1 hash and compressed with zlib.

Common causes of corruption

  • Disk failure or power loss interrupts a write to .git/objects/
  • A process is killed during git gc, git repack, or a push/pull
  • Filesystem bugs (especially on networked/shared drives)
  • Aggressive antivirus or backup software that locks or modifies files in .git/

Because Git’s storage is content‑addressable, an object that still matches its hash is intact. Corruption is usually isolated to a handful of objects.

2. Identify the Damage

Never panic‑delete anything. First, figure out exactly what’s broken.

Check overall repository integrity

git fsck --full --no-dangling

Typical output:

error: object file .git/objects/a1/b2c3... is empty
error: sha1 mismatch for .git/objects/d4/e5f6...
missing blob a1b2c3d4e5f6...
broken link from tree f7a8b9... to blob a1b2c3...

Write down the broken SHA‑1 hashes – you’ll need them later.

Verify HEAD

cat .git/HEAD          # should show: ref: refs/heads/main
cat .git/refs/heads/main
git cat-file -t $(cat .git/refs/heads/main)   # should output: commit

If HEAD or the branch ref is corrupted, that’s your starting point. Otherwise the problem lies deeper (blobs, trees, etc.).

3. Use the Reflog – Your Best Friend

The reflog records where branch pointers have been and survives most corruption because it’s stored separately from the object database.

# Show recent reflog entries for all refs
git reflog show --all

# If HEAD is broken, read the reflog directly
cat .git/logs/HEAD

Find the last known‑good commit hash and reset to it:

git reset --hard <commit‑hash>

The reflog keeps 90 days of history by default, so a recent corruption almost always has a valid commit hash you can recover.

4. Pull Missing Objects from a Remote

If you’ve ever pushed to a remote (GitHub, self‑hosted server, a colleague’s machine), you already have a backup.

# 1️⃣ Move the broken objects out of the way
mkdir -p .git/objects-broken
# Example for a broken object a1b2c3...
mv .git/objects/a1/b2c3d4e5f6* .git/objects-broken/

# 2️⃣ Fetch missing objects from the remote
git fetch origin

# 3️⃣ Verify again
git fsck --full --no-dangling

Because Git objects are immutable, the same commit on the remote has the exact same SHA‑1 and bytes. Fetching restores any missing objects.

5. Re‑create a Corrupted Blob (File)

If the corrupted object is a blob (a specific version of a file) and you still have the working‑tree version, you can rebuild it:

# Find which file the broken blob belongs to
git ls-tree -r HEAD | grep <blob‑sha>
# Example output:
# 100644 blob a1b2c3d4e5f6    path/to/file.js

# Re‑hash the current file into the object store
git hash-object -w path/to/file.js

Only works if the working‑tree file matches the broken blob. Otherwise fetch the correct version from a remote or backup.

6. Start Fresh from a Remote (When Damage Is Extensive)

If the repository is heavily damaged but you have a remote copy:

# Rename the broken repo
mv my-project my-project-broken

# Clone a fresh copy
git clone <remote‑url> my-project

# Copy over any uncommitted work
diff -rq my-project-broken/ my-project/ --exclude='.git'
# (Manually copy any files that differ)

You’re not losing anything that was pushed; the only risk is uncommitted local work, which the diff helps you locate.

7. Dealing with a Corrupted Packfile

Git periodically packs loose objects into .git/objects/pack/. A corrupted pack can hide hundreds of objects.

# Try to unpack what you can
git unpack-objects .pack

# Verify the packfile
git verify-pack -v .git/objects/pack/pack-*.idx

git unpack-objects will fail on corrupted objects but recover the intact ones. After extraction, fetch from a remote to fill the gaps.

8. Prevention – Make Corruption Rare

  1. Push frequently – every remote is a full backup. Push even messy feature branches; you can squash later.

  2. Never interrupt Git operations – let git gc, git repack, etc., finish. Killing them mid‑run is the #1 cause of corruption I’ve seen.

  3. Avoid shared/networked filesystems – NFS, CIFS, Dropbox, OneDrive, etc., are notorious for causing repo corruption. If you must use them, create portable backups with git bundle.

  4. Enable fsync for object files – protects against power loss:

    git config --global core.fsyncObjectFiles true
  5. Regularly run git fsck on important repos to catch problems early.

  6. Back up the .git directory (or the whole repo) to an external drive or cloud storage on a regular schedule.

TL;DR

  1. Run git fsck → note broken SHA‑1s.
  2. Check HEAD and branch refs.
  3. Use the reflog to locate a good commit and git reset --hard.
  4. If you have a remote, move broken objects aside, git fetch, and verify again.
  5. Re‑hash any recoverable blobs, or clone fresh and copy uncommitted work.
  6. For packfile issues, unpack what you can, verify, then fetch missing objects.

With these steps, most “fatal: bad object HEAD” scenarios are fully recoverable. Happy coding!

Git (2.36+) – More Granular core.fsync

git config core.fsync objects,derived-metadata,reference

Periodic Integrity Checks

  • Run git fsck regularly.
  • Add it to a cron job or a pre‑push hook.
  • Detecting corruption early gives you more recovery options.

Why Git’s Design Helps Recovery

  • The content‑addressable object store means every clone is a full backup.
  • Each object is self‑verifying.
  • Corruption is usually localized, not catastrophic.

A Real‑World Example

The worst Git corruption I ever dealt with took about 20 minutes to fix once I understood the object model. The first time, I spent three hours panicking before I learned any of this. Hopefully this saves you those three hours.

Want to Dive Deeper?

  • Read the Git Internals chapter in the official Git book.
  • Understanding how .git/objects/ works turns “my repo is corrupted” from a crisis into a 15‑minute fix.
0 views
Back to Blog

Related posts

Read more »

More on Version Control

Update Surprisingly and happily my last post on version controlhttps://bramcohen.com/p/manyana got picked up by Hacker News and received a lot of views. Thanks...

Spanish legislation as a Git repo

Legalize — España Legislación española como repositorio Git. Cada ley es un fichero Markdown, cada reforma un commit. Más de 8.600 leyes del API de datos abier...