One of the most reassuring things about Git is that almost everything can be undone. Committed work is rarely lost permanently. However, there are a small number of situations where undoing something incorrectly can cause data loss — particularly when working with changes that have never been committed. This topic maps out the full landscape of undoing in Git, from the safest operations to the ones that require care.
The Three Layers of Undoing
Undoing in Git operates at three distinct levels, each corresponding to one of the three sections covered earlier:
| Where the work is | What you want to undo | Tool |
|---|---|---|
| Working directory | Discard unsaved changes to a file | git restore <file> |
| Staging area | Unstage a file (keep the changes) | git restore --staged <file> |
| Committed history | Fix or undo a commit | git commit --amend, git revert, git reset |
Each layer has its own commands and its own risk profile.
1. Discarding Working Directory Changes — git restore
If you have modified a file in your working directory and want to throw those changes away entirely — reverting it back to the last committed version:
git restore app.js
⚠️ This is a destructive operation. Any changes you made to the file are permanently gone — Git replaces the file with the version from the last commit or staging area. There is no recovery. Only use this when you are absolutely certain you do not need the changes.
To discard all unstaged changes across the entire working directory:
git restore .
2. Unstaging a Staged File — git restore --staged
If you accidentally staged a file that you did not intend to include in the next commit, you can move it back to modified (unstaged) without losing the changes:
git restore --staged app.js
The file remains modified in your working directory — only its staging is undone. Your changes are safe.
Before:
Changes to be committed:
modified: app.js
After git restore --staged app.js:
Changes not staged for commit:
modified: app.js
To unstage everything currently staged:
git restore --staged .
The older equivalent
In older Git versions (before 2.23), the equivalent commands were:
git reset HEAD app.js # Unstage a file
git checkout -- app.js # Discard working directory changes
You will still encounter these in older tutorials and documentation. git restore is the modern replacement and is clearer in its intent — it was specifically introduced to make undoing less confusing.
3. Amending the Last Commit — git commit --amend
If you have just committed and immediately notice a mistake — a missing file, a typo in the message, or a small oversight — you can replace the commit entirely:
# Add the file you forgot
git add forgotten-file.js
# Replace the last commit
git commit --amend
This opens your editor with the previous commit message pre-filled. You can edit the message or leave it unchanged. When you save and close, the new commit replaces the old one — the original commit is gone from the history.
To amend only the commit message without changing its contents:
git commit --amend -m "Corrected commit message"
⚠️ Only amend local commits. Amending replaces a commit with a new one that has a different SHA-1 hash. If the original commit has already been pushed to a remote repository that others are working from, amending it and force-pushing will rewrite shared history and cause problems for your collaborators.
4. Reverting a Commit — git revert
When you need to undo the effects of a commit that has already been pushed and shared, git revert is the safe choice. Rather than removing or rewriting history, it creates a new commit that applies the opposite of the changes from the specified commit:
git revert abc123
This opens an editor to write the revert commit message. Once you save, Git creates a new commit that undoes the specified one. The original commit remains in the history — nothing is rewritten.
# Revert the most recent commit
git revert HEAD
# Revert a specific commit by hash
git revert 463dc4f
# Revert without opening an editor
git revert HEAD --no-edit
git revert is always safe to use on shared branches because it adds to history rather than rewriting it. It is the standard way to undo changes in a collaborative environment.
5. Resetting to a Previous State — git reset
git reset moves the current branch pointer backwards to a specified commit. Unlike git revert, it rewrites history by removing commits. It comes in three modes that control what happens to the changes from the removed commits:
--soft — keep changes staged
Moves the branch pointer back but keeps the changes from the removed commits in the staging area, ready to be recommitted:
git reset --soft HEAD~1 # Undo the last commit, keep changes staged
Use this when you want to undo a commit but keep all the work intact for re-committing.
--mixed — keep changes unstaged (default)
Moves the branch pointer back and unstages the changes, but keeps them in the working directory:
git reset HEAD~1 # Same as git reset --mixed HEAD~1
Use this when you want to undo a commit and re-stage things more carefully before recommitting.
--hard — discard everything
Moves the branch pointer back and discards all changes from the removed commits entirely:
git reset --hard HEAD~1 # Undo the last commit and permanently delete its changes
⚠️
git reset --hardis destructive. The changes from the removed commits are gone from both the staging area and the working directory. They cannot be recovered through normal means. Use with extreme caution.
Reset modes at a glance
| Mode | Branch pointer | Staging area | Working directory |
|---|---|---|---|
--soft | Moves back | Changes kept staged | Unchanged |
--mixed (default) | Moves back | Changes unstaged | Unchanged |
--hard | Moves back | Cleared | Cleared |
⚠️ Only reset local commits. Like
--amend, resetting rewrites history. Never usegit reseton commits that have been pushed to a shared remote branch.
6. Recovering Lost Work — the Reflog
If you accidentally reset too far or lose commits you needed, Git's reflog records every position HEAD has been in for the past 90 days (by default):
git reflog
463dc4f HEAD@{0}: reset: moving to HEAD~1
ca82a6d HEAD@{1}: commit: Add user authentication
085bb3b HEAD@{2}: commit: Remove unnecessary test
You can recover a lost commit by checking it out or resetting back to it:
git reset --hard HEAD@{1} # Go back to where HEAD was one step ago
The reflog is a safety net that makes git reset --hard recoverable as long as you act before Git's garbage collection removes the orphaned commits (typically after 90 days).
Choosing the Right Tool
| Situation | Best Tool |
|---|---|
| Discard unsaved file changes | git restore <file> |
| Unstage a file without losing changes | git restore --staged <file> |
| Fix the last commit (local only) | git commit --amend |
| Undo a pushed commit safely | git revert <hash> |
| Undo local commits, keep changes staged | git reset --soft HEAD~n |
| Undo local commits, keep changes unstaged | git reset --mixed HEAD~n |
| Undo local commits, discard all changes | git reset --hard HEAD~n |
| Recover work after an accidental reset | git reflog |
The Golden Rule
Anything that has been committed in Git can almost always be recovered, even commits that were on deleted branches or overwritten with --amend. The reflog is your safety net.
However, anything that was never committed — changes that existed only in your working directory — cannot be recovered if discarded. This is why committing frequently and using git restore carefully are both important habits.
Summary
| Command | What It Does |
|---|---|
git restore <file> | Discards working directory changes (destructive) |
git restore --staged <file> | Unstages a file, keeps changes in working directory |
git commit --amend | Replaces the last commit (local only) |
git revert <hash> | Creates a new commit that undoes a previous one (safe for shared history) |
git reset --soft HEAD~n | Moves branch back n commits, keeps changes staged |
git reset --mixed HEAD~n | Moves branch back n commits, keeps changes unstaged |
git reset --hard HEAD~n | Moves branch back n commits, discards all changes (destructive) |
git reflog | Shows the history of HEAD movements for recovery |