I'm trying to resolve merge conflict in some files
both modified: myFile.h
I ran this command:
git checkout --ours myFile.h
after that I ran:
git status
It shows this:
both modified: myFile.h
Why still shows "both modified" ?
I'm trying to resolve merge conflict in some files
both modified: myFile.h
I ran this command:
git checkout --ours myFile.h
after that I ran:
git status
It shows this:
both modified: myFile.h
Why still shows "both modified" ?
Some git checkout
commands resolve a merge conflict, taking the version you checked out, and some don't. This is one of the cases that don't.
You must therefore mark the conflict as resolved manually, with: git add myFile.h
.
Merging (the action, i.e., merge-as-a-verb) is done through Git's index (also called the staging area or sometimes the cache). The index has one entry for each file that will go into the next commit you make. Normally, that one entry holds one file—but the index has four slots per entry, which are numbered. Slot zero (0
) is the normal "no conflict, file is ready to commit" slot. Slots 1, 2, and 3 are used only during a merge conflict, and contain the merge base version (slot 1), --ours
version (slot 2), and --theirs
version (slot 3).
If slot zero is filled, the other three slots are empty. If any of the other slots are filled, slot 0 is empty and the file is in "conflicted" state. (It's possible to have just two of the other three slots filled, as is the case for add/add, modify/delete, and rename/delete conflicts.)
When you run git checkout commit -- path
,1 Git copies a file from the given commit into slot zero, then from slot zero to the work-tree. Copying to slot zero wipes out slots 1-3 if they're filled, so the file is now resolved!
But, when you run git checkout --ours -- path
, Git doesn't have to write anything to index slot zero, it can just get the file's contents from slot 2. So it copies from slot 2 to the work-tree, and the file is not resolved.
Note that this means you can do git checkout HEAD -- path
to extract the file from the HEAD
commit, writing to slot zero and thus resolving as well as writing to the work-tree. This is subtly different in another way, though. Suppose that during the merge, Git decided that the file was renamed as well as being modified. It's taken the rename into account: the file's new name is evil/zorg
instead of the old name evil-zorg
. If you git checkout --ours
, Git will extract the old (HEAD) version of evil-zorg
under the new name evil/zorg
. If you git checkout HEAD
, Git won't find the file under the new name!
(This is another case of Git letting implementation details show through—or, equivalently, of cramming too much stuff into one command.)
1The reason for the --
is to handle a file whose name looks like an option. (For instance, what if the file's name is --theirs
?) If the path part doesn't look like an option, you don't need the --
. It's a good habit to pick up, though: use the --
every time and you won't be surprised someday when your file name does resemble an option.