问题
I have an unclear understanding about merging on git, which I would like to understand correctly.
Let's say, I have a file F on master branch, which has already 100 LOC. I create a branch A from master, and I write 50 LOC, starts from line 101th to line 150th. I create a merge request to merge branch A to master. So if branch A will be merged, then file F on master will have 150 LOC
Let's assume branch A isn't merged to master yet, still waiting. And I create a new branch B from master. I also write 50 LOC, starts also from line 101th to 150th (because branch A isn't merged yet). And I also create a MR for branch B
What will happen, if 2 people review 2 MRs, and:
They merge 2 MRs at the same time? Will master have a conflict, because both branches want to be merged into line 101th to 150th?
If branch A is merged first, means master already has 150 LOC, but branch B still starts from line 101th to 150th, because it was created from master when it still had 100 LOC. Will there be also a conflict when B is merged? Or how does Git handle these?
Thanks in advance (I am not a troll, just want to figure out stuff, in case some people are going to flag this question)
回答1:
Something to clarify I think: conflicts and merge strategies are a concept of git itself. "Merge request", OTOH, is a concept of gitlab (and other repo hosts have similar concepts) but means nothing at all to git itself. Your question is best answered by talking about git; so we need only know that a merge request is one workflow by which a merge operation might be started in git. So let's take your question in two parts:
Sequential Merges
Short answer: there will probably be a conflict.
Whether there will be a conflict would depend on the merge strategy. My tests suggest there would typically be a conflict, as git sees alternative changes in lines 101 - 150. Since both sets of changes are adds, I guess you could conceive of both sets of lines being added without conflict - though it's unclear what order they would go in. You can make git try to do that using the union
merge driver; see http://kernel.org/pub/software/scm/git/docs/gitattributes.html
You can tell git to resolve merges in different ways via command line arguments, but since those directions would apply to the entire commit - not just the one file where this condition is set up - you usually wouldn't want to. You could use .gitattributes
to influence how git merges just the one file, if you can know in advance when that approach will be right for the (entire) file.
So, there are a lot of options for how to change merge
's behavior - too many to detail out here without knowing a specific desired result. But usually it works out well to use the default merge settings and resolve conflicts when they occur, in my experience anyway.
Concurrent Merges
It is not really possible for two merges to occur "at the same time" within a single repo. If a host provides some way to start a merge on the hosted (origin
) repo directly - which I don't actually know that anyone does, but for the sake of argument - then one merge would have to complete first, and the other would see the result of that merge as its starting point; so see the previous part of the answer for that.
What can happen is, one person can perform one merge on one repo, and another person can perform another merge on a second repo, and then there can be conflicts when they both try to sync up with the remote. And here's how that might look:
(Note that throughout this example I'm assuming true merges -- i.e. what would happen if you use the no-ff
option. The merge graphs might be simpler, but the results would be the same as far as conflicts go, if fast-forward merges were allowed.)
So the repo starts out with
B <--(branch_B)
/
x -- x -- O <--(master)
\
A <--(branch_A)
All commits contain a single file. In O
that file has 100 lines. A
and B
each add 50 new lines to the end of the file.
Now Alice merges branch_A
, and Bob merges branch_B
, each in their local repo. So Alice has
B <--(branch_B)
/
x -- x -- O -- MA <--(master)
\ /
A
^-(branch_A)
and Bob has
v-(branch_B)
B
/ \
x -- x -- O -- MB <--(master)
\
A <--(branch_A)
To share their work, they will each try to push
to origin
; and just as with merge
s, one will complete first before the other starts even if they try to start pushing at exactly the same moment.
So Alice gets her push in, and origin
is updated to look just like her local. When Bob tries to push, he gets an error because his master
is behind the master
on origin
(or, we could say, behind origin/master
once it's been updated, assuming typical mappings).
So Bob has to pull
(or fetch
and merge
) before he can push
. To illustrate most clearly, let's suppose he fetch
es. Now he has
v-(branch_B)
B
/ \
x -- x -- O -- MB <--(master)
|\
| MA <--(origin/master)
|/
A <--(branch_A)
and to complete the effect of a pull
, he needs to merge origin/master
into master
- so even this case boils down to the "sequential merge" scenario covered first. In fact, if you trace the same scenario using fast-forward merges, it will be clear that the "2nd merge" needed here is exactly the same as the "2nd merge" if everything were done by one user in one repo.
来源:https://stackoverflow.com/questions/46773595/git-merging-what-happens-to-2-branches-being-merged-at-same-time