Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Git merge strategies: spaces make default shows no conflict and bring unexpected results

After many trials, I got this simple test case scenario:

a --> b --> c --   (master)
 \              \
  --> d --> b' --> e   (branch)

Where:

  • b' is a cherry pick of b
  • e is a merge from master.

b' was done after c and c has modifications to same files as b (d probably doesn't matter).

e can easily look very unexpected.

Let's say all of 'em are dealing with same file "foobar.txt". This is how the file looks in each commit:

// ----------- a
foo

delme

bar

// ----------- b
foo

delme

new

bar

// ----------- c
foo

new

bar

// ----------- b'
foo

delme

new

bar

// ------------ e
foo

new

new

bar

Now, this was from my brief test just now, with this exact setup.

If you remove all spaces there, there is no such problem. Merge will just accuse a conflict, as I'd expect. But I don't think using any -X setting for spaces is what we're looking for here... Or is it?

Meanwhile, on my production code, which was the reason I began researching about all this, and which has not nearly as many blank spaces, I got to see e looking something like this instead:

// ----------- e
foo

delme

new

bar

All that happens with merge never accusing any conflict!

If git was to do any of its voodoo magical auto merge here, this is what I'd expect it to look like:

// ----------- e
foo

new

bar

But this also does not happen.


As a bit of a disclaimer...

I also tried reading the f manual, but I can't really understand too many points under merge strategies. Plus it doesn't really say what the resolve strategy is doing under the hood, for instance:

It tries to carefully detect criss-cross merge ambiguities and is considered generally safe and fast.

That says nothing.

The text about the default recursive is bigger, but I also couldn't extract enough info from it:

This has been reported to result in fewer merge conflicts without causing mis-merges by tests done on actual merge commits taken from Linux 2.6 kernel development history.

Reported? So we got 1 very heavy unit test and assumed by a few reports it's all right?

Well, it's all too vague to me.


I think I must be doing something wrong! So, how can I do it right?

What need I do to get back on merging with no worries?

like image 711
cregox Avatar asked Dec 04 '13 15:12

cregox


People also ask

What is the default git merge strategy?

Recursive is the default merge strategy when pulling or merging one branch. Additionally this can detect and handle merges involving renames, but currently cannot make use of detected copies. This is the default merge strategy when pulling or merging one branch.


1 Answers

The basic problem is that there is no formal model for what it means to do correct automated merges that do the right thing in every case. In fact, "the right thing" can differ for different use cases in ways which the merge algorithm has no idea about. There have been a variety of attempts to come up with a single, correct merge algorithm that always does the right thing (various Monotone merge strategies, Codeville, Precise Codeville, Darcs, and so on), and all of them fail in some way in real-world use cases.

So, for a real-world merge algorithm "it works pretty well on a real codebase with lots of merges" is about the best you're going to be able to do. This means that you should never blindly trust the outcome of a clean automated merge; while it may have merged cleanly without conflicts, that may not have done exactly what you expected. You still need to review what the merge did, and test the result.

My general approach is to try a couple of different merge options, like you did, to see if one of them produces the correct merge. If that doesn't work to get you the correct merge (or a merge that produces the appropriate conflict that you can resolve), then you should do git merge --no-commit, and fix up the merge as appropriate before committing it.

like image 71
Brian Campbell Avatar answered Oct 17 '22 23:10

Brian Campbell