git reset
does know five "modes": soft, mixed, hard, merge and keep. I will start with the first three, since these are the modes you'll usually encounter. After that you'll find a nice little a bonus, so stay tuned.
When using git reset --soft HEAD~1
you will remove the last commit from the current branch, but the file changes will stay in your working tree. Also the changes will stay on your index, so following with a git commit
will create a commit with the exact same changes as the commit you "removed" before.
This is the default mode and quite similar to soft. When "removing" a commit with git reset HEAD~1
you will still keep the changes in your working tree but not on the index; so if you want to "redo" the commit, you will have to add the changes (git add
) before commiting.
When using git reset --hard HEAD~1
you will lose all uncommited changes in addition to the changes introduced in the last commit. The changes won't stay in your working tree so doing a git status
command will tell you that you don't have any changes in your repository.
Tread carefully with this one. If you accidentally remove uncommited changes which were never tracked by git
(speak: committed or at least added to the index), you have no way of getting them back using git
.
git reset --keep HEAD~1
is an interesting and useful one. It only resets the files which are different between the current HEAD
and the given commit. It aborts the reset if one or more of these files has uncommited changes. It basically acts as a safer version of hard
.
You can read more about that in the git reset documentation.
Note
When doing git reset
to remove a commit the commit isn't really lost, there just is no reference pointing to it or any of it's children. You can still recover a commit which was "deleted" with git reset
by finding it's SHA-1 key, for example with a command such as git reflog
.