Jhon Piper
Jhon Piper

Reputation: 613

Oddness with git merges?

I'm new to git so this may seem simple to everyone else and I'm just not understanding.

I'm getting ready to start a project with 1 other friend and we've decided to use git as our version control system, so we've been running tests to see how this would work. Here's what we've tested with so far and where we're having issues:

We have 3 branches

Okay, so:

  1. I create a test.txt file directly in master before creating the other 2 branches and leave the txt empty.
  2. We create the other 2 branches and I checkout my branch write "Test 1" on line 1 with no other lines, then commit and merge it with master.
  3. My friend checkouts his branch and writes "Test 2" on line 1, and "Hotfix" on Line 3, then he commits and merges with master and gets a merge error because the 1 was changed to a 2 on line 1, and because Hotfix was added.

This is a little simplified compared to the tests we are running, but is git really not smart enough the recognize the difference when such a simple change has been made? I can see it asking if line 1 should have a 1 or a 2 but why is it complaining about Hotfix being added on a new line?

and I don't think it matters but we've tried the same tests in the Bash CLI for windows, Bash directly in Linux, Github for desktop, Gitkraken, and Gmaster, all to the same results.

Edit, for clarity sake here a a readout of what I did in the terminal: I explained what I did in the commit messages, and while I don't know how to display merge conflicts from the bash terminal, here is a screenshot on the conflict that it prints in vscode: https://i.sstatic.net/F6Iaw.jpg.

Also for more, clarity, when the .txt is created, there is 1 line, I put Test (number here) on that precreated line in both branches, and for the friends branch, I created line 2 and 3, and put Hotfix and line 3.

Upvotes: 1

Views: 81

Answers (1)

torek
torek

Reputation: 488073

Git believes that changes conflict with each other if they make different changes to the same original source line or if the two changes "touch" at the edges. The reason for the latter is that Git does not know what order to put them in.

That is, suppose that, starting from the same empty test.txt file, your change is:

+Test 1

(that is, add one line reading Test 1) and his change is:

+Test 2
+Hotfix

Git does not know whether to put your line first followed by his two lines, or his two lines first followed by your line.

You said that something he did changed "line 3" though. There is no line 3. Perhaps the original supposedly-empty file was actually one blank line? Then your change is:

-
+Test 1

That is, remove the empty line and put in the line reading Test 1. His change is now:

+Test 2

+Hotfix

(that is, keep the empty line, but add a first and third line). This change conflicts because you changed the blank line and he kept it, or—if we look at this a bit differently—he added a line above and below the blank line, while you changed the blank line. (Git doesn't look at changed lines, but rather only added and/or deleted lines, and that is another reason why changes that abut—that touch at edges like this—conflict.)

Either way, you would not have gotten a merge conflict had you changed lines that differed or did not "touch" each other. That is, suppose the original text.text file reads:

This test file
has several
lines in it.

You make a change that adds Test 1 at the top. He makes a change that adds Test 2 and Hotfix at the bottom. When Git compares the version of the file that you both started from—with its three lines—to your version, with four lines, and to his version, with five, Git sees that your change is to insert between "line 0" (top of file) and line 1, and his change is to insert after line 3 before "line 4" (bottom of file). These changes do not overlap, so Git can apply both changes to the original three-line file and come up with a six-line file reading:

Test 1
This test file
has several
lines in it.
Test 2
Hotfix

Think about the merge base

Another way to put all this is: Git is not adding his changes to your version of the file. Git is not adding your changes to his version of the file either. Git is finding the merge base version of the file.

Remember that every commit stores a full, complete snapshot of every file. So if Git can find any commit that you both had before you started working, whatever file we're wondering about, Git has some copy of the file in that commit.

The merge base is the "best" commit from which you both started—the one closest to what you both ended up with. Since you both started from the same commit, you both had the same version of this file. Git can therefore run two git diff operations. One finds what you changed. The other finds what he changed. Git's job is to combine the two sets of changes, and apply those combined changes to the base copy.

When these changes affect different lines and do not abut, Git can combine them on its own. When they affect the same lines, or do abut, Git cannot combine them on its own.

Upvotes: 5

Related Questions