Undo almost anything with git reflog
On this page
Good news first, because at this point you probably need some: almost nothing you have committed to git is ever truly lost. You ran git reset --hard, the two commits you meant to keep have vanished from git log, and your stomach dropped. They are not gone. Git keeps a private record of every position HEAD has held, and git reflog reads it straight back.
Git logs where HEAD has been
git log shows the history of your project. The reflog shows the history of you: every commit, reset, checkout, merge, and rebase that moved HEAD, newest first.
$ git reflog
b91e44d (HEAD -> main) HEAD@{0}: reset: moving to HEAD~2
8d04c2b HEAD@{1}: commit: Melt alerts when the freezer fails
3f2c1aa HEAD@{2}: commit: Track stock per pitch, not per van
b91e44d HEAD@{3}: pull: Fast-forwardRead it top down:
HEAD@{0}is where you are now: the hard reset that dropped two commits.HEAD@{1}is where you were a moment earlier, both commits still attached.
HEAD@{n} is the reflog's own coordinate: where HEAD pointed n moves ago, not n commits back.
That HEAD@{1} line is your way back.
Get the commits back
Point your branch at the commit from before the mistake, by its SHA or its HEAD@{1} coordinate:
$ git reset --hard 8d04c2b HEAD is now at 8d04c2b Melt alerts when the freezer fails
One thing to be careful of here: --hard rewrites your working tree to match that commit exactly, so it throws away any uncommitted changes along with the bad reset. If you have edits you would miss, commit or git stash them first.
If that feels too sharp, there is a gentler move. Park the lost commits on a new branch and leave the one you are on untouched:
$ git branch fix-whoopsie 8d04c2b
git branch <name> <commit> creates a branch at that commit and changes nothing else. Have a look at fix-whoopsie, and once you are happy it holds what you wanted, reset or merge onto it.
The branch you deleted
Deleting a branch removes the label, not the commits under it. Git prints the SHA as you delete it:
$ git branch -D melt-alerts Deleted branch melt-alerts (was 8d04c2b). $ git branch melt-alerts 8d04c2b
git branch melt-alerts 8d04c2b puts the branch back at that exact commit. And if the SHA has already scrolled off your screen, it is still sitting in git reflog, on the last line where you committed to that branch.
Why nothing was really lost
Git is a straight-up hoarder. It almost never deletes a commit you have made, it just stops pointing at it. The reflog is the list of everything HEAD used to point at, which is why a "lost" commit is usually not that big of a deal.
Two caveats, though:
- The reflog is yours alone, living on your machine, so a colleague cannot see it or recover your commits for you (no matter how much you beg them).
- Stuff expires: unreferenced entries clear out after about 90 days, so rescue sooner rather than later.
For anything further back than your own keystrokes, you want the project's history, not your reflog: see Ask the history. The reflog is where your HEAD has just been; the history is why the code is the way it is.