Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do changing adjacent lines but modifying independently cause a git merge conflict?

Tags:

git

Say I start out with one commit on master in test.txt with just the line Hello world! followed by a new line (to prevent any diffs happening on the first line when adding a second line).

Then, I branch off this commit with branch name modification. Here I change the file from

Hello world!

to

Hello world!
This is another line.

and then I commit to that branch.

Then I check out master and change the file from

Hello world!

to

Hello world! This is a new thing.

And then I commit that onto master. In summary, in both commits, I just change one line. Since I had the newline on master at the beginning, the extra commit on master only modifies line 1, while the commit on modification only modifies line 2. Hence, I don't see why this results in a merge conflict when I try to merge modification into master. However, I get this as the diff3 output.

<<<<<<< HEAD
Hello world! This is a new thing.
||||||| merged common ancestors
Hello world!
=======
Hello world!
This is another line.
>>>>>>> modification

Why wouldn't git realize that they're changing separate lines and merge those two together? I would think it would take line 1 modification from the commit on master and the line 2 modification on modification to form:

Hello world! This is a new thing.
This is another line.

The only possibility I can think of is there's something about modifying the same hunk regardless of the line number.

Interestingly, if instead on modifications I add This is another line. to line 3 instead of line 2, keeping that empty line on the modification branch, the merge continuous without conflicts.

like image 664
rb612 Avatar asked Mar 21 '19 07:03

rb612


People also ask

What happens when you merge two branches in Git?

I recently learned that when merging two branches in git, if there are changes on two adjacent lines git declares this a conflict. For example, if file test.txt has this content: and then attempt to merge testing into master, git declares a merge conflict. My naive expectation was that the merge would happen without conflict and yield this:

What is a merge conflict in Git?

I recently learned that when merging two branches in git, if there are changes on two adjacent lines git declares this a conflict. For example, if file test.txt has this content: and then attempt to merge testing into master, git declares a merge conflict.

Why doesn't Git automatically merge changes touching nearby lines?

In order to avoid causing such problems, git usually refuses to automatically merge changes touching nearby lines. It gives you a chance to verify whether the program logic would be broken or not.

What is the difference between >>== and new_branch_for_merge_conflict?

The ======= line is the “center” of the conflict. All the content between the center and the <<<<<<< HEAD line is content that exists in the current branch master which the HEAD ref is pointing to. Alternatively, all content between the center and >>>>>>> new_branch_for_merge_conflict is content that is present in our merging branch.


1 Answers

You have the right idea: Git declares a conflict if the two "sides" touch the "same lines" of the "same file", as compared to the contents of that file in the merge base commit. The trick lies in defining same file and same line. The merge base commit in this case—given your particular commits, that is—is your first commit ever, which had test.txt with one line in it, reading Hello world!. The two branch tips have test.txt with the other contents.

Philosophically speaking, defining same file is a hard problem: see the paradox of the Ship of Theseus. Git, however, just declares that if file test.txt exists in all three commits—in the merge base, and in both branch tip commits—then this is "the same file". So that clears that problem right up. 😀 However, "same line" is still a little fuzzy.

The change you made from the first commit ever to the first branch tip commit left line 1 alone but modified the end of the file, adding This is another line.

The change you made from the first commit ever to the second branch tip—the new master tip before the merge—changed line 1 itself.

Git gets a little squirrelly at the edges of a changed region—changes happen, in effect, between lines sometimes. Those changes touch both the above and below lines. Ultimately it's just a quirk of the algorithm chosen to decide whether the changes conflict: Git decides to say that these changes do touch the same line(s), while a different algorithm might say they don't.

(The edge effects arise from having to have nonempty intervals, to avoid fencepost issues. The various algorithms mostly use half-open intervals: a region starts at symbol X—lines act as symbols, here—and ends before symbol Y. The end of the file is usually assigned an EOF symbol for this purpose. Some algorithms like to have a symbol "above" the first line as well, as sort of an SOF, or Start Of File.)

like image 105
torek Avatar answered Oct 25 '22 03:10

torek