8

For example:

  • I have a master branch.
  • I create a file file.txt and I write Master branch in it, and then I commit it.
  • I create another branch called fix20, and modify the text of file.txt to This is fix20 branch. Then I commit it.
  • I switch to the master branch and then I create a branch hotfix and switch to it.
  • I modify file.txt to have the text This is the HotFix. After that I commit the changes.
  • Now I switch back to the master branch and merge it with the hotfix. The file (with no problems) changes it text to This is the HotFix (They are basically merged)).

Now I merge with the fix20 branch and I get a merging conflict. The file.txt has both the text from fix20 branch and the text, that I had after merging with HotFix. At this point, I should open an editor and decide, what should be left, and what should be removed.

The question is: Why does the merging conflict happen the second time? Why didnt I decide which text to leave, when I merged the master with the hotfix? Why havent the files been merged, when I merged with fix20 branch (why the text was not just replaced as with the hotfix)? Why basically this conflict happens the second time and not the first one???

Simon Warta
  • 10,850
  • 5
  • 40
  • 78
MyOwnFan
  • 117
  • 1
  • 7
  • 1
    branch fix20 has a diferent commit history than the master branch, which master does not have, git (or any other version tool) cannot know if you want to keep both texts or just one of them – Nikos M. Jan 03 '16 at 11:04
  • @NikosM. Then why is the question on what do I want to keep, does not appear when I merge it with the hotfix?? – MyOwnFan Jan 03 '16 at 11:07
  • because master changed a certain commit but fix20 has another one as well, so the tool cannot know – Nikos M. Jan 03 '16 at 11:12
  • @NikosM. Is it like the situation, when there is a need for rebasing? – MyOwnFan Jan 03 '16 at 11:14
  • not necessarily, except if you want to rebase the branch, eg you may need to just add to the branch, but not rebase – Nikos M. Jan 03 '16 at 11:26

2 Answers2

12

The problem here is that you know your intention... but Git doesn't.

This is how Git looks at what you did: you made two independent changes to the same line. When you merge the first one, your intention is clear: you want the change to become part of master. Since there haven't been any changes in master itself since you branched off, there is no problem with that: Git can always directly merge a piece of code if only one side of the merge changed it.

When you try to merge your second change, that is no longer true: by merging the first branch, you have introduced changes to master that are not directly "compatible" with the changes in the second branch. Git calls this: "the branches have diverged". Git doesn't know whether you'd rather keep the stuff you merged from the first branch, or the stuff you are merging from the second branch.

In your situation it's obvious to you because the second branch is a newer fix of the same thing... but many merges involve more complicated changes to the code, and maybe the correct way to merge the second branch is to combine the changes from the two merges: often, if two merged changes touch the same line of code, both will have to leave their marks on it.

Example original code:

send_request("bake cookies")

Branch 1:

send_request("bake cookies", additions: ["chocolate"])

Branch 2:

send_request("bake cookies", flour: "wheat")

The correct way to merge both of these probably isn't to take one of the two lines verbatim, it's probably more like this:

send_request("bake cookies", flour: "wheat", additions: ["chocolate"])

Since you know the intention of your code much better than Git, Git will never make an automatic decision in this kind of situation.

Jan Krüger
  • 17,870
  • 3
  • 59
  • 51
  • 1
    i would add that git like any version tool works with (sequences of) diffs, **diffs describe what changed to what**. In the case of master the diff is clear, the one line changed to another, but in the case of branch, the diff cannot apply as is (**note**, the same happens with all version tools since they use diff patterns, not only with git). Each version history in a tool is just a series of diffs (applied in sequence), git differs from other tools in other respects but not this – Nikos M. Jan 03 '16 at 13:38
3

Read this answer for full details. Its the same problem that you have but in a slightly different scenario


In short:

The answer is that there is a conflict because there isn't any merge-base commit for the 2 branches.


Here are the steps you described

enter image description here


Im using 3-diff ads the diff algorithm

Here is the content of the file:

<<<<<<< HEAD
This is hotfix branch
||||||| merged common ancestors
Master branch
=======
This is fix20 branch
>>>>>>> fix20

I have tried to generate some graphical presentation of your problem but it takes too much time.

Ill try to answer here as clear as i can be.

Since you have several branches whenever you do a merge git try to find out where was the split done (on which commit you have derived and opened the new branch). Then from this point it generates the diff and trying to merge the files.

I our case we have this:

master            master  master
   \----- hotfix --- /     |
   |                       |
   \----- fix20  ----------/


// To view the patch that will be created for the merge you can run
// this command and you will see the commits that will be merged.
git log ^master fix20 

In your case you will see that its trying to merge a commit which updated the same file (both branches were created from the same commit [merge-base commit]) and it results in conflict.

Community
  • 1
  • 1
CodeWizard
  • 128,036
  • 21
  • 144
  • 167