What's the difference between git reset --hard and git reset --merge

Viewed 68864

In my experiments I haven't been able to find any functional difference between

git reset --hard

and

git reset --merge

The usage instructions don't give any hint either

--hard                reset HEAD, index and working tree
--merge               reset HEAD, index and working tree

I regularly use the --hard option so understand how that works. What's the difference between the --merge and the --hard options?

Cheers, Olly

Perhaps an example would help here, let's use the following sequence:

cd git_repo
touch file_one
git add file_one
git commit -m "commit one" # sha1 of 123abc
echo "one" >> ./file_one
git commit -a -m "commit two" # sha1 of 234bcd
echo "two" >> ./file_one
git add . # populate index with a change
echo "three" >> ./file_one # populate working area with a change

Now if I try

git reset --merge 123abc

I get

error: Entry 'file_one' not uptodate. Cannot merge.
fatal: Could not reset index file to revision '123abc'

the reason being that file_one has changes in both the working area and the index

To remedy this I do

git add .
git reset --merge 123abc

This time it works, however, I get the same result as git reset --hard. The index is empty, working area is empty, file_one is empty, as it was after first commit.

Can someone come up with the steps that illustrate the difference?

5 Answers

tl;dr git reset --merge is git reset --keep for undoing a merge. git reset --keep is git reset --hard that tries to preserve unstaged changes. Also, git reset --hard may change unstaged files (git-reset):

Any untracked files or directories in the way of writing any tracked files are simply deleted.

I think what you generally want to know about git reset --merge is covered by by @manojlds (changes in the working tree before a merge; a conflict or a clean merge). Because that looks like the use case for git reset --merge.

But you may also want to consider the following 2 cases:

  1. If you had no changes in the working tree before a merge, and you're in the middle of resolving a conflict, git reset --merge ORIG_HEAD is not much different from git reset --hard ORIG_HEAD. Unless you start working on a new feature at this point (make changes unrelated to resolving a conflict). That is, if you want to undo the merge, you most likely want to undo everything. And in this case you can simply do git merge --abort.

    But git reset --merge ORIG_HEAD will preserve unstaged changes in this case. Except for changes made to files with conflicts (discard), and changes made to staged files (abort).

    Although theoretically it may be handy, it doesn't sound like a use case for git reset --merge.

  2. If you're not in the middle of resolving a conflict, and want to git reset --merge to an arbitrary commit, it will try to preserve unstaged changes. But so will git reset --keep. The latter simply doesn't work in the middle of a merge, and ignores staged changes.

    They will abort if they can't preserve unstaged changes. That will happen if you changed a file that was also changed between HEAD and <commit>.

Related