0

If the conflict happen on a binary or any non-text files that can't be resolved by using text editor, I should use git checkout --theirs or git checkout --ours instead, then add them into the staging area.

But, if I just do nothing, add those unmerged binaries into staging area directly, without resolving the conflict, without choosing a proper version, which version will be added into staging area ? Ours or theirs ?

Unmerged paths:
  (use "git add/rm <file>..." as appropriate to mark resolution)

      both modified: test.bin
      both modified: test.a 
Corey
  • 1,217
  • 3
  • 22
  • 39
  • 2
    i guess the question to ask is: where did those binaries come from? That might help you decide what you should use there. In general, if the .bin or .a file came up from the source you are tracking with git, they should not be tracked at all. – eftshift0 Feb 26 '19 at 01:55
  • 1
    Yeah...in general don't version binary files if at all possible. I'm not sure Git's diff tool would handle them very well. – Tim Biegeleisen Feb 26 '19 at 01:58
  • @eftshift0 In fact, those binaries updated form thirty-party(other coworkers) regularly, so I can't build them by myself. – Corey Feb 26 '19 at 02:13

2 Answers2

1

There are times when it is appropriate to check in a binary file, images, videos, office documents... but they cannot be merged. You have to pick one or the other or make a new version.

But these look like build artifacts; files generated as part of the build process. Those should not be checked in. They will fall out of date with their source code, and they will be different on different people's machines who have different compilers and different libraries.

Remove them with git rm and then add them to the project's .gitignore so they don't come back. You'll probably want to ignore entire classes of files like *.a and *.o and *.bin. gitignore.io can generate a good starting ignore file for your project.

Schwern
  • 153,029
  • 25
  • 195
  • 336
1

If the conflict happen on a binary or any non-text files that can't be resolved by using text editor, I should use git checkout --theirs or git checkout --ours instead ...

This is not necessarily true. Just as with plain text files, where sometimes the correct resolution is in fact a combined change, the correct resolution of some binary files may be a combined change. It's just that Git cannot do this for you. The only way to do it correctly may be to find a source file or files, and some sort of source-to-binary translator. You may need to combine the source changes, compile / translate the result to a new, third binary, and use that.

Nonetheless, this question has an answer. It just may be pointless to study and memorize it.

But, if I just do nothing, add those unmerged binaries into staging area directly ...

What git add does is to copy whatever is in the work-tree into the index / staging-area at slot zero, removing any higher-stage entries. What you have during the conflict is three different binaries, in the index / staging area, but using slots 1 (merge base), 2 (ours), and 3 (theirs).

Hence, this just means Copy the work-tree file into slot zero and remove the entries in slots 1, 2, and 3. So the question is the same as:

What does Git leave in the work-tree in the case of a conflict in a binary file?

The answer to that is in both the git merge documentation and the gitattributes documentation. This makes it hard to read.

The first one says, regarding the recursive and resolve strategies, that there are additional arguments that affect the result. These additional arguments are the -X ours and -X theirs arguments, which mean:

ours
This option forces conflicting hunks to be auto-resolved cleanly by favoring our version. Changes from the other tree that do not conflict with our side are reflected to the merge result. For a binary file, the entire contents are taken from our side.
...
theirs
This is the opposite of ours; note that, unlike ours, there is no theirs merge strategy to confuse this merge option with.

The gitattributes documentation adds this:

Performing a three-way merge
...
The attribute merge affects how three versions of a file are merged when a file-level merge is necessary ...

and then goes on to say that most of them "[k]eep the version from your branch in the work tree". So in general the work-tree matches index-slot-2, which you can test by doing git checkout-index --temp --stage=2 test.bin and comparing the resulting file to test.bin.

It's not clear whether such attributes override -X theirs; you will have to test this, if you set your own merge attributes and use -X theirs, by comparing what's in the work-tree against what's in index slots 2 and 3.

In general, though, most approaches mostly leave the "ours" version in the work-tree. If that's appropriate, you can use git add to copy the work-tree version back to slot zero and erase slots 1-3, marking the file as resolved. Just be sure that if you have used -X theirs and/or some sort of interesting merge setting, that you know what you are doing and have double checked everything.

(Your best bet, of course, is to avoid merging binary files this way.)

torek
  • 448,244
  • 59
  • 642
  • 775
  • So, in my case, add unmerged binaries into staging area directly will keep the version from my branch in the work tree, which matches index-slot-2 (ours), am I right ? – Corey Feb 26 '19 at 03:25
  • Generally, I'd expect so. It may be worth double-checking. – torek Feb 26 '19 at 05:03