← Back to Blog

Git Undo Last Commit: Every Method Explained

You committed too early, included the wrong files, or pushed a secret. Git gives you multiple ways to undo a commit - but the wrong choice can destroy work or rewrite shared history. This guide explains every method and when to use each one.

The Decision: Which Method Do You Need?

Before reaching for any command, answer two questions:

  1. Has the commit been pushed to a shared remote? If yes, you must use git revert. Rewriting history on shared branches causes major problems for everyone who has pulled from it.
  2. Do you want to keep the changes from the commit? If yes, use --soft or the default (mixed) reset. If you want to discard the changes entirely, use --hard.
Method Commit removed? Changes kept? Safe after push?
--softYesStagedNo
Mixed (default)YesUnstagedNo
--hardYesDiscardedNo
revertNo (new commit)ReversedYes
--amendReplacedKept + stagedNo

Method 1: git reset --soft HEAD~1

Use this when you committed too early and want to keep all your changes staged and ready to re-commit. The commit is removed from history, but every file change from that commit is moved to the staging area (index).

git reset --soft HEAD~1

# Result:
# - Last commit is gone from git log
# - All changes from that commit are staged (git status shows: Changes to be committed)
# - Working directory is untouched

git status
# On branch feature/auth
# Changes to be committed:
#   modified: src/auth.js
#   new file:  src/token.js

This is the safest reset. Your work is fully preserved and ready to commit again, perhaps after fixing the commit message or adding one more file.

Method 2: git reset HEAD~1 (mixed reset, default)

The default git reset without a mode flag is a mixed reset. It removes the commit and unstages all changes. The files are modified in your working directory but not staged.

git reset HEAD~1
# equivalent to: git reset --mixed HEAD~1

# Result:
# - Last commit is gone
# - Changes are in your working directory, unstaged
# - git status shows: Changes not staged for commit

git status
# Changes not staged for commit:
#   modified: src/auth.js
#   modified: src/token.js

Use this when you want to undo the commit and start fresh with what to stage and commit. It gives you full control over what goes into the next commit.

Method 3: git reset --hard HEAD~1

This is the destructive option. It removes the commit AND discards all changes from the working directory and index. The code is gone.

# WARNING: This discards all changes. Use with care.
git reset --hard HEAD~1

# Result:
# - Last commit is gone
# - Working directory reverted to the state of the previous commit
# - Any uncommitted changes in those files are LOST

Never run git reset --hard without being certain you do not need those changes. If in doubt, use --soft first to see what will be affected, or create a backup branch: git branch backup-before-reset

One legitimate use case: you accidentally committed a large binary file or generated build artifacts. A hard reset removes the commit and the files in one step before you push.

Method 4: git revert HEAD (safe for pushed commits)

git revert does not remove the original commit. Instead, it creates a new commit that reverses the changes from a previous commit. The history is preserved; only the effect is undone.

# Undo the last commit safely (creates a new "revert" commit)
git revert HEAD

# Undo a specific commit by hash
git revert a3b2c1d4

# Revert without immediately committing (lets you review first)
git revert --no-commit HEAD

# For multiple commits, revert in reverse order
git revert HEAD~3..HEAD

After running git revert HEAD, your editor opens for the revert commit message. Accept the default or write a meaningful description. Then push normally - no force push needed.

git log --oneline
# a3b2c1d (HEAD) Revert "add experimental payment module"
# f7e9d2c add experimental payment module  <-- still in history
# 1a2b3c4 initial commit

This is the only safe method for shared branches. Force-pushing rewritten history forces every team member to re-sync their local copies and creates a nightmare if they have built on top of the original commits.

Method 5: git commit --amend

--amend replaces the last commit with a new one. Use it to fix typos in commit messages, add a forgotten file, or adjust the last commit before pushing:

# Fix the last commit message
git commit --amend -m "feat: add user authentication with JWT"

# Add a forgotten file to the last commit
git add src/forgot-this-file.js
git commit --amend --no-edit   # --no-edit keeps the original message

# Add a file AND fix the message
git add src/forgot-this-file.js
git commit --amend -m "feat: add user authentication with JWT and helpers"

Amend creates a brand new commit object (new SHA hash). Like other history-rewriting commands, do not amend commits that have been pushed to a shared branch.

Review Your Changes Before Committing

Paste two versions of a file into our Diff Checker to review exactly what changed - before you commit, push, or revert.

Open Diff Checker →

Undoing Multiple Commits

All the reset commands above accept a commit reference, not just HEAD~1:

# Undo the last 3 commits (soft: keep changes staged)
git reset --soft HEAD~3

# Undo back to a specific commit hash
git reset --soft a3b2c1d4

# View your recent commits to find the right one
git log --oneline -10
# f7e9d2c (HEAD) bad commit 3
# a1b2c3d bad commit 2
# 9z8y7x6 bad commit 1
# 1234abc (this is where you want to go back to)
git reset --soft 1234abc

Undoing a Pushed Commit

If you have already pushed to a remote and need to undo a commit:

Option A: git revert (recommended)

git revert HEAD
git push origin main

Clean, safe, no force push. Your team's history stays intact.

Option B: Force push (only for personal branches)

# Only do this on your own feature branch - never on main/master
git reset --soft HEAD~1
git push --force-with-lease origin feature/my-branch

Use --force-with-lease instead of --force. It checks that no one else has pushed to the branch since you last pulled, preventing accidental overwrites.

If you accidentally pushed a secret (API key, password, credentials) to any branch, a revert is NOT enough. The secret is still in git history and may have already been scraped. Treat it as compromised: rotate the secret immediately, then clean the history with git filter-repo or BFG Repo Cleaner.

The Reflog: Your Safety Net

Made a destructive reset and need to get your work back? Git's reflog records every movement of HEAD, including resets:

git reflog
# 1234abc (HEAD) HEAD@{0}: reset: moving to HEAD~1
# f7e9d2c HEAD@{1}: commit: the commit you just "lost"
# a1b2c3d HEAD@{2}: commit: previous commit

# Restore to the commit before the reset
git reset --hard f7e9d2c

# Or create a new branch at that point
git branch recovery-branch f7e9d2c

The reflog is local only and entries expire after 90 days by default. It is your best recovery tool for accidental hard resets and it has saved many developers from disaster.

Undoing a Merge Commit

Merge commits have two parents, which requires special handling:

# Undo a merge commit (not yet pushed)
git reset --hard HEAD~1

# Revert a merge commit (already pushed)
# -m 1 means "keep the first parent" (the branch you merged INTO)
git revert -m 1 HEAD

Frequently Asked Questions

What is the safest way to undo a commit?

If the commit has not been pushed: git reset --soft HEAD~1 is the safest. It removes the commit but keeps all your changes staged. No work is lost. If the commit has been pushed to a shared branch: git revert HEAD is the only safe option, as it preserves history.

What is the difference between git reset and git revert?

git reset rewrites history by moving the branch pointer backwards - the original commit is removed from the log. git revert creates a new commit that undoes the changes from a previous commit - the original commit stays in history. Use reset for local, unpushed commits. Use revert for shared branches.

Can I undo a commit that was pushed weeks ago?

Yes, with git revert <commit-hash>. It will create a new commit reversing those specific changes. If many commits have been made since then, resolving conflicts may be complex. Use git log --oneline to find the right hash.

I ran git reset --hard and lost my work. Can I recover it?

Possibly, via git reflog. Run git reflog to see recent HEAD positions, find the commit you were at before the reset, and restore with git reset --hard <hash>. This only works if git garbage collection has not run (default: 90 days). Act quickly.

What does HEAD~1 mean?

HEAD refers to the current commit you are on. ~1 means "one commit before HEAD." HEAD~3 means three commits back. You can also use a specific commit hash: git reset --soft a3b2c1d. Use git log --oneline to find the hash you need.

Use our free tool here

Compare two versions of a file to see exactly what your commit changed, or to verify a revert applied correctly. Paste any two text files for instant side-by-side diff.

Use our free tool here →

The Bottom Line

The right git undo command depends on two things: whether you have pushed the commit, and whether you want to keep the changes. The decision tree is simple: pushed + shared branch = git revert. Not yet pushed = git reset with the appropriate flag. When in doubt, always use --soft to keep your changes safe while you decide what to do next.

And always remember the reflog. It is your undo button for your undo operations.

UK
Written by Usman Khan
DevOps Engineer | MSc Cybersecurity | CEH | AWS Solutions Architect

Usman has 10+ years of experience securing enterprise infrastructure, managing high-traffic servers, and building zero-knowledge security tools. Read more about the author.