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:

bash
git restore README.md

Code explanation:

  • Replaces file in working tree with last committed version
  • Cannot undo easily—copy important edits first

Old equivalent (still seen in docs):

bash
git checkout -- README.md

Unstage Without Losing Edits

File staged but you want to keep working on it:

bash
git restore --staged README.md

Code 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:

bash
git restore --source=HEAD~1 src/index.js

Code explanation:

  • HEAD~1 means 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:

ModeMoves HEADStagingWorking tree
--softYesKeeps stagedKeeps edits
--mixed (default)YesUnstagesKeeps edits
--hardYesDiscardsDiscards

Example—undo last commit but keep changes staged:

bash
git reset --soft HEAD~1

Undo last commit and unstage files:

bash
git reset HEAD~1

Throw away last commit and all its file changes:

bash
git reset --hard HEAD~1

Warning

--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:

bash
git reset --hard ORIG_HEAD

Code explanation:

  • ORIG_HEAD points 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.

bash
git revert a1b2c3d

Editor opens for revert message; save and close.

Revert latest commit:

bash
git revert HEAD

Code 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

SituationTool
Wrong file edit, not committedgit restore
Staged too muchgit restore --staged
Last commit wrong, not pushedgit reset --soft HEAD~1
Wipe last commit locally, not pushedgit reset --hard HEAD~1
Bad commit already pushed to shared branchgit revert
Recover after accidental --hardgit reflog then reset to old SHA (troubleshooting chapter)

Fix message or add forgotten file to last commit:

bash
git add forgotten.txt
git commit --amend

Warning

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

bash
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.js

Clean 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.