Table of Contents

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:

  1. Watch git reset --soft HEAD~1 move main back one commit
  2. See where the undone commit's changes end up
  3. Compare it with --mixed and --hard, and look at the two jobs --soft is 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:

  1. Before: HEAD is attached to main at 8c02d5b, "Update dependencies", the commit that added requirements.txt.
  2. main moves back one commit to "Add user settings page", and HEAD moves with it.
  3. The index and working tree are left alone, so requirements.txt is 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 commit

after

* 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 commit

The three resets side by side

All three move the branch. They differ in how much else they reset:

branchstaging areaworking directory
--softmovedkeptkept
--mixed (default)movedreset to the commitkept
--hardmovedreset to the commitreset 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.