Undo, Restore, Reset, and Revert
Introduction
Mistakes happen: wrong edit, bad commit, or a merge that should not have shipped. Git offers restore for local files, reset to move branch history, and revert to safely undo published commits. This chapter explains when to use each—and why reset --hard on shared branches is dangerous.
Prerequisites
Discard Working Tree Changes
Unstaged edits you want to throw away:
git restore README.mdCode explanation:
- Replaces file in working tree with last committed version
- Cannot undo easily—copy important edits first
Old equivalent (still seen in docs):
git checkout -- README.mdUnstage Without Losing Edits
File staged but you want to keep working on it:
git restore --staged README.mdCode explanation:
- Removes from staging area; file stays modified in working tree
- Old form:
git reset HEAD README.md
Restore From a Specific Commit
Recover an old version of one file:
git restore --source=HEAD~1 src/index.jsCode explanation:
HEAD~1means one commit before current tip- Does not move branch—only updates that file
git reset: Move HEAD
reset moves the current branch pointer and optionally staging/working tree.
Three modes:
| Mode | Moves HEAD | Staging | Working tree |
|---|---|---|---|
--soft | Yes | Keeps staged | Keeps edits |
--mixed (default) | Yes | Unstages | Keeps edits |
--hard | Yes | Discards | Discards |
Example—undo last commit but keep changes staged:
git reset --soft HEAD~1Undo last commit and unstage files:
git reset HEAD~1Throw away last commit and all its file changes:
git reset --hard HEAD~1Warning
--hard Destroys Local Work
reset --hard deletes uncommitted and committed changes after HEAD. On shared branches that were pushed, teammates' history diverges—avoid unless you know the recovery plan.
After a Bad Local Merge
Immediately after merge, before other work:
git reset --hard ORIG_HEADCode explanation:
ORIG_HEADpoints to where HEAD was before last dangerous operation
git revert: Safe Public Undo
Creates a new commit that reverses an old one—history stays intact.
git revert a1b2c3dEditor opens for revert message; save and close.
Revert latest commit:
git revert HEADCode explanation:
- Ideal for commits already on
origin/main - Team sees explicit "Revert ..." in log—no force push
Revert a merge commit needs -m parent number—advanced; ask reviewer if unsure.
reset vs revert Decision Table
| Situation | Tool |
|---|---|
| Wrong file edit, not committed | git restore |
| Staged too much | git restore --staged |
| Last commit wrong, not pushed | git reset --soft HEAD~1 |
| Wipe last commit locally, not pushed | git reset --hard HEAD~1 |
| Bad commit already pushed to shared branch | git revert |
Recover after accidental --hard | git reflog then reset to old SHA (troubleshooting chapter) |
Amend Last Commit (Related)
Fix message or add forgotten file to last commit:
git add forgotten.txt
git commit --amendWarning
Amend Rewrites History
Safe only if commit was never pushed, or you are the only user of the branch. Pushed amend requires force push—avoid on main.
See Your First Commit Workflow.
Practice Scenario
echo "typo" >> app.js
git add app.js
git commit -m "WIP typo"
# Oops—not ready
git reset --soft HEAD~1
git restore --staged app.js
git restore app.jsClean state as if commit never happened.
FAQ
restore vs reset?
restore = one file, working tree/staging.reset = move branch + optional mass discard.
Deleted file by mistake?
git restore deleted-file.txt if deletion not committed yet.
Revert twice?
Each revert adds a commit; reverting a revert restores original change.
reset pushed commit?
Possible with git push --force—breaks others' clones. Use revert on shared repos.
Undo git add .?
git restore --staged . keeps all edits, unstages all.
recover from --hard?
git reflog shows old HEAD positions—reset to saved SHA.