Git Reset: Soft, Mixed, Hard & Keep (Complete Guide for 2026)

Published February 16, 2026 · 15 min read

git reset is the most misunderstood “undo” command in Git — mainly because it can affect three different things:

This guide gives you a simple mental model for those three areas, then shows the practical recipes you actually need in real work.

Important: git reset is best for local, unpushed work. If a commit is already pushed to a shared branch, prefer git revert. If you already ran a bad reset or rebase and “lost” commits, use git reflog to recover.
⚙ Quick links: Git Undo (Reset vs Revert vs Restore) · Git Revert (pushed commits) · Undo Pushed Commit (revert workflow) · Undo Last Commit (quick guide) · Git Restore (unstage/discard) · Undo git add (unstage files) · Git Reflog Recovery · Revert a Merge Commit · Wrong Mainline Parent Recovery · Merge Queue Required Check Name Mismatch · Merge Queue Stale Review Dismissal · Merge Queue Emergency Bypass Governance · Git Commands Cheat Sheet · Git Diff Viewer Tool

Table of contents

  1. Copy/paste recipes (the 90% cases)
  2. The mental model: HEAD vs index vs working tree
  3. Reset modes: soft vs mixed vs hard vs keep
  4. Common scenarios (undo commits, unstage, reset to remote)
  5. Recovery: undo a bad reset with reflog
  6. Reset vs revert vs restore
  7. Troubleshooting
  8. FAQ

1. Copy/paste recipes (the 90% cases)

Undo the last commit (keep changes staged)

# You committed too early (or want to change the message)
# Keeps everything staged (ready to re-commit)

git reset --soft HEAD~1

Undo the last commit (keep changes, but unstage them)

# Undo the commit, but put changes back into the working tree
# so you can edit and re-stage selectively

git reset HEAD~1

Undo the last commit (discard changes completely)

# DANGEROUS: deletes staged + unstaged changes in tracked files

git reset --hard HEAD~1

Unstage everything (undo “git add .”)

# Option A: classic reset (unstages everything)

git reset

# Option B (modern): recommended unstage command

git restore --staged .

Reset your branch to match origin/main (discard local commits and changes)

# Get the latest remote pointer

git fetch origin

# DANGEROUS: throws away local commits + local changes

git reset --hard origin/main

Recover after a bad reset --hard

# Find where HEAD used to point

git reflog -n 20

# Reset back to the previous commit you want (hash from reflog)

git reset --hard <commit>
Safety trick: before a risky reset, create a backup branch pointing to your current commit:
git branch backup/before-reset
Then even if you mess up, you can get back by resetting to backup/before-reset.

2. The mental model: HEAD vs index vs working tree

To understand git reset, you need to keep three snapshots in mind:

Area What it is Common command
HEAD The commit your branch currently points to git log -1
Index (staging) The “next commit” snapshot you are building git add, git diff --staged
Working tree Your actual files on disk git diff

git reset always moves HEAD. The mode decides whether it also updates the index and your working tree.

3. Reset modes: soft vs mixed vs hard vs keep

Mode Moves HEAD? Resets index? Updates working tree files?
--soft Yes No No
--mixed (default) Yes Yes No
--hard Yes Yes Yes (destructive)
--keep Yes Yes Only if it won’t overwrite local changes

--soft: rewrite commits, keep staged changes

Use this when you want to redo a commit (message, author, squashing) but keep the content staged:

# Change the last commit message

git reset --soft HEAD~1

git commit -m "Better message"

--mixed (default): undo commits, keep files, unstage everything

This is the “undo commit but keep my work” mode. It moves HEAD and resets the index to match:

# Default mixed reset
# Equivalent to: git reset --mixed HEAD~1

git reset HEAD~1

After a mixed reset, your files still contain your changes, but they show up as unstaged modifications.

--hard: make everything match HEAD (destructive)

Hard reset is the nuclear option: it makes the index and working tree match the target commit.

# Throw away local changes to tracked files

git reset --hard
Hard reset does not reliably delete untracked files. It only affects tracked paths. If you also want to delete untracked files, that’s a different command: git clean.

--keep: move HEAD, but refuse to overwrite your local changes

--keep is useful when you want to move the branch pointer but you have local modifications you don’t want to lose.

# Keep local working tree changes if possible

git reset --keep HEAD~1

If the reset would overwrite your local changes, Git will stop with an error instead of destroying your work.

4. Common scenarios

Fix a bad commit message (local, not pushed)

git reset --soft HEAD~1

git commit -m "Fix: correct message"

Split one commit into two commits

# Undo the commit but keep changes staged
# Then unstage selectively and commit in smaller chunks

git reset --soft HEAD~1

git restore --staged .

git add -p

git commit -m "Part 1"

git add -p

git commit -m "Part 2"

Undo “git add” (unstage a file)

Modern Git: use git restore --staged (recommended):

git restore --staged path/to/file

Classic Git: you can also use git reset with a path to unstage:

git reset path/to/file
Rule of thumb: use git restore for file-level undo, and git reset for commit-history undo. If you want the full decision tree, see Git Undo: Reset, Revert & Restore.

Throw away local commits and match the remote branch

# Make sure you really want to lose local work

git fetch origin

git reset --hard origin/main

Undo a merge that you haven’t pushed yet

If you just ran git merge and want to go back immediately, ORIG_HEAD often points to where you were before:

# Go back to where you were before the merge

git reset --hard ORIG_HEAD

If the merge was pushed, don’t reset the shared branch. Use git revert -m instead: Git Revert a Merge Commit.

5. Recovery: undo a bad reset with reflog

If you moved HEAD to the wrong place, don’t panic. Git usually still knows where you were.

Step 1: inspect reflog:

git reflog -n 20

Step 2: reset back to the commit you want:

git reset --hard <hash-from-reflog>
Deep dive: reflog can also recover deleted branches and undo rebases. See Git Reflog: Recover Lost Commits (Rescue Guide).

6. Reset vs revert vs restore

Command Best for Rewrites history?
git reset Undo local commits, move branch pointer, unstage changes Yes (if you force-push)
git revert Undo a pushed commit safely by adding a new commit No
git restore Discard file edits or unstage paths without moving HEAD No

7. Troubleshooting

“fatal: ambiguous argument 'HEAD~1'”

This often happens in a repo with only one commit (there is no parent). Try resetting to a specific hash, or use --soft with an explicit commit you can see in git log.

Untracked files are still there after reset --hard

git reset --hard only affects tracked files. To remove untracked files, use git clean (careful):

# Preview what would be deleted

git clean -nd

# Then delete untracked files/directories

git clean -fd

I reset to the wrong place and now my commit is gone

Use reflog and recover quickly:

git reflog -n 20

git reset --hard <hash>

FAQ

Does git reset delete commits?

It removes commits from the current branch history, but the commits usually still exist in the repository for a while (reachable from reflog) until garbage collection prunes unreachable objects.

What’s the safest way to “undo git add”?

Use git restore --staged <file> (modern, explicit) or git reset <file> (classic). Both unstages the path without rewriting history.

What if I already pushed?

If other people might have pulled the commit, prefer git revert instead of reset. See Git Undo: Reset, Revert & Restore.


Want the full “what should I run?” decision guide for undoing anything (including pushed commits)? See: Git Undo: Reset, Revert & Restore.

Related Resources

Undo Pushed Commit Guide
Use git revert safely for shared branches with single/range/merge workflows
Git Undo: Reset vs Revert vs Restore
Decision guide: which undo command to use in each situation
Git Revert Complete Guide
Safe rollback workflows for pushed commits, ranges, and merges
Git Reflog Recovery
Recover “lost” commits after resets, rebases, and amends
Git Restore: Unstage & Discard Changes
File-level undo (the modern replacement for many checkout/reset uses)
Undo git add: Unstage Files Safely
Fast recipes for unstaging one file or everything without losing edits
Merge Queue Required Check Name Mismatch
Fix waiting-for-status rollback deadlocks caused by required-check context drift.
Merge Queue Stale Review Dismissal
Fix rollback PR approval loops caused by stale-review invalidation in queue workflows.
Git Clean: Remove Untracked Files Safely
Delete untracked files/folders with dry runs, exclusions, and interactive mode