I want to know an exact algorithm (or near that) behind \'git merge\'. The answers at least to these sub-questions will be helpful:
How does git perform when there are multiple common bases for merging branches?
This article was very helpful: http://codicesoftware.blogspot.com/2011/09/merge-recursive-strategy.html (here is part 2).
Recursive uses diff3 recursively to generate a virtual branch which will be used as the ancestor.
E.g.:
(A)----(B)----(C)-----(F)
| | |
| | +---+
| | |
| +-------+
| | |
| +---+ |
| | |
+-----(D)-----(E)
Then:
git checkout E
git merge F
There are 2 best common ancestors (common ancestors that are not ancestors of any other), C and D. Git merges them into a new virtual branch V, and then uses V as the base.
(A)----(B)----(C)--------(F)
| | |
| | +---+
| | |
| +----------+
| | | |
| +--(V) | |
| | | |
| +---+ | |
| | | |
| +------+ |
| | |
+-----(D)--------(E)
I suppose Git would just continue with the if there were more best common ancestors, merging V with the next one.
The article says that if there is a merge conflict while generating the virtual branch Git just leaves the conflict markers where they are and continues.
What happens when I merge multiple branches at once?
As @Nevik Rehnel explained, it depends on the strategy, it is well explained on man git-merge MERGE STRATEGIES section.
Only octopus and ours / theirs support merging multiple branches at once, recursive for example does not.
octopus refuses to merge if there would be conflicts, and ours is a trivial merge so there can be no conflicts.
Those commands generate a new commit will have more than 2 parents.
I did one merge -X octopus on Git 1.8.5 without conflicts to see how it goes.
Initial state:
+--B
|
A--+--C
|
+--D
Action:
git checkout B
git merge -Xoctopus C D
New state:
+--B--+
| |
A--+--C--+--E
| |
+--D--+
As expected, E has 3 parents.
TODO: how exactly octopus operates on a single file modifications. Recursive two-by-two 3-way merges?
How does git perform when there is no common base for merging branches?
@Torek mentions that since 2.9, merge fails without --allow-unrelated-histories.
I tried it out empirically on on Git 1.8.5:
git init
printf 'a\nc\n' > a
git add .
git commit -m a
git checkout --orphan b
printf 'a\nb\nc\n' > a
git add .
git commit -m b
git merge master
a contains:
a
<<<<<<< ours
b
=======
>>>>>>> theirs
c
Then:
git checkout --conflict=diff3 -- .
a contains:
<<<<<<< ours
a
b
c
||||||| base
=======
a
c
>>>>>>> theirs
Interpretation:
a\nc\n as a single line addition