[git] Practical uses of git reset --soft?

I have been working with git for just over a month. Indeed I have used reset for the first time only yesterday, but the soft reset still doesn't make much sense to me.

I understand I can use the soft reset to edit a commit without altering the index or the working directory, as I would with git commit --amend.

Are these two commands really the same (reset --soft vs commit --amend)? Any reason to use one or the other in practical terms? And more importantly, are there any other uses for reset --soft apart from amending a commit?

This question is related to git

The answer is


Another use case is when you want to replace the other branch with yours in a pull request, for example, lets say that you have a software with features A, B, C in develop.

You are developing with the next version and you:

  • Removed feature B

  • Added feature D

In the process, develop just added hotfixes for feature B.

You can merge develop into next, but that can be messy sometimes, but you can also use git reset --soft origin/develop and create a commit with your changes and the branch is mergeable without conflicts and keep your changes.

It turns out that git reset --soft is a handy command. I personally use it a lot to squash commits that dont have "completed work" like "WIP" so when I open the pull request, all my commits are understandable.


I use it to amend more than just the last commit.

Let's say I made a mistake in commit A and then made commit B. Now I can only amend B. So I do git reset --soft HEAD^^, I correct and re-commit A and then re-commit B.

Of course, it's not very convenient for large commits… but you shouldn't do large commits anyway ;-)


You can use git reset --soft to change the version you want to have as parent for the changes you have in your index and working tree. The cases where this is useful are rare. Sometimes you might decide that the changes you have in your working tree should belong onto a different branch. Or you can use this as a simple way to collapse several commits into one (similar to squash/fold).

See this answer by VonC for a practical example: Squash the first two commits in Git?


Use Case - Combine a series of local commits

"Oops. Those three commits could be just one."

So, undo the last 3 (or whatever) commits (without affecting the index nor working directory). Then commit all the changes as one.

E.g.

> git add -A; git commit -m "Start here."
> git add -A; git commit -m "One"
> git add -A; git commit -m "Two"
> git add -A' git commit -m "Three"
> git log --oneline --graph -4 --decorate

> * da883dc (HEAD, master) Three
> * 92d3eb7 Two
> * c6e82d3 One
> * e1e8042 Start here.

> git reset --soft HEAD~3
> git log --oneline --graph -1 --decorate

> * e1e8042 Start here.

Now all your changes are preserved and ready to be committed as one.

Short answers to your questions

Are these two commands really the same (reset --soft vs commit --amend)?

  • No.

Any reason to use one or the other in practical terms?

  • commit --amend to add/rm files from the very last commit or to change its message.
  • reset --soft <commit> to combine several sequential commits into a new one.

And more importantly, are there any other uses for reset --soft apart from amending a commit?

  • See other answers :)

Another potential use is as an alternative to stashing (which some people don't like, see e.g. https://codingkilledthecat.wordpress.com/2012/04/27/git-stash-pop-considered-harmful/).

For example, if I'm working on a branch and need to fix something urgently on master, I can just do:

git commit -am "In progress."

then checkout master and do the fix. When I'm done, I return to my branch and do

git reset --soft HEAD~1

to continue working where I left off.


One possible usage would be when you want to continue your work on a different machine. It would work like this:

  1. Checkout a new branch with a stash-like name,

    git checkout -b <branchname>_stash
    
  2. Push your stash branch up,

    git push -u origin <branchname>_stash
    
  3. Switch to your other machine.

  4. Pull down both your stash and existing branches,

    git checkout <branchname>_stash; git checkout <branchname>
    
  5. You should be on your existing branch now. Merge in the changes from the stash branch,

    git merge <branchname>_stash
    
  6. Soft reset your existing branch to 1 before your merge,

    git reset --soft HEAD^
    
  7. Remove your stash branch,

    git branch -d <branchname>_stash
    
  8. Also remove your stash branch from origin,

    git push origin :<branchname>_stash
    
  9. Continue working with your changes as if you had stashed them normally.

I think, in the future, GitHub and co. should offer this "remote stash" functionality in fewer steps.


While I really like the answers in this thread, I use git reset --soft for a slightly different, but a very practical scenario nevertheless.

I use an IDE for development which has a good diff tool for showing changes (staged and unstaged) after my last commit. Now, most of my tasks involve multiple commits. For example, let's say I make 5 commits to complete a particular task. I use the diff tool in the IDE during every incremental commit from 1-5 to look at my changes from the last commit. I find it a very helpful way to review my changes before committing.

But at the end of my task, when I want to see all my changes together (from before 1st commit), to do a self code-review before making a pull request, I would only see the changes from my previous commit (after commit 4) and not changes from all the commits of my current task.

So I use git reset --soft HEAD~4 to go back 4 commits. This lets me see all the changes together. When I am confident of my changes, I can then do git reset HEAD@{1} and push it to remote confidently.


One practical use is if you have committed to your local repo already (ie. git commit -m ) then you can reverse that last commit by doing git reset --soft HEAD~1

Also for your knowledge, if you have staged your changes already (ie with git add .) then you can reverse the staging by doing git reset --mixed HEAD or i've commonly also just used git reset

lastly, git reset --hard wipes everything out including your local changes. The ~ after head tells you how many commits to go to from the top.


SourceTree is a git GUI which has a pretty convenient interface for staging just the bits you want. It does not have anything remotely similar for amending a proper revision.

So git reset --soft HEAD~1 is much more useful than commit --amend in this scenario. I can undo the commit, get all the changes back into the staging area, and resume tweaking the staged bits using SourceTree.

Really, it seems to me that commit --amend is the more redundant command of the two, but git is git and does not shy away from similar commands that do slightly different things.


A great reason to use 'git reset --soft <sha1>' is to move HEAD in a bare repo.

If you try to use the --mixed or --hard option, you'll get an error since you're trying to modify and working tree and/or index that does not exist.

Note: You will need to do this directly from the bare repo.

Note Again: You will need to make sure the branch you want to reset in the bare repo is the active branch. If not, follow VonC's answer on how to update the active branch in a bare repo when you have direct access to the repo.