You made a few commits, realized they’re not quite right, and nothing has been pushed yet. Good news: you have several clean ways to unwind without breaking shared history. This guide shows each option, what it does, and exact commands.
TL;DR: Decide whether you want to discard the work, keep it unstaged, or keep it staged—then pick the matching reset mode below.
Quick safety net (recommended)
Before doing anything destructive, create a throwaway backup branch so you can recover with reflog or by checking out this branch.
|
1 2 3 |
# from your working branch git branch backup/undo-$(date +%F) |
Option A — Throw away local commits and changes
Use when: You want your local branch to exactly match the remote, losing all local commits and file changes.
|
1 2 3 4 5 6 |
# ensure you’re on the right branch git fetch origin git checkout <your-branch> git reset --hard origin/<your-branch> |
Effect:
- Local commits are discarded.
- Working tree and index are reset to the remote branch.
Recovery: Possible via git reflog, but assume the work is gone.
Option B — Drop the commits, keep changes unstaged
Use when: You want to rework the commits or split them up before recommitting.
|
1 2 3 4 5 |
git fetch origin git checkout <your-branch> git reset origin/<your-branch> # (aka --mixed; default) |
Effect:
- Commits are removed.
- All diffs land in your working directory as unstaged changes.
Option C — Drop the commits, keep changes staged
Use when: You want to immediately recommit in one or few commits.
|
1 2 3 4 5 |
git fetch origin git checkout <your-branch> git reset --soft origin/<your-branch> |
Effect:
- Commits are removed.
- All diffs move to the staging area.
Option D — Just peel back the last N commits
Use when: You know how many commits you want to undo from HEAD and you may want to keep (or drop) the changes.
|
1 2 3 4 5 6 7 8 9 |
# keep changes as unstaged edits git reset HEAD~N # keep changes staged for a fresh commit git reset --soft HEAD~N # discard changes too (destructive) git reset --hard HEAD~N |
Replace
Nwith the number of commits to remove, e.g.,HEAD~2.
In-progress operations
If you’re mid‑operation, bail out cleanly first:
|
1 2 3 4 5 6 |
# during a merge git merge --abort # during a rebase git rebase --abort |
Then apply the appropriate reset option above.
Verify before and after
See the local commits that are ahead of the remote:
|
1 2 3 4 |
git fetch origin git log --oneline origin/<your-branch>..HEAD |
Check workspace status:
|
1 2 |
git status |
Show what’s staged vs. unstaged:
|
1 2 3 |
git diff # unstaged diffs git diff --staged # staged diffs |
Common scenarios
“I committed to the wrong branch, nothing pushed.”
|
1 2 3 4 5 6 7 8 9 |
# move your work safely onto a new branch git branch work/miscommit # return original branch to remote state git reset --hard origin/<original-branch> # continue work on the new branch git checkout work/miscommit |
“I only want to drop the very last commit message (contents fine).”
|
1 2 3 |
# rewrite the last commit message (unpushed only!) git commit --amend |
“I need to surgically keep or drop parts of a commit.”
|
1 2 3 |
# after a mixed reset, interactively stage just what you want git add -p |
Safety notes
- Prefer
git revert <sha>for commits that have already been pushed and shared. git reset --hardis destructive. Make a backup branch and confirm withgit logandgit statusbefore running it.git reflogcan often rescue lost work:
|
1 2 3 |
git reflog # find the previous HEAD git reset --hard <reflog-sha> |
Cheatsheet
- Discard everything:
git reset --hard origin/<branch> - Keep changes (unstaged):
git reset origin/<branch> - Keep changes (staged):
git reset --soft origin/<branch> - Undo last N commits:
git reset [--soft|--hard] HEAD~N - Abort merge/rebase:
git merge --abort/git rebase --abort - Inspect ahead-of-remote:
git log --oneline origin/<branch>..HEAD
Have a twist on this scenario (worktrees, detached HEAD, or rebasing gone wild)? Drop a comment—we’ll add it to this guide.




