When you modify a file in your repository, the change is initially unstaged. In order to commit it, you must stage it—that is, add it to the index—using git add
. When you make a commit, the changes that are committed are those that have been added to the index.1
git reset
changes, at minimum, where the current branch2 is pointing. The difference between --mixed
and --soft
is whether or not your index is also modified. So, if we're on branch master
with this series of commits:
- A - B - C (master)
HEAD
(the current commit) is C
3 and the index matches C
(assuming we haven't staged any changes with git add
).
When we run git reset --soft B
, master
(and thus HEAD
, indirectly) now points to B
, but the index still has the changes from C
; git status
will show them as staged. So if we run git commit
at this point, we'll get a new commit with the same changes as C
.
(If we did have staged changes before the reset, those will still be in the index and git commit
would commit those changes in addition to the changes from C
.)
Okay, so starting from here again:
- A - B - C (master)
Now let's do git reset --mixed B
. (--mixed
is the default option, so this is equivalent to git reset B
). Once again, master
and HEAD
point to B
, but this time the index is also modified to match B
. If we run git commit
at this point, nothing will happen since the index matches HEAD
. We still have the changes in the working directory, but since they're not in the index, git status
shows them as unstaged. To commit them, you would git add
and then commit as usual.
(This time, if we had staged changes before the reset, those changes will be removed from the index, but the files themselves will still contain any changes that were made.)
And finally, --hard
is the same as --mixed
(it changes your HEAD
and index), except that --hard
also modifies your working directory. If we're at C
and run git reset --hard B
, then the changes added in C
, as well as any uncommitted changes you've made, will be removed, and the files in your working copy will match commit B
. Since you can permanently lose changes this way, you should always run git status
before doing a hard reset to make sure your working directory is clean or that you're okay with losing your uncommitted changes.
In each of the above cases, we specified a commit (B
) to reset to. If you don't provide one, it uses HEAD
as the default. git reset --soft
with no commit specified doesn't do anything (it makes the current branch point to where it was already pointing), but it can be useful for the other two modes. git reset --mixed
(or just git reset
) updates the index to match the current commit, which has the effect of unstaging any changes that have been added but not committed; git reset --hard
does the same, plus it removes any changes in your working directory so that all your files match the latest commit on your current branch. (Again, since those changes are permanently lost, you should be careful when doing a hard reset.)
1 The index is also referred to as the "staging area". You can think of it as another copy of all the files in the repository. When a branch is checked out, the index is updated so that all its files match the contents of that branch. When you git add
a file, any changes you made to that file are copied to the index, and when you git commit
, the contents of the index are turned into a commit and added to the current branch.
2 HEAD
is how Git refers to the commit that is currently checked out. HEAD
(in most cases) points to a specific branch, called the current branch, and that branch points to a specific commit.
3 Because HEAD
points to master
and master
points to C
. Whenever we add or remove a commit on the current branch, the commit that HEAD
refers to changes not because HEAD
itself changed, but because the branch that HEAD
points to was updated to point to that commit.
soft: stage everything
,mixed: unstage everything
,hard: ignore everything
up to the commit I'm resetting from. – TenaciousDavid Zych
with clear explanation - davidzych.com/difference-between-git-reset-soft-mixed-and-hard – Denunciatorygit reset
here. – Coprophagousgit reset
meansgit reset --mixed
! – Painless