How to recover a deleted commit or branch in Git?
In Git, almost nothing is permanently deleted. Even after reset --hard or deleting a branch, commits remain in reflog and can be recovered for 90 days.
git reflog — the main recovery tool. Reflog records every HEAD movement: commits, checkout, reset, pull. Run git reflog — you'll see a history with commit hashes and action descriptions. Find the hash of the commit before deletion. An entry like "a1b2c3d HEAD@{2}: reset: moving to HEAD~1" means that at HEAD@{3} was the commit you reset away.
Recovering a commit: git reset --hard <hash> moves the current branch to the specified commit. If you don't want to rewrite the current branch, create a new one: git branch recovered <hash>, then git checkout recovered.
Recovering a deleted branch: git reflog shows the last commit of the branch. Find an entry like "abc1234 branchname@{1}: commit: last commit". Run git branch branchname <hash> — the branch is restored with that commit as HEAD.
Recovering after git reset --hard: if you accidentally ran reset --hard and lost changes, git reflog shows the previous HEAD state. Find the hash before reset and run git reset --hard <hash>. Changes are back.
Recovering after force-push: if someone force-pushed and overwrote your commits in remote, the commits are still in your local reflog. Find the hash via git reflog, create a branch git branch backup <hash>, then git push origin backup. The commits are back in remote.
Recovering uncommitted changes: if you ran git stash drop and lost a stash, git fsck --no-reflog --unreachable shows dangling objects. Find the commit object with your stash changes: git fsck --no-reflog --unreachable | grep commit. Then git stash apply <hash> restores the stash.
Time limits: reflog keeps entries for 90 days for reachable commits and 30 days for unreachable. After that, Git removes objects via git gc. If more than 90 days have passed — recovery is impossible. So check reflog immediately after accidental deletion.
Prevention: before reset --hard or force-push, create a backup branch: git branch backup-$(date +%s). It takes a second and saves you from losing work.