You just did git reset --hard HEAD~1 and threw away a commit
you actually needed. The commit is gone from git log. It's not
on any branch. Your working directory doesn't have the changes.
Panic seems reasonable.
Don't panic. Git rarely deletes anything immediately. The commit
is still in your local .git/ folder; you just need to find it
again. The tool for that is git reflog.
Git remembers every position
Every time your HEAD moves, whether from a commit, a reset, a
switch, a rebase, a merge, Git writes a line to a hidden log
called the reflog. Each line records where HEAD was and what
put it there. Run:
git reflog
Output looks something like:
c2 HEAD@{0}: reset: moving to HEAD~1
c3 HEAD@{1}: commit: Important work
c2 HEAD@{2}: commit: Earlier
Read it top down, most recent first. HEAD@{0} is where you are
right now. HEAD@{1} is where you were one step ago. And so on.
In this case, HEAD@{1} is the commit called Important work,
the one you thought you'd lost. Its SHA (c3) is right there in
the first column.
Getting the commit back
Once you know the SHA (or the HEAD@{n} reference), you can move
HEAD back to it:
git reset --hard HEAD@{1}
Or equivalently:
git reset --hard c3
Both do the same thing: point HEAD (and the current branch) back
at that commit, and reset the working directory to match. Your
"lost" commit is back on your branch, git log shows it again,
your files are as they were.
What reflog protects you from
Almost any local mistake. Some common ones:
- Hard reset that threw away a commit you needed.
- Force-checkout that overwrote uncommitted changes... actually no, reflog doesn't cover those, because those changes were never committed. Reflog only saves things that were committed at some point.
- Rebase that went wrong. Every commit that HEAD was on before the rebase is in the reflog.
- Deleted a branch (
git branch -Deven the "force" delete). The commits themselves live on in reflog for a while.
The rule: if it was ever committed, it's recoverable via reflog for about 30 days. After that, Git's garbage collector may prune the unreachable commits and they're gone for real.
Reflog is local
The reflog lives in .git/logs/HEAD on your machine. It is not
shared with anyone, not pushed to any remote, and does not exist
on your teammate's machine. If they lose a commit on their
machine, only their reflog can help. And vice versa.
This is important to remember, because it means reflog can't recover a commit that never existed on your machine. If your teammate rebased a shared branch and pushed the result, and you pull, your reflog won't have their old commits. You'd have to ask them to check theirs.
The one habit worth building
When you're about to do something that rewrites history (reset,
rebase, force operations), run git reflog first and make note of
where HEAD is. If anything goes sideways, that entry gives you a
known-good spot to reset back to. It's cheap insurance.