| Tested on | RHEL 10.2 (Coughlan) |
|---|---|
| Package | git 2.52.0 |
| Applies to | Any host with Git installed |
| Privilege | Normal user |
| Scope | git reset modes and common scenarios — undo local commits, unstage paths, discard tracked edits with --hard HEAD, and align with a remote after fetch. Brief reset-versus-revert and reflog pointers — not a full history-rewrite or reflog tutorial. |
| Related guides | Git discard changes Git revert examples Git unstage files Git reflog tutorial Git remove commit |
git reset lets you move back to an earlier commit. Depending on the mode you choose, Git can keep your changes staged, keep them only in your files, or discard them completely. It can also unstage a file after git add without moving your branch at all.
In Git terms, the staging area is where changes sit after git add (ready to commit). The working tree is your actual files on disk. Reset always affects one or both of those — plus your branch position when you reset to an older commit.
HEAD means the commit your branch currently points to. HEAD~1 means one commit before it, and HEAD~2 means two commits before it.
Each section below stands alone. Read the decision table first, pick the row that matches what you want, then jump to that section.
Choose the Right Reset Mode
| Your goal | Mode | Command |
|---|---|---|
| Undo last commit; keep changes staged | --soft |
git reset --soft HEAD~1 |
| Undo last commit; keep edits unstaged on disk | --mixed (default) |
git reset HEAD~1 |
| Undo last commit; drop those changes entirely | --hard |
git reset --hard HEAD~1 |
| Unstage one file; keep the same commits | --mixed at current commit |
git reset HEAD file |
| Unstage everything; keep the same commits | --mixed at current commit |
git reset |
| Throw away all uncommitted edits; keep the same commits | --hard at current commit |
git reset --hard HEAD |
| Move branch back N commits | any mode | git reset [--soft|--mixed|--hard] HEAD~N |
| Match remote after fetch | --hard |
git fetch origin then git reset --hard origin/main |
| Undo on a shared branch without rewriting history | use revert | git revert <commit> — see Git revert examples |
On modern Git, unstage-only work can also use git restore --staged — see Git unstage files. To discard current local edits without moving commits, see Git discard changes.
What git reset Changes
Think of --soft, --mixed, and --hard as three levels of undo when you move your branch to an earlier commit:
--soft— undo the commit, but keep everything ready to commit again (still staged aftergit add).--mixed— undo the commit and unstage the changes, but keep your edited files on disk.--hard— undo the commit and throw away the changes in your files too.
When you specify a filename, Git uses the file-only form of reset, which only changes the staging area. It does not move your branch to another commit:
git reset HEAD app.txt--soft and --hard are available only when resetting the repository to a commit — not when you pass a filename.
Technical mapping — if you already know Git’s internal names:
| Mode | Branch (HEAD) |
Staging area (index) | Working tree (files on disk) |
|---|---|---|---|
--soft |
moves to target commit | unchanged | unchanged |
--mixed |
moves to target commit | reset to match target | unchanged |
--hard |
moves to target commit | reset to match target | reset to match target |
For --mixed, Git removes the commit and takes its changes out of the staging area, but the edits remain in your files. Technically, Git resets the index to the target commit while leaving the working tree unchanged.
When the target is your current commit — git reset --hard HEAD — the branch does not move. You stay on the same commit; Git only clears uncommitted staged and on-disk changes in tracked files.
Undo the Last Commit
Scenario: you committed too early. Your latest commit is 5a7c04b Third commit and you want it off the branch — but you may still need the file changes. Each example below starts from that state; run one mode, not all three in a row.
Keep changes staged (--soft)
When to use this: you will fix the commit message or tweak the files and commit again right away.
git reset --soft HEAD~1The last commit disappears from your branch, but Git keeps the changes staged (ready for git commit):
git status -sb## main
M app.txtgit log --oneline now shows Second commit as the latest — not Third commit.
Keep changes in your files but unstaged (--mixed)
When to use this: you want the edits in your files, but not staged — this is the default when you omit --soft or --hard. Git removes the commit and takes its changes out of the staging area, but the edits stay in your files.
git reset HEAD~1Git may print that it unstaged files after removing the commit:
Unstaged changes after reset:
M app.txtIn git status -sb, the first column should be blank — the M moves to the second column, meaning the edit is only in your file, not staged:
git status -sb## main
M app.txtDrop the commit and the edits (--hard)
When to use this: the last commit and everything in it should be gone.
git reset --hard HEAD~1HEAD is now at 4d23291 Second commitYour files should now match Second commit with nothing left over from Third commit:
git status -sb## mainUnstage a File Without Removing Commits
Scenario: you ran git add and want one file out of the staging area before you commit. Status shows M in the first column:
## main
M app.txtWhen you give git reset a filename, Git does not move your branch to another commit. It only removes that file from the staging area:
git reset HEAD app.txtUnstaged changes after reset:
M app.txtThe edit is still in the file; it is just no longer staged:
git status -sb## main
M app.txtTo unstage every staged file at once:
git resetThat clears the staging area back to the current commit. It does not delete any commits.
Discard All Uncommitted Edits
Scenario: you have local changes (staged, unstaged, or both) and want your tracked files to match the last commit. You are not trying to remove commits from history.
git reset --hard HEADHEAD is now at 4d23291 Second commitYou should still be on the same commit — only your uncommitted work is gone:
git status -sb## maingit reset --hard HEAD usually leaves unrelated untracked files (?? in status) alone. Use git clean when you want those removed on purpose. Git may delete an untracked file if it would block updating a tracked file. To drop changes in one file without touching the rest of the repo, see Git discard changes.
Move the Branch Back Further
Scenario: you need to remove more than one recent commit, or jump back to a specific commit hash from git log.
To drop the last two commits but keep the file edits (unstaged):
git reset HEAD~2To jump back to one exact commit and delete local edits — check the hash with Git show command first if you are unsure:
git reset --hard c86447aHEAD is now at c86447a Initial commitSame three modes as undoing one commit (--soft, --mixed, --hard) — only the commit you target changes.
Match the Remote Branch After Fetch
Scenario: the copy on the server is correct and your local branch is wrong — extra commits, local edits, or both.
Download the latest remote state without merging:
git fetch originUse the next command when you want to throw away your local version of the branch and make it exactly match the remote branch. Replace main with your branch name:
git reset --hard origin/mainHEAD is now at 91b8fc5 Remote moved forwardThis makes your current branch and tracked files match origin/main. Local-only commits and tracked staged or unstaged edits are discarded. Untracked files may remain — run git status and use git clean if you also need ?? paths removed. Commits you lost may still show up in git reflog for a while — see Git reflog tutorial if you need to recover one.
Only do this on a branch you control. If you already pushed the commits you are removing, teammates may be affected — Git revert examples is often safer on shared branches.
Shared Branches: Reset vs Revert
Scenario: the bad commit is already on main (or another branch your team pulls from).
If the commit has already been pushed and other people may be using it, normally use git revert instead of reset. Revert creates a new undo commit, while reset moves your branch backward and can require a force push to publish the change.
Use reset on a local feature branch you have not shared. Use revert on branches the whole team uses — see Git revert examples.
Recover After a Mistaken Reset
Scenario: you ran git reset --hard to the wrong place and want your previous latest commit back.
A reset can remove a commit from the normal branch history, but Git often remembers the old branch position temporarily in the reflog. List those recent positions:
git reflog4d23291 HEAD@{0}: reset: moving to HEAD~1
5a7c04b HEAD@{1}: commit: Third commit
4d23291 HEAD@{2}: commit: Second commitRead it from the top: HEAD@{0} is where you are now (after the mistaken reset, on Second commit). HEAD@{1} is where you were one step ago — still on Third commit at 5a7c04b.
Find the reflog entry that contains the commit you want, then reset to that entry. In this example, it is HEAD@{1}:
git reset --hard HEAD@{1}That puts Third commit back at the tip of your branch. Reflog entries do not last forever — see Git reflog tutorial for a full recovery walkthrough.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
fatal: Cannot do hard reset with paths |
--hard with a file path |
Use git reset --hard without paths, or git restore --staged --worktree file for one file |
fatal: Cannot do soft reset with paths |
--soft with a file path |
Use git reset --soft HEAD~1 at commit level, or git reset HEAD file to unstage |
| Reset removed the commit but changes are still staged | You used --soft |
Expected — use --mixed or --hard if you wanted unstaged or deleted edits |
git reset --hard HEAD but unrelated ?? files remain |
Reset usually does not remove arbitrary untracked files | Run git clean -fd after git clean -n when you want them gone |
| Teammates broken after you reset a pushed branch | Shared history was rewritten | Prefer git revert on team branches |
References
Git documentation: git-reset
Git documentation: git-revert
Git documentation: git-reflog
Git documentation: git-restore
Git documentation: git-fetch
Summary
git reset answers three common questions: how do I undo a commit, how do I unstage after git add, and how do I throw away uncommitted edits? The --soft, --mixed, and --hard flags control what survives when you move your branch to an older commit — changes remain staged (--soft), changes remain in your files but become unstaged (--mixed), or tracked changes are discarded (--hard).
git reset HEAD file and plain git reset only unstage; they do not remove commits. git reset --hard HEAD clears uncommitted work while staying on the same commit. After git fetch, git reset --hard origin/main makes your branch and tracked files match the server and drops local-only commits and edits; untracked files may remain.
On branches your team shares, prefer git revert over reset. If you reset to the wrong commit by mistake, git reflog lists recent branch positions — find the entry with the commit you want, then reset to that entry (for example HEAD@{1} in the walkthrough above).

