Undoing things: reset, revert and reflog
Everyone makes mistakes in Git — a bad commit, a change committed to the wrong branch, a file deleted, a
reset that went too far. The difference between someone who panics and someone who calmly fixes it is
knowing the handful of "undo" tools and, crucially, which to use when. This lesson is undoing things safely:
checkout/restore, reset, revert, and the safety net almost nobody teaches beginners — reflog. It
closes the Git module.
Undoing uncommitted changes
The simplest case: you edited files, have not committed, and want to throw the changes away or unstage them.
git restore file.txt # discard uncommitted changes to a file (revert it to the last commit)
git restore --staged file.txt # unstage a file (keep the edit, just remove it from staging)
git restore . # discard ALL uncommitted changes — careful, this is destructive
(Older Git uses git checkout -- file and git reset HEAD file for these.) git restore throws away
uncommitted work permanently — there is no getting it back, because it was never committed. So look before you
run git restore .. If you are unsure, commit or stash first:
git stash # tuck all uncommitted changes away safely, giving you a clean tree
git stash pop # bring them back
Stash is a handy "hold this for a moment" — for example when you need to switch branches but are not ready to commit.
Undoing commits: reset vs revert
This is the crucial distinction, and getting it wrong is how people lose work or corrupt shared history.
git reset moves your current branch pointer to an earlier commit — it rewrites history by
discarding (or unstaging) the commits after that point. It has three modes:
git reset --soft HEAD~1 # undo the last commit, KEEP its changes staged (redo the commit differently)
git reset HEAD~1 # (--mixed, default) undo the commit, keep changes in the working dir, unstaged
git reset --hard HEAD~1 # undo the commit AND throw away its changes entirely — destructive
reset is for local, unshared commits — tidying up before you push. Because it rewrites history, using it
on commits you have already pushed (that others may have) causes the same shared-history problems as rebasing.
And --hard deletes work, so it is the most dangerous everyday Git command — be sure before you run it.
git revert does not rewrite history. It creates a new commit that undoes an earlier one, leaving the
original in place:
git revert HEAD # make a new commit that undoes the last commit
git revert a1b2c3d # undo a specific commit by hash
Because it adds a commit rather than removing one, revert is safe on shared history — it is how you undo
something that is already on main and that others have pulled. The rule:
reset— undo local, unpushed commits (rewrites history; use privately).revert— undo already-shared commits (adds an undoing commit; safe for everyone).
When you have pushed a bad commit to main, the answer is almost always revert, never reset.
Fixing the last commit: commit --amend
A special, common case: you just committed and immediately notice a typo in the message, or a file you forgot
to include. --amend replaces the last commit:
git commit --amend -m "better message" # change the last commit's message
git add forgotten.txt && git commit --amend --no-edit # add a file into the last commit
Like reset, --amend rewrites the last commit, so only amend commits you have not pushed. It is the
tidy way to fix a just-made commit without an ugly "fix typo" follow-up.
The safety net: reflog
Here is the thing that means you can almost never truly lose committed work, and that turns Git panic into a minor annoyance. Git keeps a log of everywhere HEAD has been — every commit, reset, checkout, merge — in the reflog:
git reflog # a list of recent HEAD positions, each with a hash
git reset --hard a1b2c3d # jump back to any of those states
So if you reset --hard and destroy commits, or lose track of a commit after a rebase, the reflog still lists
the hash of where you were — and you can get back to it. Even "deleted" commits linger for weeks before Git
cleans them up, and the reflog is how you find them. This is the single most reassuring thing to know in Git:
as long as work was committed at some point, the reflog can almost always recover it. People who know
reflog do not fear reset; people who do not, do. Learn it, and Git mistakes stop being scary.
Check your work
Uncommitted: git restore file (discard a file's changes), git restore --staged file (unstage), git restore . (discard all — destructive, never recoverable since never committed); git stash/stash pop to
tuck changes away safely.
reset vs revert (the key distinction): git reset moves the branch to an earlier commit, rewriting
history — --soft (keep staged), default (keep unstaged), --hard (delete changes — most dangerous). Use
only on local, unpushed commits. git revert adds a new commit that undoes an old one — safe on
shared history. Pushed a bad commit to main? Use revert, not reset.
commit --amend replaces the last commit (message or forgotten file) — rewrites it, so only for
unpushed commits.
reflog = the safety net: Git logs every HEAD position; git reflog lists them and you can reset --hard
back to any. Committed work is almost always recoverable, even after a --hard. Knowing reflog removes the
fear of reset.
Practice
- Edit a file, then
git restoreit; edit and stage one, thengit restore --stagedit — describe what each did. - Use
git stashto switch branches with uncommitted work, thengit stash popto bring it back. - Make a commit, then
git reset --soft HEAD~1and re-commit differently; explain what--softkept. - Make a commit on a shared-style branch and undo it with
git revert; explain why revert (not reset) is correct there. git reset --hardto delete a commit, then usegit reflogto find and restore it.- Explain the rule for when to use
resetversusrevert, and why amending only unpushed commits.
Official documentation
- Pro Git — Undoing things — restore, amend and the basics of undoing.
- Pro Git — Reset demystified — What
reset --soft/--mixed/--hardactually do. - Git — reflog documentation — Recovering lost commits with the reflog.
Next: the Containers module.
Stuck on this lesson?
Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.
About the internship