Reputation: 151166
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:
mkdir
a new directory and cd
into it and git init
foo.txt
and add the line a
(first time just like that, and second time with 2 empty lines after a
)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.git co feature
and make the file look like a
and then empty line and then c
on the third linegit checkout sprint
and make the file look like a
and then next line b
on its own.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
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
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
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
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