Undoing changes: restore, reset & revert

Everyone commits the wrong file or breaks something eventually. Git almost never loses committed work, but the right "undo" command depends on where the change is: working directory, staging area, a local commit, or a commit already pushed and shared.

The three places a change can live

Where the mistake is Command Destroys work?
Edited file, not staged git restore file.py Yes, the edits are gone
Staged but not committed git restore --staged file.py No, just unstages
Last commit message wrong git commit --amend No (rewrites the local commit)
Local commits you want to drop or redo git reset Depends on the mode
Commit already pushed to a shared branch git revert <sha> No, adds a new commit

git restore

restore (Git 2.23+) replaced the confusing uses of checkout for files.

git restore settings.py              # throw away unstaged edits to one file
git restore --staged .env            # unstage, keep the file as it is
git restore --source=HEAD~2 app.py   # bring back app.py as it was two commits ago

git reset: move the branch pointer

reset moves your current branch to another commit. Its mode decides what happens to the changes in between:

git reset --soft HEAD~1    # undo last commit, keep changes staged (great for re-committing)
git reset --mixed HEAD~1   # default: undo commit, keep changes unstaged
git reset --hard HEAD~1    # undo commit AND discard its changes

Use reset only on commits that exist only on your machine. Resetting commits that teammates already pulled rewrites history and forces them to untangle it.

git revert: the safe undo for shared history

revert creates a new commit that applies the opposite of an earlier commit. History stays intact, so it is the right tool for main or any pushed branch.

git log --oneline -5
# 7c1e2d9 Change GST rate calculation   <- this broke billing
git revert 7c1e2d9                     # opens the editor for a message, then commits
git push

Reverting a merge commit needs -m 1 to say which parent is the mainline: git revert -m 1 <merge-sha>.

Your safety net: reflog

Git records every movement of HEAD for a while (by default around 90 days for reachable entries). Even after a bad reset --hard, you can usually recover:

git reflog
# a41f0b3 HEAD@{0}: reset: moving to HEAD~3
# 9d8e7f6 HEAD@{1}: commit: Add invoice PDF export
git reset --hard 9d8e7f6               # back to where you were

Uncommitted changes are not in the reflog, which is why restore and reset --hard on unsaved work are the only truly dangerous undo operations.

Common mistakes

  • Running git reset --hard with uncommitted work you wanted to keep. Stash or commit first.
  • Resetting and force-pushing a shared branch instead of reverting.
  • Using git commit --amend after pushing, then being surprised the push is rejected.
  • Committing a secret and thinking revert removes it. The secret is still in history: rotate the key immediately.

Practice

In a scratch repo make five commits. Then: amend the last message, reset --soft two commits and re-commit them as one, revert the first commit, and finally do a reset --hard HEAD~2 and recover it using git reflog.

B

Written by Bablu Kumar Jha

Founder, BeeProton AI · Mumbai, Maharashtra, India