Stop, breathe, do not push
The first rule of Git disasters: do not make it worse. Most "disasters" are recoverable because Git is conservative - it rarely deletes data, it just stops referencing it. The reflog and dangling objects are your friends.
Snapshot before recovery
Before attempting fixes, save the current state:
git tag panic-snapshot
cp -r .git ~/git-backup-$(date +%s)
You can always return to this point if recovery goes sideways.
Common disasters and fixes
Bad reset
git reflog
git reset --hard HEAD@{1}
Bad rebase
git reflog
git reset --hard ORIG_HEAD
# or the explicit reflog entry just before "rebase (start)"
Deleted branch
git reflog --all
git branch recovered <sha>
Force-pushed over a teammate
# On their machine, the branch still exists locally:
git push --force-with-lease <their-branch-tip>
# Their reflog also has the SHA
Committed secrets
If pushed: assume compromised, rotate immediately. Then rewrite history:
git filter-repo --replace-text passwords.txt
git push --force --all
git push --force --tags
Coordinate - everyone must reclone.
Detached HEAD with new commits
git checkout main
# "Warning: leaving detached HEAD..."
git branch rescued <sha>
Corrupt repo
git fsck --full
# If pack files are damaged:
git unpack-objects < .git/objects/pack/pack-XXX.pack
Or, simplest, reclone and copy your uncommitted changes across.
The reflog cheat sheet
git reflog # HEAD's history of moves
git reflog show feature/x # specific branch
git log -g # reflog as commit log
git fsck --lost-found # dangling commits
Avoiding repeats
- Use
--force-with-leaseinstead of--force. - Set
pull.ff = onlyto prevent accidental merges. - Configure long reflog expiry:
git config gc.reflogExpire 365.days. - Push feature branches as backups:
git push -u origin HEAD. - Run
gitleaksin pre-commit and CI to catch secrets early.
When recovery is impossible
If you reflog has expired and no remote has the commits, the work may be truly lost. Tools like extundelete or filesystem snapshots can sometimes recover deleted .git contents. After that, accept the loss, document what was lost, and rebuild.
Practising recovery
The best preparation is a deliberate disaster drill. Clone a throwaway repo, do a hard reset, and recover. Drop a stash, recover. Force-push and recover. Repeat until the fix patterns are reflexive. When real disaster strikes - and it will - you will recover in five minutes instead of an hour of panic.