Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Github can't merge branch, no conflicts, manually it auto-merges

I have a pull request that Github says it can't automatically merge. This change is behind master a few commits, but without conflicts.

Manually merging I don't get any conflicts, and I get this output:

(on master)
$git merge otherbranch
[vim pops up for commit message, :wq]
Auto-merging <file>
Merge made by the 'recursive' strategy.
<file> | 1 +
1 file changed, 1 insertion(+)

Is that why Github can't merge automatically? It merged automatically from the command line anyway. Is this not automatic enough for Github?

like image 771
jpimentel Avatar asked Oct 17 '13 15:10

jpimentel


People also ask

How do you fix can't automatically merge don't worry you can still create the pull request?

Checkout via command line If you cannot merge a pull request automatically here, you have the option of checking it out via command line to resolve conflicts and perform a manual merge. Step 1: From your project repository, check out a new branch and test the changes. Step 2: Merge the changes and update on origin.

How do I stop git from auto merging?

Otherwise, select the files to be taken, stage them with git add and finally commit them with git commit . Restore the unwanted files then with git checkout -- filename . @marckassy: But you could then git reset HEAD and git add -p to select what you want. To shut off the initial merge completely, add -s ours .


1 Answers

The reason is that git merge uses a strategy called "recursive" merging by default. It is able to perform 3-way merging: taking the patch from one side, and applying that patch to the other side, to produce a new file. It also does this recursively, in more complicated situations where a lot of branching and merging has been happening and there are multiple merge bases for the two commits being merged.

I recently encountered this same situation:

$ git merge-base --all 90d64557 05b3dd8f
711d1ad9772e42d64e5ecd592bee95fd63590b86
f303c59666877696feef62844cfbb7960d464fc1
$

With 2 merge bases, a 3-way merge is not possible. The 'recursive' strategy therefore resolved this by first recursing into a merge of those two commits:

$ git merge-base 711d1ad9 f303c596
3f5db59435ffa4a453e5e82348f478547440e7eb
$

OK, only one merge base, so the 3-way merging can begin. what's the changes on either side?

$ git diff --stat 3f5db594 711d1ad9
 normalize/coll.py      | 116 ++++++++++++++++++++++++++++++++++++++-----------
 normalize/visitor.py   |  49 ++++++++++-----------
 tests/test_property.py |  10 +++--
 3 files changed, 120 insertions(+), 55 deletions(-)
$ git diff --stat 3f5db594 f303c596
 normalize/identity.py  | 38 +++++++++++++++++++++++++++++++-------
 tests/test_property.py |  2 ++
 2 files changed, 33 insertions(+), 7 deletions(-)
$ 

These two diffs both made changes to the same file, so they can't be resolved using a simple strategy of just taking the newer version of each file from each side (an index merge). Instead, git takes the new file from one side, and tries to apply the patch from the other side to it. The result is a combined commit, which can be simulated like this:

$ git checkout -b tmp
Switched to a new branch 'tmp'
$ git reset --hard f303c59666877696feef62844cfbb7960d464fc1
HEAD is now at f303c59 record_id: throw a more helpful error if record identity is not hashable
$ git merge 711d1ad9772e42d64e5ecd592bee95fd63590b86
Auto-merging tests/test_property.py
Merge made by the 'recursive' strategy.
 normalize/coll.py      | 116 ++++++++++++++++++++++++++++++++++++++-----------
 normalize/visitor.py   |  49 ++++++++++-----------
 tests/test_property.py |  10 +++--
 3 files changed, 120 insertions(+), 55 deletions(-)
$ git diff --stat 3f5db594 HEAD tests/test_property.py
 tests/test_property.py | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)
$

It then returns to the original 3-way merge, using this merge result as its starting point; and this also involves changes to the same file:

$ git diff --stat HEAD 90d64557| grep selector
 normalize/selector.py          |  17 +--
 tests/test_selector.py         |  19 ++--
$ git diff --stat HEAD 05b3dd8f| grep selector
 normalize/selector.py  | 29 +++++++++++++++++------------
 tests/test_selector.py |  9 +++++++++
$

However again the changes are to different sections of the file, and so taking the diff and applying it to the other side is successful.

So, C git was able to resolve this merge by first doing a 3-way merge on the two merge bases of the two starting points, and then doing another 3-way merge on the two original commits being merged and the intermediate result of the first merge.

Github's automatic resolution doesn't do this. It's not necessarily incapable, and I'm not sure how much of the recursive strategy it does implement, but it is erring on the side of caution, which is exactly what you expect a big green button like that to do :-).

like image 198
samv Avatar answered Nov 06 '22 21:11

samv