Git Reset: Undo Changes at Any Stage
git reset is one of Git's most powerful, and most misunderstood, commands. This guide explains the three modes (--soft, --mixed, --hard), when each is safe to use, and how to recover if you go too far.
Beginner10 min readUpdated
What is git reset?
git reset moves the current branch pointer (HEAD) to a different commit, optionally changing the staging area and working directory. The three modes are: --soft (moves HEAD only), --mixed (default, also clears the staging area), and --hard (also discards working directory changes).
| Aspect | --soft | --hard |
|---|---|---|
| Moves HEAD | yes | yes |
| Staging area | kept as is | cleared |
| Working directory | kept as is | all changes discarded |
Why it matters
You committed too early, staged the wrong file, or want to throw away some changes entirely, but you're scared to touch git reset because you've heard it can destroy work.
git reset is one of the most useful undoing tools in Git. The key is understanding which of its three modes moves what: the commit pointer (HEAD), the staging area (index), and the working directory. Once you understand that, it stops being scary.
Where it usually goes wrong
- Using
--hardwhen you meant--soft, discarding uncommitted work - Running
git reseton a pushed commit and force-pushing, breaking teammates' history - Confusing
git reset <file>(unstage) withgit reset HEAD~1(undo commit) - Not knowing how to recover from an accidental
--hardreset
Git reset, step by step
Step 1: Unstage a file (reset the index for one file)
The most common everyday use: you staged something by accident and want to unstage it without changing the file.
Terminalgit reset HEAD src/config.ts# or with modern Git:git restore --staged src/config.tsTip: This doesn't change the file contents. It just removes it from the staging area.
Step 2: Undo the last commit, keep changes staged (--soft)
--softmoves HEAD back by one commit but leaves all changes staged. Useful when you want to rewrite the commit message or split the commit.Terminalgit reset --soft HEAD~1# Your changes are still staged - just re-commit:git commit -m "better message this time"Step 3: Undo the last commit, keep changes unstaged (--mixed)
--mixed(the default) moves HEAD back and unstages the changes. The files are still modified in your working directory.Terminalgit reset HEAD~1# equivalent to:git reset --mixed HEAD~1Tip: This is the safest way to undo a commit: you lose nothing, you just need to re-stage and re-commit.
Step 4: Undo the last commit AND discard all changes (--hard)
--hardmoves HEAD back and discards all changes in the staging area and working directory. The files are reverted to exactly the state they were in at the target commit.Terminalgit reset --hard HEAD~1Careful:
--hardpermanently discards uncommitted changes. There is no undo, unless you have the original SHA and usegit reflogto recover it. Use with extreme caution.In Gitoryx: Right-click any commit in the graph to reset to itHow it works Step 5: Reset to a specific commit
Instead of
HEAD~1, you can target any commit by its SHA.Terminalgit log --oneline# a3f2c1d add login form# 9b1e4fa init projectgit reset --soft 9b1e4faStep 6: Recover from an accidental --hard reset
If you ran
--hardby mistake, your commits are still in Git's reflog for 30 days. Find the SHA and reset back to it.Terminalgit reflog# HEAD@{1}: reset: moving to HEAD~1# a3f2c1d HEAD@{2}: commit: add login form ← this is what we lostgit reset --hard a3f2c1d
Mistakes to avoid with git reset
- Using --hard instead of --soft or --mixed
- Most of the time you want to undo a commit but keep the code.
--hardthrows the code away too. - Fix: Default to
--softor--mixed. Only use--hardwhen you're certain you want to discard the changes. - Resetting a pushed commit and force-pushing
- This rewrites shared history. Teammates whose branches are based on the old commit will have a diverged history and will be forced to reconcile it.
- Fix: Use
git revertfor commits already pushed to a shared branch. It creates a new commit that undoes the changes, without rewriting history. - Resetting too many commits back
- Using
HEAD~5when you meantHEAD~1undoes more history than intended. - Fix: Use
git log --onelineto count commits carefully, or use the exact SHA instead ofHEAD~N.
Git reset in Gitoryx
Gitoryx lets you right-click any commit in the graph and choose Reset to here (soft, mixed, or hard), with a clear description of what each mode will do before you confirm.
- Right-click any commit in the graph to reset to it
- Choose soft, mixed, or hard from a clear dropdown with descriptions
- The reflog is accessible in Gitoryx to recover from accidental resets
- Gitoryx warns you before a --hard reset that would discard changes
Free plan · no account required · macOS, Windows and Linux
Git reset: frequently asked questions
- What is the difference between git reset and git revert?
git resetmoves the branch pointer backwards, rewriting history.git revertcreates a new commit that undoes a previous commit's changes, preserving history. Useresetfor local commits; userevertfor pushed commits.- Can I recover from a git reset --hard?
- Yes, if you act quickly. Run
git reflogto find the SHA of the commit you lost, thengit reset --hard <sha>to restore it. Git keeps reflog entries for 30 days by default. - What does git reset HEAD~1 do?
- It moves the current branch back by one commit (--mixed by default). The changes from that commit are kept in your working directory but are no longer staged.
- How do I unstage a file without undoing a commit?
- Run
git reset HEAD <file>orgit restore --staged <file>(Git 2.23+). This removes the file from the staging area while keeping your changes intact.
Related reading
- Git Add: How to Stage Changes Before a CommitTutorial · 7 min
- Git Diff: See What Changed Before You CommitTutorial · 8 min
- How to Undo Almost Anything in GitBlog · 14 min