Undo Mistakes
Git's safety net is larger than most people realize. Almost every "mistake" is recoverable. This lesson covers the full toolkit for undoing changes at every stage.
Stash: Save Work in Progress
You are mid-way through a change and need to switch branches urgently — but you are not ready to commit. git stash saves your uncommitted changes and restores a clean working directory.
# Save your WIP
git stash
# Your working directory is now clean
git status # nothing to commit
# Do the urgent thing (switch branches, pull, etc.)
git switch main
git pull
# Come back to your WIP
git switch -
git stash pop # restore your stashed changes
Stash with a description
git stash push -m "half-finished refactor of login form"
See all stashes
git stash list
stash@{0}: On feature-x: half-finished refactor of login form
stash@{1}: WIP on main: fix typo
Restore a specific stash
git stash pop stash@{1}
Discard Unstaged Changes
Changed a file and want to throw the changes away and go back to the last committed version:
git restore <file>
This is destructive — the unsaved changes are gone. There is no undo.
Discard all unstaged changes in the project
git restore .
Unstage a File
You ran git add but changed your mind about including a file in the next commit:
git restore --staged <file>
This moves the file back from the Staging Area to the Working Directory. Your changes are preserved — they are just no longer staged.
Undo a Commit (Soft Reset)
You just committed something and want to uncommit it, but keep the changes staged:
git reset --soft HEAD~1
HEAD~1 means "one commit before HEAD." The commit is gone from history, but all the changes are still in the Staging Area, ready to be recommitted differently.
Use this when you want to redo a commit with a different message or a different set of files.
Undo a Commit (Hard Reset)
git reset --hard permanently deletes commits and their changes. Only use this for local, unpushed work you are certain you want to discard.
git reset --hard HEAD~1
The last commit is removed from history and its changes are deleted from your working directory entirely.
Safe Undo for Pushed Commits
If a commit is already on GitHub and others may have pulled it, do not use git reset. Use git revert instead:
git revert <commit-hash>
git revert creates a new commit that reverses the changes of the specified commit. The original commit stays in history. This is safe because it does not rewrite history — it only adds to it.
The Ultimate Safety Net: Reflog
git reflog records every state HEAD has been in, including commits you "deleted" with git reset.
git reflog
a1b2c3d HEAD@{0}: reset: moving to HEAD~1
9f8e7c6 HEAD@{1}: commit: The commit you "lost"
3d2c1b0 HEAD@{2}: commit: Previous commit
To recover a "lost" commit, reset back to it:
git reset --hard 9f8e7c6
Reflog entries expire after 90 days by default. For practically all real-world accidents, your work is still there.
Which Command to Use
| Situation | Command |
|---|---|
| Undo staged files (keep changes) | git restore --staged <file> |
| Discard unstaged changes | git restore <file> |
| Save WIP without committing | git stash / git stash pop |
| Undo last commit (keep staged) | git reset --soft HEAD~1 |
| Undo last commit (discard changes) | git reset --hard HEAD~1 |
| Undo a pushed commit safely | git revert <hash> |
| Recover "lost" work | git reflog then git reset --hard <hash> |