6

In the git docs (and numerous SO threads) this reset approach is recommended:

$ git reset --soft HEAD^ ;# go back to WIP state  <2>
$ git reset                                       <3>

.2. This removes the WIP commit from the commit history, and sets your working tree to the state just before you made that snapshot.

.3. At this point the index file still has all the WIP changes you committed as snapshot WIP. This updates the index to show your WIP files as uncommitted.

https://www.kernel.org/pub/software/scm/git/docs/git-reset.html

Obviously that's fine, but it seems that these two commands could be replaced by

$ git reset HEAD^

(which is equivalent to)

$ git reset --mixed HEAD^

which should reset both the HEAD pointer and the index to the previous commit. Is there in fact a difference between the result of this command and the previous two? If not, is there some reason to prefer the two-stage process? Or was it just done that way in the docs to explicitly illustrate the behavior of --soft?

Nathan Stretch
  • 1,028
  • 1
  • 11
  • 23

1 Answers1

5

No, there doesn't seem to be any difference.
It is more to illustrate the git reset --soft (i.e. moving HEAD only, which can have other more practical uses)

git reset HEAD is for "unstaging", and a simple git reset HEAD^ does both (move the HEAD, and unstage, no need for --mixed, since it is the default option)


Here is a quick test to see what that looks like:

Before (you just switch back to feature, where you committed a "wip" -- work in progress):

C:\Users\VonC\prog\git\test\r\r3>gl
* 6ac95bd - (origin/master, origin/HEAD, master) fix in master (2 minutes ago) <VonC>
| * fd8d97d - (HEAD, origin/feature, feature) snap WIP (3 minutes ago) <VonC>
| * 16066dd - f1 (3 minutes ago) <VonC>
|/
* e8ad96f - f1 (3 minutes ago) <VonC>

The reset itself:

C:\Users\VonC\prog\git\test\r\r3>git reset "HEAD^"
Unstaged changes after reset:
M       f

That gives you the status:

C:\Users\VonC\prog\git\test\r\r3>git st
# On branch feature
# Your branch is behind 'origin/feature' by 1 commit, and can be fast-forwarded.
#   (use "git pull" to update your local branch)
#
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   f
#
no changes added to commit (use "git add" and/or "git commit -a")

log after git reset HEAD^

C:\Users\VonC\prog\git\test\r\r3>gl
* 6ac95bd - (origin/master, origin/HEAD, master) fix in master (6 minutes ago) <VonC>
| * fd8d97d - (origin/feature) snap WIP (7 minutes ago) <VonC>
| * 16066dd - (HEAD, feature) f1 (7 minutes ago) <VonC>
|/
* e8ad96f - f1 (8 minutes ago) <VonC>

In two steps, you would have seen the following log after the git reset --soft HEAD^:

C:\Users\VonC\prog\git\test\r\r2>gl
* 6ac95bd - (origin/master, origin/HEAD, master) fix in master (65 seconds ago) <VonC>
| * fd8d97d - (origin/feature) snap WIP (89 seconds ago) <VonC>
| * 16066dd - (HEAD, feature) f1 (2 minutes ago) <VonC>
|/
* e8ad96f - f1 (2 minutes ago) <VonC>

You index would still reflect what was staged for wip:

C:\Users\VonC\prog\git\test\r\r2>git st
# On branch feature
# Your branch is behind 'origin/feature' by 1 commit, and can be fast-forwarded.
#   (use "git pull" to update your local branch)
#
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   f
#

The reset would then unstaged, bringing you back to the same stage than a git reset HEAD^ would have in one step:

C:\Users\VonC\prog\git\test\r\r2>git reset
Unstaged changes after reset:
M       f

C:\Users\VonC\prog\git\test\r\r2>git st
# On branch feature
# Your branch is behind 'origin/feature' by 1 commit, and can be fast-forwarded.
#   (use "git pull" to update your local branch)
#
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   f
#
no changes added to commit (use "git add" and/or "git commit -a")
Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Thanks for the confirmation. And certainly there are other uses for git reset --soft. (In the most basic case, there's often simply no reason to reset the index as well, in which case --soft will save you having to re-stage the files.) But good to know for sure that there's no need for the two-stage process if you're planning to reset the index as well anyway. Why type more characters than necessary? – Nathan Stretch Jul 21 '13 at 20:00
  • @NathanStretch I agree. It is more to give a choice (in case you committed a work in progress composed of evolutions that should be staged, and *other* evolutions that should be staged *separately*: then, you unstage everything, and `git add` what you want to commit first in your wip. – VonC Jul 21 '13 at 20:14