Skip to content

Undoing Changes in Git

Git gives you multiple tools for undoing changes. Choose the right one based on whether the commit is local or shared, and how far back you need to go.

Terminal window
# Discard all changes in working tree (cannot be recovered)
git restore .
git restore path/to/file.ts
# Unstage a file (keep changes in working tree)
git restore --staged path/to/file.ts
# Unstage everything
git restore --staged .

Fix the most recent commit โ€” message, files, or both:

Terminal window
# Change the commit message
git commit --amend -m "Better commit message"
# Add a forgotten file to the last commit
git add forgotten-file.ts
git commit --amend --no-edit
# Change both files and message
git add fixed-file.ts
git commit --amend -m "Correct message and files"

Only amend commits that have not been pushed โ€” amending rewrites history.

Creates a new commit that undoes the changes from a previous commit. Safe because it doesnโ€™t rewrite history:

Terminal window
# Revert the last commit
git revert HEAD
# Revert a specific commit
git revert abc1234
# Revert without automatically committing (preview changes first)
git revert -n abc1234
git revert --no-commit abc1234
# Revert a range of commits
git revert abc1234..ghi9012

Use revert when the commit has been pushed to a shared branch.

git reset moves HEAD (and the branch pointer) to a different commit. Three modes:

Terminal window
# --soft: keeps staged changes and working tree
git reset --soft HEAD~1 # undo last commit, keep changes staged
# --mixed (default): unstages changes, keeps working tree
git reset HEAD~1 # undo last commit, changes in working tree
git reset --mixed HEAD~1 # same
# --hard: discards staged and working tree changes
git reset --hard HEAD~1 # undo last commit, LOSE all changes
git reset --hard origin/main # match remote exactly

Never use --hard unless youโ€™re certain you donโ€™t need those changes.

git reflog records every change to HEAD โ€” even after reset or rebase:

Terminal window
git reflog
# abc1234 HEAD@{0}: reset: moving to HEAD~1
# def5678 HEAD@{1}: commit: Add user profile page
# ...
# Recover the lost commit
git reset --hard def5678
# or create a branch at it
git switch -c recovery-branch def5678

The reflog is local only and entries expire after 90 days (default).

Terminal window
# Stop tracking a file but keep it on disk
git rm --cached secrets.env
# Stop tracking a directory
git rm --cached -r config/local/
# Then add to .gitignore to prevent re-tracking
Terminal window
# Preview what would be deleted
git clean -n
# Delete untracked files
git clean -f
# Delete untracked files and directories
git clean -fd
# Delete files including ignored ones
git clean -fxd
CommandWhat it does
git restore <file>Discard working tree changes
git restore --staged <file>Unstage file
git revert <commit>Create new commit undoing changes (safe)
git reset --soft HEAD~nUndo commits, keep changes staged
git reset --mixed HEAD~nUndo commits, changes go to working tree
git reset --hard HEAD~nUndo commits, discard all changes
Did you push the commit to a shared branch?
โ”œโ”€โ”€ YES โ†’ git revert (creates a new "undo" commit)
โ””โ”€โ”€ NO โ†’ What do you want to undo?
โ”œโ”€โ”€ Just the commit message โ†’ git commit --amend
โ”œโ”€โ”€ Last commit (keep changes) โ†’ git reset --soft HEAD~1
โ””โ”€โ”€ Last commit + changes โ†’ git reset --hard HEAD~1