git reset is all about moving HEAD, and generally the branch ref.
Question: what about the working tree and index?
When employed with --soft, moves HEAD, most often updating the branch ref, and only the HEAD.
This differs from commit --amend as:

  • it doesn't create a new commit.
  • it can actually move HEAD to any commit (as commit --amend is only about not moving HEAD, while allowing to redo the current commit)

Just found this example of combining:

  • a classic merge
  • a subtree merge

All into one (octopus, since there are more than two branches merged) commit merge.

Tomas "wereHamster" Carnecky explains in his "Subtree Octopus merge" article:

  • The subtree merge strategy can be used if you want to merge one project into a subdirectory of another project, and the subsequently keep the subproject up to date. It is an alternative to git submodules.
  • The octopus merge strategy can be used to merge three or more branches. The normal strategy can merge only two branches and if you try to merge more than that, git automatically falls back to the octopus strategy.

The problem is that you can choose only one strategy. But I wanted to combine the two in order to get a clean history in which the whole repository is atomically updated to a new version.

I have a superproject, let's call it projectA, and a subproject, projectB, that I merged into a subdirectory of projectA.

(that's the subtree merge part)

I'm also maintaining a few local commits.
ProjectA is regularly updated, projectB has a new version every couple days or weeks and usually depends on a particular version of projectA.

When I decide to update both projects, I don't simply pull from projectA and projectB as that would create two commits for what should be an atomic update of the whole project.
Instead, I create a single merge commit which combines projectA, projectB and my local commits.
The tricky part here is that this is an octopus merge (three heads), but projectB needs to be merged with the subtree strategy. So this is what I do:

# Merge projectA with the default strategy:
git merge projectA/master

# Merge projectB with the subtree strategy:
git merge -s subtree projectB/master

Here the author used a reset --hard, and then read-tree to restore what the first two merges had done to the working tree and index, but that is where reset --soft can help:
How do I redo those two merges, which have worked, i.e. my working tree and index are fine, but without having to record those two commits?

# Move the HEAD, and just the HEAD, two commits back!
git reset --soft HEAD@{2}

Now, we can resume Tomas's solution:

# Pretend that we just did an octopus merge with three heads:
echo $(git rev-parse projectA/master) > .git/MERGE_HEAD
echo $(git rev-parse projectB/master) >> .git/MERGE_HEAD

# And finally do the commit:
git commit

So, each time:

  • you are satisfied with what you end up with (in terms of working tree and index)
  • you are not satisfied with all the commits that took you to get there:

git reset --soft is the answer.


Note that --no-soft does not make sense, and Git 2.42 (Q3 2023) tells you so now.

See commit 3821eb6 (19 Jul 2023) by Junio C Hamano (gitster).
(Merged by Junio C Hamano -- gitster -- in commit e672bc4, 27 Jul 2023)

e672bc4f76:Merge branch 'jc/parse-options-reset'

Command line parser fix. * jc/parse-options-reset: reset: reject --no-(mixed|soft|hard|merge|keep) option

You would get an "unknown option" error.

Answer from VonC on Stack Overflow
Top answer
1 of 13
156

git reset is all about moving HEAD, and generally the branch ref.
Question: what about the working tree and index?
When employed with --soft, moves HEAD, most often updating the branch ref, and only the HEAD.
This differs from commit --amend as:

  • it doesn't create a new commit.
  • it can actually move HEAD to any commit (as commit --amend is only about not moving HEAD, while allowing to redo the current commit)

Just found this example of combining:

  • a classic merge
  • a subtree merge

All into one (octopus, since there are more than two branches merged) commit merge.

Tomas "wereHamster" Carnecky explains in his "Subtree Octopus merge" article:

  • The subtree merge strategy can be used if you want to merge one project into a subdirectory of another project, and the subsequently keep the subproject up to date. It is an alternative to git submodules.
  • The octopus merge strategy can be used to merge three or more branches. The normal strategy can merge only two branches and if you try to merge more than that, git automatically falls back to the octopus strategy.

The problem is that you can choose only one strategy. But I wanted to combine the two in order to get a clean history in which the whole repository is atomically updated to a new version.

I have a superproject, let's call it projectA, and a subproject, projectB, that I merged into a subdirectory of projectA.

(that's the subtree merge part)

I'm also maintaining a few local commits.
ProjectA is regularly updated, projectB has a new version every couple days or weeks and usually depends on a particular version of projectA.

When I decide to update both projects, I don't simply pull from projectA and projectB as that would create two commits for what should be an atomic update of the whole project.
Instead, I create a single merge commit which combines projectA, projectB and my local commits.
The tricky part here is that this is an octopus merge (three heads), but projectB needs to be merged with the subtree strategy. So this is what I do:

# Merge projectA with the default strategy:
git merge projectA/master

# Merge projectB with the subtree strategy:
git merge -s subtree projectB/master

Here the author used a reset --hard, and then read-tree to restore what the first two merges had done to the working tree and index, but that is where reset --soft can help:
How do I redo those two merges, which have worked, i.e. my working tree and index are fine, but without having to record those two commits?

# Move the HEAD, and just the HEAD, two commits back!
git reset --soft HEAD@{2}

Now, we can resume Tomas's solution:

# Pretend that we just did an octopus merge with three heads:
echo $(git rev-parse projectA/master) > .git/MERGE_HEAD
echo $(git rev-parse projectB/master) >> .git/MERGE_HEAD

# And finally do the commit:
git commit

So, each time:

  • you are satisfied with what you end up with (in terms of working tree and index)
  • you are not satisfied with all the commits that took you to get there:

git reset --soft is the answer.


Note that --no-soft does not make sense, and Git 2.42 (Q3 2023) tells you so now.

See commit 3821eb6 (19 Jul 2023) by Junio C Hamano (gitster).
(Merged by Junio C Hamano -- gitster -- in commit e672bc4, 27 Jul 2023)

e672bc4f76:Merge branch 'jc/parse-options-reset'

Command line parser fix. * jc/parse-options-reset: reset: reject --no-(mixed|soft|hard|merge|keep) option

You would get an "unknown option" error.

2 of 13
92

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 :)
🌐
DataCamp
datacamp.com › tutorial › git-reset-soft-complete-guide
Git Reset Soft: Complete Guide with Examples | DataCamp
September 16, 2025 - When I use git reset --soft HEAD~2, running git status shows everything is ready. This command undoes two commits while keeping changes staged. I can then use git add .
Discussions

git reset --soft HEAD~1
Sometimes, I accidentally commit into a Branch I don't have permission to. This is because I need to create a new branch, switch to it, commit my changes there, and do a pull request. When this acc... More on github.com
🌐 github.com
5
January 29, 2020
`git reset --soft` instead of `git rebase -i HEAD~N`
Merging the upstream into your feature is a pretty controversial thing to do! More on reddit.com
🌐 r/git
9
6
June 30, 2023
Is my understanding of Git Reset Correct?
git reset --hard resets changes in the current working directory. If I'm ever in doubt about git and can't be bothered reading the documentation (the man pages are actually pretty good, but still...), I just make a new git, commit some meaningless text, and try out the command. More on reddit.com
🌐 r/git
16
15
August 26, 2021
How to Undo "git reset -HEAD~"?
Find the commit hash you want to reset to with git reflog, then do a git reset [hash]. On mobile so sorry for formatting More on reddit.com
🌐 r/Frontend
11
13
October 17, 2022
🌐
Git
git-scm.com › docs › git-reset
Git - git-reset Documentation
$ git switch feature ;# you were working in "feature" branch and $ work work work ;# got interrupted $ git commit -a -m "snapshot WIP" (1) $ git switch master $ fix fix fix $ git commit ;# commit with real log $ git switch feature $ git reset --soft HEAD^ ;# go back to WIP state (2) $ git reset (3)
🌐
Built In
builtin.com › software-engineering-perspectives › git-reset-soft-head
How to Undo the Last Commit Using Git Reset Command | Built In
git reset --soft: Moves HEAD to the previous commit, but leaves staging area and working directory unchanged.
🌐
Graphite
graphite.com › guides › git-soft-reset
How to use git soft reset
Each affects the current branch and staging area differently: Soft reset (--soft): This type of reset moves the current branch's HEAD to a specified commit but does not alter the index (staging area) or the working directory.
Find elsewhere
🌐
GeeksforGeeks
geeksforgeeks.org › git › practical-uses-of-git-reset-soft
Practical Uses Of 'git reset --soft'? - GeeksforGeeks
September 3, 2024 - You can use git reset --soft to unstage the commit while keeping the changes intact. This command will reset your branch to the previous commit (HEAD~1), but your changes will still be staged.
🌐
GitKraken
gitkraken.com › home › learn › git reset
Git Reset | Hard, Soft & Mixed | Learn Git
March 26, 2026 - If HEAD is pointed at f30ab when we start, and then perform a git reset –soft 98ca9, HEAD will move to that commit, along with the pointer that points to the last commit of the chain (in this instance, called main).
🌐
Codidact
software.codidact.com › posts › 286550
Is it possible to undo a git reset? - Software Development
All git reset does is change what commit the HEAD references. If you find the hash corresponding to the commit you'd like HEAD to reference, you could just git reset --soft <commit hash>.
🌐
Atlassian
atlassian.com › git › tutorials › undoing changes › git reset
Git Reset | Atlassian Git Tutorial
1$ git reset --soft 2$ git status 3On branch main 4Changes to be committed: 5 (use "git reset HEAD ..." to unstage) 6 7modified: reset_lifecycle_file 8$ git ls-files -s 9100644 67cc52710639e5da6b515416fd779d0741e3762e 0 reset_lifecycle_file
🌐
GitHub
github.com › desktop › desktop › issues › 9005
git reset --soft HEAD~1 · Issue #9005 · desktop/desktop
January 29, 2020 - When this accident happens, I always have to Google how to undo a commit: git reset --soft HEAD~1 Because, when I use the "Revert this commit" option, GitHub Desktop does not keep the changes staged and automatically creates an extra commit.
Author   desktop
🌐
Diekmeier
diekmeier.de › posts › 2023-01-04-git-reset-soft
Undo your last commit with `git reset --soft "HEAD^"` for a better™ stash workflow – diekmeier.de
January 3, 2023 - By using --soft here, we bring back the changes to the working directory, and with "HEAD^", we only undo the last commit. ... wip = !"[[ $(git log -1 --pretty=%B) == \"WIP\" ]] && (git reset --soft \"HEAD^\") || (git add .
🌐
Atlassian
atlassian.com › git › tutorials › resetting checking out and reverting
Resetting, Checking Out & Reverting | Atlassian Git Tutorial
December 16, 2025 - The --soft, --mixed, and --hard flags do not have any effect on the file-level version of git reset, as the staged snapshot is always updated, and the working directory is never updated.
🌐
Medium
medium.com › @krejjas › using-git-reset-soft-50b8bc004327
Using Git reset — soft
December 25, 2024 - Suppose we want to revert to commit c1, so index.html contains only line with 1. We will use git reset command with — soft switch, followed by the number of steps, or commit undos we want to perform.
🌐
Graphite
graphite.com › guides › how-to-use-git-reset-head
How to use Git reset HEAD
This can happen when you checkout a specific commit. To avoid this, always checkout branches or create a new branch when checking out a specific commit. Use --soft when you want to undo a commit but keep changes staged
🌐
Coderwall
coderwall.com › p › e8oqzg › git-undo-git-reset
Git: Undo git reset (Example)
November 21, 2022 - but git reset HEAD@{1} after doing git reset HEAD~1, doesn't make sense to me and didn't undo the reset
🌐
freeCodeCamp
freecodecamp.org › news › git-reset-hard-how-to-reset-to-head-in-git
Git Reset Hard – How to Reset to Head in Git
April 10, 2023 - Be aware that the git reset –hard HEAD or git reset –hard HEAD@{n} command would remove your uncommitted changes, even if you staged them. If you don’t want your unstaged changes to be removed, you can use the --soft flag instead of the --hard flag.
🌐
Reddit
reddit.com › r/git › `git reset --soft` instead of `git rebase -i head~n`
r/git on Reddit: `git reset --soft` instead of `git rebase -i HEAD~N`
June 30, 2023 -

The project I currently work at wants PRs to get squashed before the commit, according to those guidelines:

https://www.kubernetes.dev/docs/guide/github-workflow/#squash-commits

This suggests to use git rebase -i HEAD~N.

The question is how to get to the number N.

It is quite easy if you don't have merges in your branch.

If you merged the upstream branch into your branch while developing, it is not that easy to get to the number N. At least I have found no easy way.

I discovered:

git reset --soft $(git merge-base main HEAD)

This works fine, except that I need to create the commit message again, but that's no big issue.

Question:

Does above reset --soft way of squashing all commits of a branch has any draw-backs?

Up to now it worked fine, but maybe there are cases where this method could fail?

🌐
DataCamp
datacamp.com › tutorial › git-reset-revert-tutorial
Git Reset and Revert Tutorial for Beginners | DataCamp
December 16, 2022 - git reset --soft <commit ID> moves back to the head with the <commit ID>. Let’s look at some examples. git add data_acquisition.py data_preprocessing.py git commit -m "added data acquisition and preprocessing scripts" This is the result of the previous command.