git reset
Advanced Git CLI Careful
Summary: git reset <target> moves the current branch to another commit. The mode decides what happens to the change that was in the commits you moved past: --soft keeps it staged, --mixed (the default) keeps it in your files unstaged, --hard discards it. git reset <file> is a different job entirely: it unstages that file.
Careful — --hard overwrites uncommitted work with no way back, and every mode rewrites history, so none of them belongs on a pushed branch.
What it does
Points the current branch at the commit you name, then optionally updates the staging area and the working tree to match. The commits it moves past are not deleted; they simply have no branch pointing at them and stay in the repository, findable through git reflog.
Why it exists
Branches are pointers, so "undo the last commit" is really "move the pointer back". Reset is that move, and its three modes exist because there are three sensible answers to "and what should happen to the change?".
When to use it
- Redo the last commit differently, before pushing:
--soft. - Rebuild a commit from its files, staging deliberately:
--mixed. - Throw away local commits and their changes entirely:
--hard, after checkinggit status. - Make your branch match the server exactly:
git reset --hard origin/main. - Unstage one file:
git reset <file>, thoughgit restore --stagedsays it more clearly.
When not to use it
- On a commit that has been pushed:
git revertinstead. - When you only want a file back:
git restore. - With uncommitted work you care about:
git stashfirst.
Syntax
| Form | Effect |
|---|---|
git reset --soft <target> |
Branch moves; changes stay staged |
git reset <target> |
Branch moves; changes stay in the files, unstaged (--mixed) |
git reset --hard <target> |
Branch moves; staging area and working tree overwritten |
git reset --keep <target> |
Like --hard, but refuses if it would overwrite local changes |
git reset <file> |
Unstage that file; the branch does not move |
git reset |
Unstage everything |
Targets: HEAD~1, a hash, origin/main, ORIG_HEAD, HEAD@{2}.
Examples
Redo the last commit, keeping everything staged:
$ git reset --soft HEAD~1
$ git status --shortM docs/getting-started.mdThe default, leaving the change unstaged:
$ git reset HEAD~1Unstaged changes after reset:
M docs/getting-started.mdDiscard the commit and its change:
$ git reset --hard HEAD~1HEAD is now at d3b92ec chore: add CI configuration and contributing guideUnstage one file:
$ git add docs/faq.md
$ git reset docs/faq.mdUnstaged changes after reset:
M docs/faq.mdExpected result
git log --oneline -1 shows the target commit, and git status shows the change in the place the mode chose: staged, unstaged, or nowhere.
Try it here
The simulator below runs a small model of Git in the page. Nothing here touches a real repository, so try the command, then try it wrong (lesson 2.8 explains it).
The Git state simulator loads here.
Common mistakes
--hardwith uncommitted work open. It is discarded silently, and the reflog does not cover it.- Counting
HEAD~nwrongly. Checkgit log --onelinefirst, or name a hash. - Using reset on a pushed branch, which then needs a force push (lesson 12.8).
- Confusing
git reset <file>withgit reset --hard. The first only unstages. - Expecting the commits to be gone. They are unreferenced, not deleted, until garbage collection.
How to undo or recover
git reset --hard ORIG_HEADreturns you to where you were before the last reset, merge, rebase or pull.- Otherwise
git reflog, find the position you wanted, and reset to it. - Uncommitted changes destroyed by
--hardare not recoverable through Git; IntelliJ's Local History or VS Code's Timeline may have them.
In VS Code
Undo Last Commit in the Source Control ⋯ menu is git reset --soft HEAD~1. The other modes are not exposed; use the built-in terminal.
In IntelliJ IDEA
Right-click a commit in the Log → Reset Current Branch to Here…, then choose Soft, Mixed, Hard or Keep, each explained in the dialog.
Related commands
git restore for files rather than branches · git revert for pushed commits · git reflog to find where you were · git stash to park work before resetting.