git fsck: Checking Repository Integrity and Detecting Data Corruption
AI generated
git
HEAD
Git · Repository Maintenance
git fsck
checking repository integrity and catching data corruption early

Git is generally considered robust because every object is identified by a hash of its content, but an object database built on SHA hashes is not immune to failing disks, killed processes, or accidentally deleted files. The built in git fsck command scans exactly that object database for inconsistencies and surfaces problems before they turn into real, irreversible data loss. This article explains what fsck actually checks, how to read its most common error messages, and which steps repair a damaged repository.

8 min read Git Repository Maintenance

1. What git fsck actually checks

Every object in Git, whether blob, tree, commit, or tag, is identified by a hash of its content and stored in the object database under .git/objects. git fsck, short for file system check, reads these objects, recomputes their hash, and compares it to the filename the object is stored under. If the two diverge, that is a clear sign of corruption, because in an intact repository an object's content must exactly match its hash.

In addition, fsck checks the reference structure between objects: if a commit points at a tree that does not exist, or a tree entry references a missing blob, fsck reports that as a broken link. The command is strictly read only, it does not modify the repository, it only produces a diagnosis that can then be used to repair things in a targeted way.


# Basic integrity check
git fsck

# More thorough check including packed objects
git fsck --full

# Also report unreachable objects
git fsck --full --unreachable --dangling

2. Making sense of common error messages

fsck's output clearly distinguishes between real errors and mere informational notices. dangling commit means a commit exists that no branch, tag, or other reference points to anymore, usually the result of git reset --hard, a deleted branch, or an aborted rebase. Such commits are not broken, they are simply unreachable and get removed by the garbage collector after some time.

unreachable object describes the same situation for blobs and trees no longer referenced by any reachable commit. Considerably more serious is missing blob or missing tree, here an object is entirely absent even though another object references it, a clear sign of data loss. The most critical case is error: sha1 mismatch, meaning a stored object's content differs from what its filename implies, in other words genuine bit level corruption.

3. How corruption ends up in the object database in the first place

Sudden power loss or a hard process kill while Git is in the middle of writing objects into .git/objects is among the most common causes, especially on systems without a journaling filesystem or with failing SSDs. Equally risky is a full disk, when Git aborts partway through writing a pack file because there is no space left.

Manual intervention directly inside the .git directory, say a careless cleanup script moving or deleting individual object files, reliably produces inconsistencies too. On network drives or synced cloud folders that happen to hold a .git directory, a conflict between two processes writing at the same time can also corrupt individual object files, which is why Git repositories generally should never live inside automatically synced folders.

4. Important options in detail

Without extra parameters, fsck only checks loose objects, meaning ones not yet compressed into a pack file. The --full option includes packed objects in the check as well and should be set for any serious diagnostic run. --strict enables additional, stricter consistency rules, for example around correctly formatted tree entries, uncovering more subtle problems in the process.

--unreachable lists objects no branch or tag reaches anymore, while --dangling specifically shows objects with no incoming reference at all, often exactly the commits someone wants to recover after an accidental reset. With --lost-found, fsck additionally writes any dangling objects it finds into the .git/lost-found directory, making them easier to work with afterward.


# Stricter check, saving found dangling objects
git fsck --full --strict --lost-found

# Inspect a found dangling commit
git show <commit-hash>

# Rescue a found commit as a new branch
git branch recovered-state <commit-hash>

5. Repair strategies after a positive fsck finding

Plain dangling or unreachable objects usually need no action at all, they are a normal side effect of using Git and get cleaned up automatically sooner or later. Real missing or corrupt objects are a different matter: the first move is checking a backup or another clone of the same repository, because Git objects are content addressed, an identical object from another, intact repository can simply be copied back into .git/objects.

If no backup is available but a current remote exists, a fresh clone from there is often the most pragmatic path, since it transfers the entire object database new and guaranteed to be consistent. Only if the affected object existed exclusively on the local machine and nowhere else is it truly and permanently lost, one more reason to push important commits promptly.

6. The reflog as a built in safety net

Before reaching for fsck at all, it is worth checking the reflog for commits believed lost, since it locally logs where HEAD and every branch pointed over the past weeks. git reflog lists this history chronologically and surfaces commits that seemingly vanished through a reset, a deleted branch reference, or a failed rebase, but are actually still sitting in the database as dangling objects.

The reflog is purely local and by default gets pruned after 90 days for reachable entries and 30 days for unreachable ones, a narrow window compared to a real backup strategy, but perfectly sufficient for most accidental losses that get noticed within days or a few weeks.


# Search the local history of HEAD and branches
git reflog show HEAD

# Restore a lost state
git checkout -b restored HEAD@{5}

7. Automating integrity checks

For critical repositories, especially central bare repositories on a self hosted Git server, a regular, automated fsck run via a cron job pays off, combined with an alert whenever the output contains real errors instead of just harmless dangling notices. A simple script can distinguish the two cases by filtering specifically for lines containing missing, corrupt, or sha1 mismatch.

In larger infrastructures, such a check ideally complements an existing backup regime, since fsck detects problems but does not fix them automatically, actual recovery always needs an intact copy of the affected objects from somewhere.


#!/bin/bash
# Simple fsck check for cron jobs, only alerts on real errors
OUTPUT=$(git fsck --full 2>&1)
if echo "$OUTPUT" | grep -qE "missing|corrupt|sha1 mismatch"; then
  echo "Critical fsck finding in repository:" >&2
  echo "$OUTPUT" >&2
  exit 1
fi

8. Case study: a corrupted repository after a server crash

After an unexpected power outage on a build server, git status suddenly reported fatal: loose object is corrupt. An initial git fsck --full confirmed exactly one broken blob object, every other object checked out fine. Since the repository was pushed regularly to a central GitLab server, a simple git fetch followed by copying the corresponding object file from a fresh clone into the local .git/objects directory was enough to get the build server running again.

Had no remote been available, only a full re-clone from an intact backup would have helped. The incident once again showed that a locally isolated repository without a remote offers no recovery option in a real emergency, no matter how carefully commits were made.

9. Prevention: backups, bare mirrors, and regular checks

The most effective protection against data loss is not fsck itself, but consistently pushing to at least one remote repository, ideally complemented by a separate bare mirror on a second server. A bare repository without a working tree can easily be kept up to date via a cron job running git remote update, serving as an additional, independent copy of the entire object database.

On developer machines, regularly pushing feature branches is part of prevention too, since local, never pushed commits are the only ones that can actually be lost in a corruption incident. A monthly fsck run on central servers rounds out the strategy and surfaces creeping problems before they become a real incident.

Error type Meaning Typical cause Action
dangling commit Commit with no incoming reference Reset, deleted branch, rebase Usually harmless, rescue via branch if needed
unreachable object Blob/tree with no reachable path Amend, rebase, squash Harmless, cleaned up later by gc
missing blob/tree Referenced object entirely absent Deleted object file, transfer error Restore from backup or an intact clone
sha1 mismatch Content does not match its hash Bit corruption, failing hardware Replace object from remote/backup, check hardware

Mironsoft

Git workflows, branching strategies, and CI hooks

Chaotic Git history and unclear branching rules across the team?

We set up clean Git workflows, clarify branching strategies for the team, and automate quality checks via Git hooks and CI pipelines so the history stays traceable.

Workflow Audit

Review the existing branching strategy and merge practice for weak spots.

Hook Automation

Set up pre-commit and pre-push hooks for linting, tests, and commit conventions.

Team Training

Teach rebase, cherry-pick, and conflict resolution hands-on across the team.

10. Summary

git fsck at a Glance

Purpose

Checks whether stored objects match their hash and every reference resolves

Key option

git fsck --full also includes packed objects in the check

First stop

For seemingly lost commits, check git reflog first, not fsck directly

Prevention

Regular pushing and a separate bare mirror beat after the fact repair

11. FAQ: git fsck at a Glance

1What exactly does git fsck check?
git fsck recomputes the hash of every stored object and compares it to the filename it is stored under, and additionally checks that every reference between commits, trees, and blobs points to an object that actually exists.
2Is a dangling commit an error I need to fix?
No, a dangling commit is simply a commit with no incoming reference, usually caused by a reset or a deleted branch. It gets removed automatically by garbage collection after some time and does not represent corruption.
3What does the sha1 mismatch message mean?
This message indicates genuine bit level corruption: the actual content of a stored object no longer matches the hash it was stored under. It usually points to failing hardware or an interrupted write.
4Why should I use --full with git fsck?
Without --full, fsck only checks loose, not yet packed objects. A large share of objects in a well maintained repository sit in pack files, which only get included in the check with --full.
5Can git fsck automatically repair a corrupted repository?
No, fsck only produces a diagnosis. Actual repair requires an intact copy of the affected objects from a backup, a remote repository, or another clone.
6What is the difference between fsck and the reflog for troubleshooting?
The reflog logs where HEAD and branches pointed locally over time and helps with accidentally lost but technically intact commits. fsck, by contrast, checks the technical consistency of the object database and also finds genuine data corruption.
7How long do dangling objects stick around in a repository?
By default, git gc removes unreachable objects after 30 days and reflog entries for unreachable commits after roughly 30 days as well, reachable reflog entries after 90 days, exact values are configurable via gc.pruneExpire.
8Should I run git fsck regularly on an automated schedule?
For central, business critical bare repositories on a self hosted Git server, a regular automated fsck run makes sense, combined with an alert on real error messages rather than just harmless dangling notices.
9Can a synced cloud folder corrupt a Git repository?
Yes, if two processes write into the same .git directory at the same time, for example because it lives in a cloud sync folder active on two machines, individual object files can be written inconsistently. Git repositories should generally not live in such folders.
10What is the best protection against data loss from repository corruption?
Consistently and regularly pushing to at least one remote repository, ideally complemented by a separate bare mirror on a second server, protects more reliably than any after the fact repair with fsck.