Recover from a bad pull, rebase, or reset
Sooner or later you will run a Git command, watch a wave of red text scroll by, and feel your stomach drop. The good news: almost every "I just lost my work" Git situation is recoverable. The recovery procedure is the same shape every time: stop typing destructive commands, find the lost tip with git reflog, anchor it to a branch, evaluate, then choose how to integrate.
The first move is always git reflog --date=relative -n 50. The output lists every move HEAD has made for 90 days, with timestamps. Find the entry that looks like the state you want — usually the one right before the destructive command. Each entry's hash is a real commit you can return to. Do not run more destructive commands until you have identified the rescue target.
Anchoring is next. git switch -c rescue HEAD@{N} creates a new branch pointing at the lost tip. From there, evaluate: is this exactly what was lost, or are some commits missing? Run git log rescue --oneline and confirm. Once you have a branch holding the lost work, the disaster is over — you can choose how to integrate. git reset --hard rescue on the original branch puts everything back. Or git cherry-pick specific lost commits onto current main. Or just keep the rescue branch as a parallel record while you continue.
Three common scenarios. Bad pull merge — accidental merge commit instead of the linear history you wanted. git reset --hard ORIG_HEAD rewinds to before the pull; you can then git pull --rebase for the linear version. Bad rebase — rebase produced a mess or has unresolvable conflicts mid-way. git rebase --abort rewinds to before the rebase. If you committed the bad rebase result, git reflog + git reset --hard HEAD@{N} recovers. Bad force-push — overwrote a teammate's work. Their reflog still has it; have them git push --force-with-lease from a state they hold, or recover via HEAD@{N} from your reflog if you saw their work pre-force-push.