Recovering deleted work
A branch was deleted together with its reflog. Running fsck lists the dangling commits that still exist, so you can find the right one and point a new branch at it.
Git · Command
git fsck checks a repository's object database for integrity. It confirms that objects are valid and that everything they refer to is present, then reports corruption, missing objects and objects that nothing points to.
Last updated
fsck starts from a set of head objects and walks every commit, tree, tag and blob that can be reached from them. Unless you name objects, the heads are the index, every ref and every reflog. Along the way it checks each object's hash and format. It reports missing or bad objects, plus dangling ones: objects that exist but that no other object points to. By default it also checks the refs database. Message IDs such as missingEmail can be configured to change how severe a problem is treated, and a skip list can exempt known-bad objects. The fsck.* settings apply only to this command.
git fsck [--tags] [--root] [--unreachable] [--cache] [--no-reflogs] [--[no-]full] [--strict] [--verbose] [--lost-found] [--[no-]dangling] [--[no-]progress] [--connectivity-only] [--[no-]name-objects] [--[no-]references] [<object>…]| Name | Type | Description |
|---|---|---|
<object> | object name | An object to use as a head (starting point) for the reachability check. If none is given, fsck uses the index, all refs and all reflogs. |
--unreachable | flag | List objects that exist but cannot be reached from any of the heads. |
--[no-]dangling | flag | Show (default) or hide objects that exist but that no other object points to directly. |
--root | flag | Report root nodes. |
--tags | flag | Report tags. |
--cache | flag | Also use every object recorded in the index as a head. |
--no-reflogs | flag | Do not count commits as reachable if only a reflog entry refers to them. |
--[no-]full | flag | Also check alternate object stores and packfiles. This is on by default. |
--connectivity-only | flag | Check only that reachable objects are present. Blob contents are never read, which makes the check faster. |
--strict | flag | Use stricter checks, for example flagging file modes with the group-write bit set, which older versions of Git created. |
--verbose | flag | Print more detailed output. |
--lost-found | flag | Save dangling objects under .git/lost-found/commit/ or .git/lost-found/other/. |
#!/usr/bin/env bash
set -euo pipefail
repo=$(mktemp -d)
cd "$repo"
git init -q
git commit -q --allow-empty -m "first"
git commit -q --allow-empty -m "second"
# Drop "second" from the branch; only the reflog still refers to it
git reset -q --hard HEAD~1
# Ignore reflogs so the dropped commit is reported as dangling
git fsck --no-reflogs
# Save dangling objects under .git/lost-found
git fsck --no-reflogs --lost-found
ls .git/lost-found/commit/
# Fast health check without the dangling-object list
git fsck --connectivity-only --no-dangling && echo "connectivity OK"The script drops a commit from its branch, runs fsck with --no-reflogs so the commit shows up as dangling, saves it with --lost-found, and then runs a quick connectivity check.
A branch was deleted together with its reflog. Running fsck lists the dangling commits that still exist, so you can find the right one and point a new branch at it.
After a disk failure or a crash during a write, run git fsck --full --no-dangling to list only real problems, such as missing or broken objects.
An old repository has early commits with bad committer emails. List those object IDs in fsck.skipList, and set receive.fsck.skipList and fetch.fsck.skipList too, so fsck checks pass without hiding new problems of the same kind.
An unreachable object cannot be reached, directly or indirectly, from any head. A dangling object exists but no other object points to it directly. fsck lists dangling objects by default, while unreachable objects appear only with --unreachable.
Follow-up: Why can't fsck see a commit that only the reflog points to? Because reflogs are included in the default heads, so that commit counts as reachable. Pass --no-reflogs to have it reported.
Use --connectivity-only, which skips reading blobs and only checks that every referenced object exists. Add --no-dangling as well, so fsck doesn't have to walk unreachable history to find dangling tips. The cost is that corrupted blobs and format errors are not detected.
Follow-up: Does it still catch a missing blob? Yes. It confirms that referenced blobs exist; it just doesn't read their contents.
The best approach is to list the specific bad object IDs in fsck.skipList. Setting fsck.missingEmail=ignore would also let new commits with the same problem pass unnoticed.
Follow-up: Why do pushes to the server still fail after that change? Because receive.fsck.skipList doesn't fall back to fsck.skipList, so it has to be set on the server separately.
git gcgit prunegit refloggit refsgit commit-graphgit rev-parsegit configgit fsck-objects