git reset --merge vs git reset --keep [duplicate]
I agree that the documentation is not very clear. From testing, I have found three differences, relating to what happens to files which:
- have staged changes
- no unstaged changes
In summary:
reset --merge
always discards the index (staged changes); aborts if unstaged and staged changes present on any filereset --keep
keeps, but unstages, the index; aborts if the reset target touches the same file
Test scenario:
echo First > file.txtgit add file.txtgit commit -m 'first'git tag v1echo Second >> file.txtgit commit -am 'second'git tag v2echo New > newfile.txtgit add newfile.txtgit commit -m 'third'git tag v3echo 'More stuff' >> file.txtgit add file.txt
We now have three commits, and 'file.txt' changes between v1 and v2, but does not change between commits v2 and v3.
No changes between index and new HEAD
In this situation:
git reset --merge v2
throws away those changesgit reset --keep v2
keeps them, but unstages them.
Changes between index and new HEAD
If we instead try to reset to v1:
git reset --merge v1
throws away the changesgit reset --keep v1
refuses:error: Entry 'file.txt' would be overwritten by merge. Cannot merge.fatal: Could not reset index file to revision 'v1'.
Changes between index and new HEAD, plus unstaged changes
git echo "Even more things" >> file.txt
Now, both fail, but with slightly different error messages:
git reset --merge v1
error: Entry 'file.txt' not uptodate. Cannot merge.fatal: Could not reset index file to revision 'v1'.
git reset --keep v1
error: Entry 'file.txt' would be overwritten by merge. Cannot merge.fatal: Could not reset index file to revision 'v1'.
Staged and unstaged changes to an unrelated file
echo Unrelated > unrelated.txtgit add unrelated.txtecho Stuff >> unrelated.txt
Now this is somewhat odd:
git reset --merge v1
error: Entry 'unrelated.txt' not uptodate. Cannot merge.fatal: Could not reset index file to revision 'v1'.
git reset --keep v1
Both sets of changes are kept, but unstaged.
No staged changes, but unstaged changes
For completeness, these both behave identically: the reset succeeds and the file remains unstaged.
They are different when dealing with a merge conflict, for example this will generate a conflict
git initecho 333 > foo.txtgit add foo.txtgit commit -m 333git checkout -b featureecho 444 > foo.txtgit commit -am 444git checkout masterecho 555 > foo.txtgit commit -am 555git merge feature
Then
$ git reset --keepfatal: Cannot do a keep reset in the middle of a merge.$ cat foo.txt<<<<<<< HEAD555=======444>>>>>>> feature
Versus
$ git reset --merge$ cat foo.txt555