Check a Git Repository's Object Database with git-fsck-objects
If an old script calls git-fsck-objects instead of git fsck, it still works. This guide walks through a read-only check of the object database, tells unused history apart from real corruption, and shows a quicker connectivity check for when a full scan is too slow. On this machine, git-fsck-objects is provided by Git 2.43.0, package git-man version 1:2.43.0-1ubuntu7.3. Allow ten minutes for a normal repository, or longer with large packs.
The route
Jump straight to the step you need, or tick off Done means at the end.
The command does not need root when you own the repository. It reads Git metadata and only writes files if you explicitly ask for --lost-found. The examples below avoid that option and do not change commits, refs or working files.
1. Start in the repository you mean to inspect
Change into the working tree, or set GIT_DIR for a bare repository. Check the location before running any diagnostic command, especially if a shell script changed directory on you earlier:
$ cd /path/to/repository
$ git rev-parse --show-toplevel
/path/to/repository
$ git status --short
The last command should print nothing on a clean worktree, but a dirty worktree does not stop fsck from running. This check is about the object database, not uncommitted files, so do not confuse a repository's working directory with the objects that actually record its history.
Checkpoint
The path printed by git rev-parse is the repository you meant to examine. If it is wrong, stop and fix the directory before continuing.
2. Run the normal integrity check
git-fsck-objects is an alias for git fsck, and the latter is the clearer spelling for new scripts, while the older name stays useful when an existing tool already invokes it. Suppress terminal progress when capturing output:
$ git-fsck-objects --full --no-progress
$ printf 'exit status: %s\n' "$?"
exit status: 0
On a healthy repository, no diagnostic lines and status 0 is exactly what you want. --full covers the main object directory, packs and any configured alternate object pools. Full checking is the default in this Git release, but spelling it out makes the scope visible in a runbook.
The no-argument form uses the index, refs and reflogs as heads, so an object referenced only by a reflog counts as reachable. That is usually what you want during routine maintenance, since recently moved or deleted branch tips may still be recoverable through reflogs.
3. Read the useful diagnostics
Run the same check without hiding its output when you are actually investigating a report:
$ git fsck --full --no-progress
missing blob 0123456789abcdef0123456789abcdef01234567
error: object missing: 0123456789abcdef0123456789abcdef01234567
That object ID is an illustrative shape, not a prediction of what your own repository will show. A missing object is referenced but absent, and hash mismatch means the stored contents do not match the object's name, either is an integrity problem. Do not delete objects just to make the report disappear, find a known-good clone, backup or remote and restore the missing data through a recovery plan that fits that repository.
A dangling object exists but is not directly used, and a dangling commit can be an old branch tip that still holds valuable work. unreachable means an object is not reachable from the selected heads. Neither message alone proves corruption, and neither says deletion is safe.
4. Look for history hidden by reflogs
To search for commits that used to be referenced but now survive only in reflogs, exclude reflogs from the reachability roots:
$ git fsck --full --no-reflogs --unreachable --no-progress
unreachable commit 0123456789abcdef0123456789abcdef01234567
The object ID and the number of results will vary. Inspect a candidate before deciding whether it actually matters:
$ git show --stat --oneline 0123456789abcdef0123456789abcdef01234567
Use the complete object name copied straight from the fsck output. If the commit is worth keeping, create a new reference before reflog expiry closes your easy route back to it:
$ git branch recovered-work 0123456789abcdef0123456789abcdef01234567
$ git log -1 --oneline recovered-work
This changes repository state by creating a branch, so confirm the object first and pick a name that does not already exist. To undo just this example, remove the new branch after checking it is the one you created:
$ git branch -d recovered-work
Git may refuse -d if the branch is not merged, which is that refusal protecting the reference. Do not reach for -D instead unless you have deliberately reviewed the commit and accepted losing that branch name.
5. Use a faster connectivity-only check when it fits
For a large repository, check reachable commits and trees without reading blob contents at all:
$ git fsck --connectivity-only --no-dangling --no-progress
$ printf 'exit status: %s\n' "$?"
exit status: 0
This can be substantially quicker. It still checks that referenced blobs exist and can catch corruption in commits and trees, but it will not detect corruption inside blob contents themselves. It is a connectivity check, not a replacement for a full integrity scan when blob validation actually matters.
--no-dangling drops the default dangling-object report, saving work that is irrelevant when all you need is confirmation that reachable history is connected. Leave it off when orphaned history is part of what you are investigating.
6. Know the safe boundary
Routine fsck is diagnostic, it does not repair a corrupt object. The manual's --lost-found option writes dangling objects below .git/lost-found/, so treat it as a deliberate state-changing action and make sure you have disk space before using it. It is not a substitute for a backup or for restoring a verified object from another copy.
--strict adds checks for legacy file modes, such as a recorded group-writable bit. Older projects can contain objects that trigger this warning even when their history is otherwise perfectly usable. Use it when auditing new repositories, and actually investigate its output rather than applying a blanket ignore.
For automation, test the exit status and keep the diagnostics around. A zero status from a connectivity-only run does not certify blob contents. A non-zero status deserves a saved log and a recovery decision, not an automatic prune. No command in this guide needs sudo; if a repository is unreadable, fix its ownership or access through your normal administrative process rather than widening a script's privileges.
Done means
- You confirmed the path:
git rev-parse --show-toplevelmatched the repository you meant to check. - The check ran:
git-fsck-objects --full --no-progresscompleted and you recorded its exit status. - You can tell the difference: missing or mismatched objects are distinguished from dangling and unreachable history.
- Reflogs were deliberate:
--no-reflogswas used only when searching for history hidden by reflog roots. - Scope was understood:
--connectivity-onlywas not mistaken for blob validation. - Nothing was rushed: no objects were deleted and no recovery branch was created without reviewing the target first.