How to Undo or Reverse Commits in Git

This guide covers how to undo, fix, or reverse commits in Git depending on your workflow state (local vs. remote) and what you want to do with your code changes.

The Core Choice: Amend vs. Reset vs. Revert

Before running any command, ask yourself two main questions:

  1. Have you already pushed your commit to a remote repository?
  2. Do you just want to tweak/fix the latest local commit, or discard/undo it entirely?
graph TD
    A[Want to undo or fix a commit?] --> B{Has it been pushed?}
    
    B -- No (Local Only) --> C{What is your goal?}
    C -- Tweak / modify last commit --> C1[Use git commit --amend]
    C -- Undo / rewind 1+ commits --> C2[Use git reset]
    
    C2 --> C2a[--soft: Keep changes staged]
    C2 --> C2b[--mixed: Keep changes unstaged]
    C2 --> C2c[--hard: Nuke changes completely]
    
    B -- Yes (Shared / Remote) --> D[Use git revert]
    D --> D1[Creates a new safe commit that undoes the work]

1. Local Commits Only (Not Yet Pushed)

If your changes only exist on your local computer, you can safely rewrite your commit history.

CAUTION

Danger Zone: Commands that alter commit history (like git commit --amend and git reset) should never be used on commits that others have pulled or built upon, as it will break their local repositories.


Strategy A: Modify the Most Recent Commit (git commit --amend)

Use this when you want to combine new changes into your last commit or fix a typo in your commit message without creating an extra, messy commit.

  • Command (Update message only):

    git commit --amend -m "Updated commit message"
  • Command (Add missing files to last commit):

    git add missing-file.txt
    git commit --amend --no-edit
  • History: Replaces the tip of the current branch with a newly modified commit.

  • Your Code: Your newly staged files and previous staged changes are merged into the original commit.


Strategy B: Rewind Commit History (git reset)

Mode 1: Keep Changes Staged (--soft)

Use this when you want to completely undo the commit structure but keep files prepped and ready to re-commit.

  • Command: git reset --soft HEAD~1
  • History: The last commit vanishes.
  • Your Code: Your files remain modified and sit in the Staging Area (ready to be committed again).

Mode 2: Keep Changes Unstaged (--mixed / Default)

Use this when you want to undo the commit and step back to rethink your work.

  • Command: git reset HEAD~1 (or git reset --mixed HEAD~1)
  • History: The last commit vanishes.
  • Your Code: Your files remain modified but move back to your Working Directory (unstaged).

Mode 3: Destroy Everything Permanently (--hard)

Use this when you realize a commit was a total mistake and you want to erase it completely from existence.

  • Command: git reset --hard HEAD~1
  • History: The last commit vanishes.
  • Your Code: Permanently deleted. Any uncommitted changes in your working directory are also wiped out.

2. Pushed Commits (Public / Shared History) — git revert

If your commit is already on a remote server, altering history with reset or --amend will cause conflicts for teammates. Instead, you must use git revert.

  • Command: git revert HEAD
  • History: Your bad commit remains in the history log. Git creates a brand-new commit that introduces the exact opposite changes, cleanly neutralizing the mistake.
  • Your Code: Your working directory updates to reflect the rolled-back state.

Reverting Older Commits

To undo a specific commit further back in time, use git log to find its unique SHA hash and pass it directly:

git revert <commit-hash>

Quick Reference Summary Table

CommandTarget EnvironmentModifies History?What Happens to Your Code?
git commit --amendLocal OnlyYes (Rewrites tip)Combines staged changes & updates last commit
git reset --soft HEAD~1Local OnlyYes (Deletes commit)Kept in Staging Area (Ready to commit)
git reset HEAD~1Local OnlyYes (Deletes commit)Kept in Working Directory (Unstaged)
git reset --hard HEAD~1Local OnlyYes (Deletes commit)Permanently Deleted 🛑
git revert HEADPushed / RemoteNo (Appends new)Safely rolls back to previous state via a new commit

Hands-On Interactive Sandbox Test

You can test all these scenarios safely by running this step-by-step simulation inside a blank folder on your computer.

Setup a Test Repository

Open your terminal (Mac/Linux) or Git Bash (Windows) and run:

# 1. Create a fresh sandbox folder and enter it
mkdir git-sandbox && cd git-sandbox
 
# 2. Initialize it as a Git repository
git init -b main
 
# 3. Create a baseline file and make a first commit
echo "Line 1: Good Code" > app.txt
git add app.txt
git commit -m "Initial baseline commit"

Scenario 1: Test git commit --amend (Fixing a mistake locally)

Let’s add a line, commit it, and then fix a missing file without making a second commit.

# 1. Commit a new line
echo "Line 2: New feature" >> app.txt
git add app.txt
git commit -m "Add feature line"
 
# 2. Realize you forgot a config file!
echo "config=true" > config.txt
git add config.txt
 
# 3. Amend the previous commit to include config.txt and fix the commit message
git commit --amend -m "Add feature line and config file"
 
# 4. Check history (You will see only ONE commit was created for both files!)
git log --oneline

Scenario 2: Test a Local --soft Reset

Let’s make a mistake and undo it while keeping our files staged.

# 1. Make a bad modification and commit it
echo "Line 3: Oops, a typo here!" >> app.txt
git add app.txt
git commit -m "Add line 3 with a typo"
 
# 2. Run the soft reset
git reset --soft HEAD~1
 
# 3. Verify status (The file is still staged and ready to edit!)
git status
# Output: "Changes to be committed: modified: app.txt"

Scenario 3: Test a Public git revert

Let’s simulate undoing a commit in a way that is perfectly safe for a pushed, remote repository.

# 1. Commit the change normally again
git commit -m "Add line 3 with typo"
 
# 2. Revert the commit safely
git revert HEAD --no-edit
 
# 3. Check your file content—the bad line is gone, but history remains intact!
cat app.txt
 
# 4. View your log to see the new revert commit appended cleanly
git log --oneline