0

Today I tried to merge two branches and I ran into a conflict. I use the Visual Studio 2019 Team Explorer, and .gitconfig is set-up like this to launch KDiff3:

[merge]
    tool = kdiff3
[mergetool "kdiff3"]
    path = C:/Program Files/KDiff3/bin/kdiff3.exe
    trustExitCode = false

This has worked great until now, but today there were Git's conflict markers in the base version of the file. Something like this:

Common code
<<<<<<<<< Temporary merge branch 1
One version of code
=========
Another version of code
>>>>>>>>> Temporary merge branch 2
More common code

This never happened before. Aren't those markers only meant for merging manually using text files? Any idea on how to fix this?

EDIT:

Also, using git directly from command line has the same markers, but I have no idea if those were there before because I almost never use the command line. This is the command I used:

git mergetool -g FileName.cs
relatively_random
  • 4,505
  • 1
  • 26
  • 48

2 Answers2

0

Those markers are added by Git whenever there is a merge conflict. It is Git's way to make the location(s) of the conflict(s) easy to spot (by a human or a merge tool) and to show the alternative versions.

Merge tools detect these markers and make it easier for the user to compare versions and choose the one they prefer. GUI tools such as KDiff3 usually hide the markers and present the alternative versions in different panes. Once the user has resolved the conflict, the merge tool deletes the lines with the markers.

Other tools allow to easily jump from conflict to conflict, highlight the alternative versions in different colors, and have keybindings to easily resolve the conflict, but they do not hide those Git conflict markers from the user (e.g. ediff).

In any event, whether you see them or not (depending on the merge tool you use), they are there until the conflict gets resolved.

I don't know what went wrong this time with KDiff3, but it is very easy to fix manually:

You can simply open the file with any text editor, delete the lines

<<<<<<<<< Temporary merge branch 1
=========
>>>>>>>>> Temporary merge branch 2

and choose either One version of code, Another version of code, or a combination of the two (or something else entirely).

Once you are done, save the file, run:

git add <file>

(this tells Git that you have resolved the conflict), then:

git commit

You don't have to enter a commit message because Git will automatically offer you a merge commit message (that you can accept or modify).

Et voilà.

prosoitos
  • 6,679
  • 5
  • 27
  • 41
  • Are you sure 3-way merge tools know anything about conflict markers? I don't think that's how they work. They take three files, without markers, as input and produce an output file. – relatively_random Oct 08 '20 at 07:53
  • Hmmm. I thought they did, but reading your answer below, I realized that I probably understood wrongly how they work under the hood. Thanks for making me question my prior understanding. I don't use a GUI merge tool myself and I should look more into it. – prosoitos Oct 08 '20 at 14:28
  • Have a look at [this question](https://softwarerecs.stackexchange.com/q/49512/62709) – prosoitos Oct 08 '20 at 14:44
  • [The answer](https://softwarerecs.stackexchange.com/a/49528/62709) says the same thing I wrote: "kdiff3 will try to merge for you the trivial stuff and will present you a 4 panes window to resolve the non trivial stuff, based on git merge failures annotations." – prosoitos Oct 08 '20 at 14:48
  • The answer is correct, but that doesn't mean that KDiff3 interprets the conflict markers. Normally, the markers are not even there when the external tool is launched. Git generates three files, calls the merge tool and tells it where to put the input. When the merge tool closes, git asks you if you wish to accept the generated output file. You can see the three git-generated files in the file system (with suffixes: base, local and remote), if you look while the merge tool is still running. – relatively_random Oct 08 '20 at 18:30
0

Turns out this doesn't happen on normal conflicts, this was just a case of a convoluted tree of merges. For normal merge conflicts with an obvious single common ancestor, git generates three simple files for merge tools to look at. When you have multiple common ancestors for a conflict, it leaves in some markers in the "base" file.

relatively_random
  • 4,505
  • 1
  • 26
  • 48
  • I am not sure this is how it works either: Git does leave those markers whenever there is a merge conflict. You don't need convoluted trees and multiple common ancestors for this to happen. – prosoitos Oct 08 '20 at 14:36
  • Whenever Git has to stop in the process of creating a merge commit because there is a conflict on at least one hunk of one of the files, Git puts in those markers. I could be totally wrong in how the fancy GUI merge tools work under the hood, but I am sure that Git does this. – prosoitos Oct 08 '20 at 14:38
  • It is very hard to find info on how the fancy merge tools work under the hood. But it is easy to see what Git does: in your Git config file, remove your merge tool conf and play with Git without merge tools. Create simple merge conflicts and look at what Git does. – prosoitos Oct 08 '20 at 14:51
  • @prosoitos I just realized there are comments here too. They're not that fancy really. They work without Git and they have existed before Git. They take three files: a common ancestor (A) and two versions (B and C). Then they look through the files line by line. If a line is the same in A and B and different in C, it outputs the line from C (this means C modified something that B hasn't touched since the common ancestor A). If B and C are the same and A is different, it means both versions made the same edit and picks that. Otherwise it shows you a conflict and you need to decide. – relatively_random Oct 08 '20 at 18:54
  • @prosoitos https://git-scm.com/docs/git-mergetool "When git mergetool is invoked with this tool (...) the configured command line will be invoked with $BASE set to the name of a *temporary file containing the common base for the merge*, if available; $LOCAL set to the name of a *temporary file containing the contents of the file on the current branch*; $REMOTE set to the name of a *temporary file containing the contents of the file to be merged*, and $MERGED set to the *name of the file to which the merge tool should write* the result of the merge resolution." – relatively_random Oct 08 '20 at 18:59
  • Cool. Thank you for the link and info. They take over what Git normally does. I had the chronology wrong and I didn't know they worked this way. This was interesting! Part of my answer is actually wrong then. – prosoitos Oct 08 '20 at 21:24