Skip to main content

Undoing Changes

Quick Summary

Git provides ways to undo changes at every level — from discarding uncommitted edits to rewriting entire commit histories. The right tool depends on what you want to undo and whether the changes have been shared.


Undo Decision Flowchart

flowchart TD
A["What do you want to undo?"] --> B{Pushed to remote?}
B -->|No| C{Committed?}
B -->|Yes| D["git revert<br/>(safe, creates new commit)"]
C -->|No| E{Staged?}
C -->|Yes, last commit| F["git commit --amend<br/>or git reset"]
C -->|Yes, older commit| G["git rebase -i"]
E -->|No| H["git checkout -- file<br/>or git restore file"]
E -->|Yes| I["git restore --staged file<br/>or git reset HEAD file"]

By Severity Level

Level 1: Discard Unstaged Changes (Working Directory)

# Discard changes to a specific file
git restore <file>
git checkout -- <file> # Legacy equivalent

# Discard ALL unstaged changes
git restore .
git checkout -- . # Legacy
This is irreversible

Discarding unstaged changes permanently deletes your modifications. There's no undo for this undo.

Level 2: Unstage Files (Keep Changes)

# Unstage a specific file (keep modifications in working directory)
git restore --staged <file>
git reset HEAD <file> # Legacy equivalent

# Unstage everything
git restore --staged .
git reset HEAD # Legacy

Level 3: Amend the Last Commit

# Fix the commit message
git commit --amend -m "Corrected message"

# Add forgotten files to the last commit
git add forgotten-file.js
git commit --amend --no-edit

# Change author
git commit --amend --author="Name <email>" --no-edit

Level 4: Undo Commits (Local Only)

# Undo last commit, keep changes staged
git reset --soft HEAD~1

# Undo last commit, keep changes unstaged
git reset --mixed HEAD~1 # (default)
git reset HEAD~1

# Undo last commit, DELETE all changes
git reset --hard HEAD~1
Reset ModeCommitStagingWorking Directory
--soft❌ Undone✅ Preserved✅ Preserved
--mixed (default)❌ Undone❌ Unstaged✅ Preserved
--hard❌ Undone❌ Cleared❌ Deleted

Level 5: Undo Pushed Commits (Safe)

# Create a NEW commit that reverses the changes of a specific commit
git revert <commit-hash>

# Revert the last commit
git revert HEAD

# Revert without auto-committing
git revert --no-commit <hash>

# Revert a merge commit (specify parent)
git revert -m 1 <merge-commit-hash>
Revert vs Reset

revert creates a new commit that undoes changes — safe for shared branches.
reset rewrites history — only safe for local, unpushed commits.


Common Undo Scenarios

ScenarioCommand
Accidentally edited a filegit restore <file>
Staged wrong filesgit restore --staged <file>
Commit message typogit commit --amend -m "..."
Forgot to include a filegit add file && git commit --amend --no-edit
Want to redo last commit differentlygit reset --soft HEAD~1
Need to undo a pushed commitgit revert <hash>
Accidentally deleted a branchgit reflog + git branch recover <hash>
Bad mergegit revert -m 1 <merge-hash>

Best Practices

  • Use git restore (Git 2.23+) instead of the overloaded git checkout for discarding changes
  • Use revert for shared history — never reset --hard on pushed commits
  • Check git status before dangerous operations — know what you're undoing
  • Keep reflog in mind — your last resort for recovering "lost" commits

What's Next

  1. Recovery Techniques — Recover deleted branches, lost commits, and corrupted repos
  2. Cheatsheet — Quick reference for all Git commands