The main truth about Git, worth learning before your first panic: committed work is almost impossible to lose. Every mistake has a standard undo, and for the worst case there's reflog — a black box that remembers everything. Let's go through the tools from the light cases to the heavy ones.
Undo uncommitted changes: restore
git restore file.txt # roll the file back to the last commit (edits WILL BE LOST)
git restore --staged file.txt # remove from the index (edits stay in the file)
git restore . # roll back everything uncommitted
The only place in Git where work is truly lost is here: uncommitted edits cannot be brought back after restore. Hence the rule: when in doubt — commit first or stash it; you can always roll back later.
Stash it for a minute: stash
You need to switch urgently, but the work isn't finished:
git stash # tuck uncommitted work into the pocket
git stash list # what's in the pocket
git stash pop # bring back the last stashed item
Stash is a temporary pocket, not an archive: back on the task — pop right away. Collecting stashes for half a year is a way to forget what was in them.
Rolling back commits: reset versus revert
Two tools for different situations — the line is drawn by the question "has this already been shared with others?"
reset — rewrite local history (commits not pushed yet):
git reset --soft HEAD~1 # undo the last commit, changes stay in the index
git reset HEAD~1 # undo the commit, changes go to the working files (default)
git reset --hard HEAD~1 # undo the commit AND THROW AWAY the changes
--soft is "rebuild the commit differently", --hard is "this never happened". Treat --hard like UPDATE without WHERE: first make sure you're throwing away exactly what you think.
revert — undo publicly and honestly (commits already on the server):
git revert a1b2c3 # creates a NEW commit with the inverse changes
History isn't rewritten — it's extended with an antidote commit. This is exactly how merged-to-main changes get rolled back: a PR that broke production is undone with a revert commit in a minute, safely and with the chronicle preserved. The one-line rule: local — reset, pushed — revert.
reflog: the time machine of last resort
"Did reset --hard to the wrong place", "rebase broke everything", "deleted a branch with my work" — stay calm. Reflog is a journal of every HEAD movement over the last ~90 days, including "deleted" states:
git reflog
# a1b2c3 HEAD@{0}: reset: moving to HEAD~3
# d4e5f6 HEAD@{1}: commit: that very work ← there it is!
git reset --hard d4e5f6 # return to the state before the accident
# or more carefully: git branch rescue d4e5f6 — point a branch at the found commit
Everything that was ever committed can be found in reflog. There are almost no real ways to lose committed work — which brings us back to the rule from the start of the series: commit often; a commit is insurance that can't be taken away.
In short
- Uncommitted work is the only thing that's truly losable:
restoreis irreversible. When in doubt — commit or stash. - stash is a pocket for a minute: tuck away → switch → come back → pop.
- Local history is edited with reset (soft — rebuild, hard — throw away); pushed history is undone with a revert commit. "Local — reset, public — revert".
- reflog remembers all states for ~90 days: after any accident —
git reflog→ return to the right commit. - Frequent commits = insurance nobody can take away.
What to read next
- Rebase and cherry-pick — operations after which reflog is especially heartwarming.
- Commits and history —
--amendand other light touch-ups. - Branching models — the final article of the series.