Undoing Changes: restore, reset & revert
Reviewed & published by Brayan K
Everyone makes mistakes in Git — the trick is knowing the right tool to fix each one. By the end of this lesson you'll confidently pick between git restore, the three modes of git reset, and git revert, and you'll know which ones are safe and which are destructive.
Part of the free Git course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
What You'll Learn
- Discard unstaged edits with git restore
- Unstage a file with git restore --staged (keeping your edits)
- Un-commit with git reset --soft, --mixed, and --hard
- Tell the safe resets from the destructive --hard
- Undo a shared commit safely with git revert
- Choose the right undo for each real-world situation
1️⃣ git restore — Undo Working-Tree Changes
git restore is the modern, focused way to undo file changes. With no flag it discards unstaged edits, snapping a file back to its last committed state — this is destructive for those edits, so be sure. Add --staged and it instead unstages a file while leaving your edits untouched. Same command, two jobs, split by one flag.
2️⃣ git reset — Move the Branch Pointer
git reset moves your branch back to an earlier commit. The mode decides what happens to the changes from the commits you drop. --soft keeps them staged (ideal for re-doing the last commit). --mixed (the default) keeps them unstaged in your working tree. --hard discards them entirely — that one is destructive, so reach for it carefully.
# git reset moves the current branch pointer to an earlier commit.
# Three modes decide what happens to the changes from the commits you drop:
#
# --soft keep changes STAGED (great for re-doing the last commit)
# --mixed keep changes UNSTAGED (the DEFAULT)
# --hard DISCARD changes entirely (⚠️ destructive, no undo)
# Un-commit the last commit but keep its work staged
git reset --soft HEAD~1
# Un-commit AND unstage — edits stay in your working tree (default)
git reset HEAD~1
# Nuke the last commit and any uncommitted edits with it
git reset --hard HEAD~13️⃣ git revert — The Safe Undo
When a commit is already pushed and shared, rewriting history with reset would break everyone who pulled it. git revert avoids that: it creates a new commit that applies the inverse of the target. History only grows, so collaborators stay in sync. This is the undo you'll use most on shared branches.
# git revert is the SAFE undo for commits you've already shared. Instead
# of erasing history, it adds a NEW commit that reverses the target one.
# See the history first
git log --oneline
# d4e5f6g add b <- we want to undo this
# a1b2c3d initial
# Revert it — Git makes a brand-new "Revert ..." commit
git revert d4e5f6g
# History GROWS (nothing is rewritten), so it's safe for teammates:
# 9z8y7x6 Revert "add b" <- new commit that undoes d4e5f6g
# d4e5f6g add b
# a1b2c3d initialYour turn. Match each undo to its situation by filling in the three blanks.
# 🎯 YOUR TURN — replace each ___ then run it in your terminal.
# Goal: undo work safely depending on the situation.
# 1) You edited app.js and regret it — discard the UNSTAGED edits
git ___ app.js # 👉 the command that discards working-tree edits
# 2) You staged the wrong file — UNSTAGE it but keep the edits
git restore ___ wrong.js # 👉 the flag that targets the staging area
# 3) You want to undo an ALREADY-PUSHED commit safely (new commit)
git ___ HEAD # 👉 the safe, history-preserving undo command
# ✅ Expected: step 1 leaves app.js clean, step 2 shows wrong.js as unstaged,
# step 3 creates a "Revert ..." commit on top of HEAD.Common Errors (and the fix)
- Used --hard and lost uncommitted work: uncommitted changes are unrecoverable. If the work was committed first, git reflog can often find it again.
- reset on a pushed branch broke teammates: reset rewrites history. On shared branches use git revert instead — it never rewrites.
- "error: pathspec did not match" with git restore: you mistyped the file path, or the file is untracked (restore only knows tracked files). Check git status.
- Confused soft and hard: remember --soft keeps work staged; --hard deletes it. When unsure, never use --hard.
Pro Tips
- 💡 Commit before experimenting: a commit is a safety net — reflog can rescue committed work, never uncommitted.
- 💡 Default to revert on shared branches: if anyone else has the commit, revert, don't reset.
- 💡 Read status after every undo: confirm the result before doing anything else.
- 💡 Save destructive resets for throwaway state: --hard is great to abandon a local mess, terrible by accident.
📋 Quick Reference
| Command | Purpose |
|---|---|
| git restore file | Discard unstaged edits to a file |
| git restore --staged file | Unstage a file, keep the edits |
| git reset --soft HEAD~1 | Un-commit, keep changes staged |
| git reset HEAD~1 | Un-commit, keep changes unstaged (default) |
| git reset --hard HEAD~1 | Un-commit and discard changes (destructive) |
| git revert <commit> | Undo a commit with a new commit (safe) |
Mini-Challenge: Choose Your Undo
No commands given this time — just three real situations. Decide which undo fits each, then prove it in a throwaway repo.
# 🎯 MINI-CHALLENGE: pick the right undo for each scene.
# No commands given — just the situations. Solve each in your terminal.
#
# A. You made local-only edits you don't want -> which command discards them?
# B. You committed too early and want the work back as staged changes
# -> which reset MODE keeps changes staged?
# C. You pushed a bad commit your team already pulled
# -> which command undoes it WITHOUT rewriting history?
#
# ✅ Expected answers: A = git restore <file>, B = git reset --soft HEAD~1,
# C = git revert <commit>. Try each in a throwaway repo to prove it.
# your commands here🎉 Lesson Complete!
- ✅ git restore discards unstaged edits; --staged unstages
- ✅ reset --soft keeps work staged, --mixed unstages, --hard deletes
- ✅ --hard is destructive for uncommitted work — no undo
- ✅ git revert safely undoes shared commits by adding a new one
- ✅ Reset rewrites history; revert preserves it — choose by who else has the commit
Practice quiz
Which command discards unstaged edits in your working tree, reverting a file to its last committed state?
- git reset file.txt
- git restore file.txt
- git revert file.txt
- git clean file.txt
Answer: git restore file.txt. git restore file.txt overwrites the working-tree file with the version from the index/last commit.
How do you UNSTAGE a file without losing your edits?
- git restore --staged file.txt
- git restore file.txt
- git reset --hard
- git checkout file.txt
Answer: git restore --staged file.txt. git restore --staged removes the file from the index but leaves your working-tree changes intact.
What does `git reset --soft HEAD~1` do?
- Deletes the last commit and its changes
- Moves HEAD back one commit but leaves those changes STAGED
- Discards all uncommitted work
- Creates a new commit
Answer: Moves HEAD back one commit but leaves those changes STAGED. --soft moves the branch pointer back but keeps the changes in the staging area, ready to recommit.
What does the DEFAULT `git reset HEAD~1` (i.e. --mixed) do?
- Leaves changes staged
- Moves HEAD back and leaves the changes UNSTAGED in the working tree
- Deletes the working-tree changes
- Pushes to remote
Answer: Moves HEAD back and leaves the changes UNSTAGED in the working tree. --mixed (the default) un-commits and unstages, but your file edits remain in the working tree.
What is dangerous about `git reset --hard HEAD~1`?
- It pushes automatically
- It permanently discards the commit AND your working-tree changes
- It renames the branch
- It creates a merge commit
Answer: It permanently discards the commit AND your working-tree changes. --hard wipes the working tree to match the target commit, so uncommitted work is lost.
Which command undoes a commit by creating a NEW commit that reverses it?
- git reset
- git restore
- git revert
- git amend
Answer: git revert. git revert builds a fresh commit that applies the inverse of the target commit, preserving history.
Why is git revert preferred over git reset for SHARED, already-pushed commits?
- It is faster
- It rewrites less code
- It doesn't rewrite history, so it's safe for branches others have pulled
- It compresses the repo
Answer: It doesn't rewrite history, so it's safe for branches others have pulled. revert adds a new commit instead of moving the branch pointer, so collaborators' history stays valid.
You staged a file by mistake but want to keep editing it. Which is correct?
- git reset --hard
- git restore --staged file.txt
- git revert file.txt
- git clean -f
Answer: git restore --staged file.txt. git restore --staged unstages it while leaving your edits untouched.
After `git reset --soft HEAD~1`, where are the changes from that commit?
- Deleted
- Staged, ready to commit again
- Pushed to origin
- In the stash
Answer: Staged, ready to commit again. Soft reset keeps everything staged, which is handy for re-doing the last commit differently.
Which command would you use to throw away ALL local commits and edits back to a known good commit (knowingly destructive)?
- git restore
- git revert HEAD
- git reset --hard <commit>
- git diff
Answer: git reset --hard <commit>. git reset --hard <commit> moves the branch and wipes the working tree to that commit — irreversible for uncommitted work.
Continue this course
- Previous: The Staging Area & git diff
- Next: Stashing Work in Progress — Shelve unfinished changes with git stash and bring them back later
- Quick reference: Git cheat sheet › Undoing
- From the blog: Essential Git Commands for Developers
Frequently asked questions
What's the difference between git restore and git reset?
git restore operates on file contents — it discards unstaged edits or unstages files. git reset operates on the branch pointer and the staging area — it moves where your branch points and decides whether dropped changes stay staged, unstaged, or are discarded. As a rule of thumb: use restore for 'undo my edits', and reset for 'move my branch back in history'.
When should I use --soft, --mixed, or --hard with git reset?
Use --soft to un-commit while keeping everything staged, perfect for redoing the last commit with a better message or different files. Use --mixed (the default) to un-commit and unstage, leaving your edits in the working tree. Use --hard only when you truly want to throw away both the commits and any uncommitted work — it overwrites your working tree and there's no undo for unsaved changes.
Is git reset --hard recoverable?
Committed work you reset away can often be recovered through git reflog, which remembers where your branch pointed recently. But uncommitted changes that --hard wipes are gone for good — Git never saved them, so there's nothing to recover. Treat --hard as a one-way door for anything not yet committed.
Why use git revert instead of git reset on a shared branch?
git reset rewrites history by moving the branch pointer, which breaks every teammate who already pulled those commits. git revert instead adds a brand-new commit that reverses the change, so history only grows and stays valid for everyone. On any branch others have, revert is the safe choice.
How do I undo just one file from a specific commit?
Use git restore --source=<commit> <file> to pull that file's contents from a particular commit into your working tree (staging it is then up to you). git revert and git reset both operate on whole commits, so for a single-file rollback, git restore --source is the precise tool.