Git commands
How git reset --soft folds commits back into the staging area
git reset --soft: uncommit without touching a file
How to use this page
- slider / ▶Drag the slider, or press play, to watch the command happen. Before and After jump to either end.
- ← → · spaceStep through a multi-step command; space toggles Before / After.
- APlay or pause the loop (the page opens playing). Any manual input takes over.
- hoverA commit shows its message, author, date and parents, with its history highlighted.
- clickCopies the commit sha.
- ctrl + wheelZoom around the cursor (pinch on a trackpad). Double-click resets the view.
- EscStop playback, reset the view, close this menu.
- shareThe Share button copies a link to this graph, copies it as an image, downloads PNG/SVG/page, or posts it. #before, #after or #step=N in the link pins the state.
git-sim visually simulates any Git command in your own repos - from your terminal, IDE, or AI.
Table of Contents
- Introduction
- What is git reset --soft?
- Watch it happen
- Before and after
- The three resets side by side
- Is it safe?
- How to undo it
- Try it on your repository
- Common questions
- Summary
- Next steps
- Related commands
Introduction
Of the three kinds of git reset, --soft is the gentle one. It moves the branch pointer and stops there. Your staging area and your files stay exactly as they are, which means the changes from the commit you just undid are still staged, waiting to be committed again, differently.
In this article, we'll:
- Watch
git reset --soft HEAD~1movemainback one commit - See where the undone commit's changes end up
- Compare it with
--mixedand--hard, and look at the two jobs--softis best at
What is git reset --soft?
git reset --soft <commit> points the current branch (and so HEAD) at <commit> and does nothing else. The staging area still holds the tree of the commit you were on, and the working directory is untouched. From the staging area's point of view, everything that was in the undone commits is now "staged and not yet committed".
Watch it happen
Our sample repo has a clean working tree on main. Here's git reset --soft HEAD~1:
- Before:
HEADis attached tomainat8c02d5b, "Update dependencies", the commit that addedrequirements.txt. mainmoves back one commit to "Add user settings page", andHEADmoves with it.- The index and working tree are left alone, so
requirements.txtis now a staged new file, waiting to be committed again. No other ref moves.
Before and after
main is one commit shorter. Now look at git status, which was clean before and now reads:
A requirements.txt
"Update dependencies" added requirements.txt. That file is still on disk and still in the staging area, shown as a staged addition, because --soft didn't touch either. Run git commit right now and you'd get that commit back, with whatever message you like.
The raw git output, if you want to read along in text
git log --oneline --graph --all
before
* 1117a34 (feature) Add search tests
* e5869f0 Fix typo in search box
* fc19889 Add search box
| * 8c02d5b (HEAD -> main) Update dependencies
| * a0b2db3 Add user settings page
|/
* 96c4fc2 Fix header layout
* ae65976 Add login page
* 3e1ffe4 Add project skeleton
* 4114b2c Initial commitafter
* 1117a34 (feature) Add search tests
* e5869f0 Fix typo in search box
* fc19889 Add search box
| * a0b2db3 (HEAD -> main) Add user settings page
|/
* 96c4fc2 Fix header layout
* ae65976 Add login page
* 3e1ffe4 Add project skeleton
* 4114b2c Initial commitThe three resets side by side
All three move the branch. They differ in how much else they reset:
| branch | staging area | working directory | |
|---|---|---|---|
--soft | moved | kept | kept |
--mixed (default) | moved | reset to the commit | kept |
--hard | moved | reset to the commit | reset to the commit |
--soft is the one to use when the changes were right and only the commit was wrong: wrong message, wrong grouping, committed too early.
git reset --soft HEAD~3 followed by one git commit is my quick way to squash the last few commits when I don't need the control of an interactive rebase. The three commits' changes land in the staging area together, and one new commit records them as one.
Is it safe?
Caution git-sim pre-flight
Moves main from 8c02d5b to a0b2db3 (soft reset).
What you would lose
- 1 commit(s) removed from branch main
The way back
Commits stay in the reflog ~90 days: git reset --hard 8c02d5b
The commit leaves the branch but stays in the reflog, and every change it contained is still staged. --soft cannot lose file contents.
How to undo it
git reset --soft 8c02d5b
moves main forward again onto the original commit. Because the staging area already matches it, this brings you back exactly.
Try it on your repository
pip install git-sim
git-sim reset --soft HEAD~1
git-sim shows where the branch would land and lists the commits that would leave it, and confirms that the index and working tree stay as they are.
Common questions
What does git reset --soft do?
It moves the current branch to the given commit and leaves the staging area and working directory unchanged. The undone commits' changes remain staged.
What is the difference between git reset --soft and --mixed?
--mixed (the default) also resets the staging area to match the target commit, so the undone changes become unstaged edits. --soft keeps them staged.
How do I undo the last commit but keep the changes?
git reset --soft HEAD~1 keeps them staged, and git reset HEAD~1 keeps them as unstaged edits.
Can I use git reset --soft to squash commits?
Yes. git reset --soft HEAD~N followed by git commit combines the last N commits into one.
Summary
In this article, we watched git reset --soft move main back one commit while leaving the undone change staged, compared the three reset modes, and saw how --soft doubles as a quick squash.
Next steps
git reset covers the default mode, and git commit --amend is the shortcut when only the last commit needs changing.
Related commands
- git reset, the default that also unstages
- git reset --hard, the one that touches files
- git commit --amend, to fix just the last commit
- git rebase -i, to squash with more control
- git reflog, to find the undone commit again
- git commit, to record the staged changes anew
