We recently went through some merge issues with git, and while it probably did 'The Right Thing'(TM) it wasn't what I expected. I have reduced an issue to a small public github repository located at https://github.com/geretz/merge-quirk.
quirk.c exists on master. merge-src and merge-dst are both branched from the same version on master, which is the common ancestor for the eventual merge. merge-src adds a comment and some code. merge-dst reformats the code and changes the exiting comments but does not have the added comment or code.
git merge detects and declares a conflict.
git clone https://github.com/geretz/merge-quirk.git cd merge-quirk git checkout merge-dst git merge origin/merge-src Auto-merging quirk.c CONFLICT (content): Merge conflict in quirk.c Automatic merge failed; fix conflicts and then commit the result. However the thisLineMightDisapper (sic) function call will get lost if a naive/trusting developer chooses the origin/merge-src code block in the conflict flagged quirk.c .
In my mental model, if the thisLineMightDisapper function call exists in both HEAD and origin/src in conflicting states it should exist in both of the conflict blocks, if it doesn't exist in conflicting states it should exist outside of both conflict blocks. Why does it appear only inside the HEAD block ?
<<<<<<< HEAD // a few comment lines - change 1 // that existed - change 2 // in the common ancestor - change 3 // that get changed - change 4 if(1) { if (f(1, 2)) { if (thisLineMightDisapper(42)) ======= // a few comment lines // that existed // in the common ancestor // added this line in merge-src branch // that get changed if(1) { if (f(1, 2)) >>>>>>> origin/merge-src { t = time(0); } } } if (anotherFunction(1,2)) { t = time(0) f(0); } } The files
master/quirk.c
// a few comment lines // that existed // in the common ancestor // that get changed if(1) { if (f(1, 2)) { if (thisLineMightDisapper(42)) { t = time(0); } } } } merge-src/quirk.c
// a few comment lines // that existed // in the common ancestor // added this line in merge-src branch // that get changed if(1) { if (f(1, 2)) { if (thisLineMightDisapper(42)) { t = time(0); } } } if (anotherFunction(1,2)) { t = time(0) f(0); } } merge-dst/quirk.c
// a few comment lines - change 1 // that existed - change 2 // in the common ancestor - change 3 // that get changed - change 4 if(1) { if (f(1, 2)) { if (thisLineMightDisapper(42)) { t = time(0); } } } }
merge.conflictStyletodiff3as well: this shows what Git saw in the original (common base) file, vs the two end-points being merged, i.e., HEAD /--oursand other /--theirs. Note that if you are looking at the conflict now, and have not resolved it yet, you can also dogit checkout --conflict=diff3 quirk.cto replace its contents with a new conflicted-merge, but this time with the chosen style.