Brydon Gibson Brydon Gibson - 25 days ago 5
Git Question

Merging with git - how do I figure out where the 'new' code ends?

Another user on my git created a branch and can't figure out how to merge it through eclipse. I'm therefore merging it with master.

To start :

git pull origin master
git pull origin garbage (this is what his branch is named)


I get a merge conflict in a file. Usually I can figure these out if I wrote all the code, but in this case I can't. It looks like this:

<<<<<<<<<<<HEAD
//a bunch of code
=========
>>>>>>>>>>> A bunch of numbers (I'm assuming the hash of the new branch)
//code that I didn't write
//the rest of the code


I can't find the gap between
code I didn't write
and
rest of code
. Shouldn't there be another
========
line after the 'new' code? What's the best way to go about merging this?

Answer

This particular conflict style shows just two parts of the conflict—but there are actually three parts, it's just that one usually is to be thrown away.

Remember that there is a "base" version of the file, and two tip versions. The base version is what you started with before you made your changes on master—and he started with the same base version before he made his changes. That's what makes the base version "the base": you both had that same file, in its same form, some time in the past.

Since then—since that common base—Git looks at this as "you made some number of commits (at least 1, perhaps many), and he made some commits (at least one, perhaps many)":

          o--o--A   <-- you (master)
         /
...--o--*
         \
          o--o--o--B   <-- him

To combine these changes, Git runs a diff from * (the base) to A (your master), and a second diff from * to B (his garbage, which you'll generally be calling origin/garbage instead). Git found some sort of conflict between "what you did" and "what he did", and put this into the combined (mostly-finished) file using the conflict markers:

[there might be stuff up here too]
<<<<<<<<<<< HEAD
//a bunch of code
=========
>>>>>>>>>>> A bunch of numbers (I'm assuming the hash of the new branch)
//code that I didn't write
//the rest of the code

This is Git's best guess as to the final form of the file, resolving the parts that didn't conflict, while leaving the parts that did conflict in there as both sets of code. There's one big piece missing: what did Git think you both started with?

Let's say, for instance, that Git erroneously decided that you both kept the 17th completely-blank line, because your new file has a blank line near there and his new file has a blank line near there (even though in fact that's just an accidental match). Git was then able to decide that everything he did after that blank line did not conflict, so that's in your combined file, but not marked with a conflict marker.

Meanwhile, Git decided that, because of this "kept" blank line, you added the first // a bunch of code section, that he didn't. (This might actually have been in the original file, but when Git mis-synchronized, it wound up "looking new". Or it could really be all new.)

After that part, between the initial <<< chevrons and the === line, Git includes the code that it thinks he added: that's whatever is after the === line, up to the >>> line. (In this case, it thinks he did not add anything here: probably, it thinks he deleted something, such as a blank line.)

The rest of the code, including the // code that [you] didn't write, was either in the base already, or Git was able to add without seeing a conflict.

I find it better to set merge.conflictstyle to diff3. This changes how Git inserts the two conflicting sections into the mostly-final file: it puts in the part it could handle on its own, then the <<<<<<< marker, then what it thinks you added if anything, then a series of vertical bars |||||||, then the base code that Git thinks is to be replaced, then the ======= marker, then his code, then the closing >>>>>>> marker.

Git thinks it likely that you will get rid of the base code and use one or the other of the HEAD or other branch code sections, or perhaps even a mix of both HEAD and other. But if the base section turns out to be utter nonsense, you can immediately tell that Git synchronized on something bogus, like blank lines and lines consisting only of a }, for instance.