nonopolarity
nonopolarity

Reputation: 151166

Why does a seemingly possible merge using Git have conflicts?

In short, why does a file foo.txt having content

a
b

failed to merge with the branch with foo.txt having content:

a

c

?

The longer version is: to experiment with Git and merging, I did the following:

  1. mkdir a new directory and cd into it and git init
  2. create a file foo.txt and add the line a (first time just like that, and second time with 2 empty lines after a)
  3. commit it, and now git checkout -b feature and git checkout -b sprint (so as far as I know, it makes no difference to do it in a row instead of first switching back to master and create sprint, because branches are created based on commitID, and either case, they are exactly the same.
  4. Now git co feature and make the file look like a and then empty line and then c on the third line
  5. Now commit it, and do git checkout sprint and make the file look like a and then next line b on its own.
  6. Now commit it, and now do a git merge feature

and supposedly, the merge could have succeeded, with the content

a
b
c

but why did it fail? Instead of guessing "maybe the lines are too close", can a more definitive answer from docs or reference be given?

I also tried adding an empty line between a and b, and between b and c so they are more spaced out, but without the initial empty lines in the first version of foo.txt, and the result was the same: merge conflict.

Upvotes: 3

Views: 882

Answers (4)

Schleis
Schleis

Reputation: 43760

The merge resulted in conflicts because on each of your branches you modified the file in almost the same way. Git could attempt to resolve the conflict itself but because any decision that it makes could be wrong, it is going to make you do it.

Git doesn't look at what was changed for each line. Only that a line was changed or added. In one branch you added a new line and on the other you added a character and a new line. In both branches you are adding a line immediately after the first and git wants you to determine which line should be in the file upon merge.

You would not have had a conflict because git would have seen independent changes in the file on each branch. But because there were changes on the same line in each branch git has a conflict and asks for your resolution.

Upvotes: 1

Edward Thomson
Edward Thomson

Reputation: 78753

As you posit, they're too close. Let's use a common-ancestor that doesn't have empty lines to avoid confusion. If you have some common ancestor:

line 1
line 2
line 3
line 4

And you edit both sides:

line 1
LINE TWO
line 3
line 4

And:

line 1
line 2
LINE THREE
line 4

Then the git diff/merge engine (xdiff) will produce a conflict. Though I could not find documentation on this, it can obviously be seen empirically. This is an implementation detail, though a common one.

If you think of the automerge as describing changed regions, described in relation to other regions (instead of lines, addressed by numbers) this might make more sense: the first side changes data after line 1 and before line 3. The second side changes data after line 2 and before line 4.

When you try to correlate these changes, though, you run into trouble: the first side has removed the context (line 3) that the second side relies on to describe its changes.

As long as there's some context (ie, the changes are not "too close") this should work, even if that context is a single line. To extend your example to where you are not changing immediately adjacent lines, if your common ancestor is:

a



d

And one side is:

a
b


d

The other side is:

a


c
d

Then this will automerge successfully as:

a
b

c
d

Upvotes: 2

Alex Wolf
Alex Wolf

Reputation: 20148

Git checks for differences on a line level. So lets say your fist version of the file looks like this:

a

Now you create a second version of the file on a branch named feature:

a
b

In this version you have changed two lines. Why two lines do you think? Well there was a newline character added \n at the end of a.

In the branch sprint you added another version of the file:

a

c

Now you modified three lines.

If you now try to merge the two modifications git recognizes that you changed line 1 and 2 in both commits, so git doesn't know which version to take and a conflict occurs.

Upvotes: 2

Farid Nouri Neshat
Farid Nouri Neshat

Reputation: 30430

Basically to git I believe every merge that has different histories is a conflict. But it will try to resolve as much it can by it's own. It will try to apply(using git apply) every change from the diff to the files of the target branch, but when the apply fails, it won't do anything anymore and it will let the programmer resolve it.

In your files, in branch feature, you have changed a\n\n to a\n\nc and in branch sprint you have changed a\n\n to a\nb\nc. To git by default empty lines and white space changes are significant. It cannot decide which change to apply, because they are both different and conflicting.

Upvotes: 0

Related Questions