When something seems lost, the first rule is to stop typing Git 1,932 commands that rewrite things: every gc, reset or checkout you add in a hurry makes the trail harder to read. Then work through the list:
Run git status. A rebase, merge, cherry-pick or bisect still in progress is undone with its own --abort (or git bisect reset), which restores the starting state exactly.
Make a safety copy of the whole repository directory, .git included, before trying anything clever.
Read git reflog for HEAD and git reflog <branch> for the branch concerned, and find the entry just before the accident.
Point a new branch at it (git branch rescue <entry>) and inspect it before moving the original branch.
Nothing in the reflog? Run git fsck --lost-found and look through the dangling commits and blobs.
Still missing? Check other copies: origin, a colleague's clone, a CI checkout, or the hosting service's record of force-pushes (GitHub).
| Accident | Recovery |
|---|---|
| Branch deleted | git branch <name> <tip printed by -D> or a HEAD@{n} entry |
| reset --hard too far | git reset --hard <branch>@{1} or ORIG_HEAD |
| Bad rebase or amend | git reset --hard <branch>@{1} |
| Stash dropped or popped | git fsck, then git stash apply <hash> |
| Uncommitted, never staged | Gone: check your editor's local history |
Git protects what it has seen: commit or stash before any risky command, and treat git reset --hard, git clean -f and git checkout -- . as the truly destructive ones.