1)有一个'主人'分支包含
的文件1
2
3
4
5
2)A从[' master'并编辑如
1
2
100
3
4
5
3)B从主人那里拿出一个分支'并编辑如
1
2
3
4
200
5
4)现在推送变成了主人。然后B也试图推动。
B会发生什么?任何合并冲突或没有合并冲突?原因是什么?
答案 0 :(得分:4)
你的问题意味着事情并非如此。
具体而言,git push
仅推送现有提交。它没有合并任何东西,事实上,它甚至从未尝试来合并任何东西。
在您的问题中,涉及三个实体(人员和存储库)。 A人(让她称她为Alice),B人(让他们称他为Bob)和C人(让他们称他为Central-Server,他实际上只是一台机器,不是一个人,虽然这并不重要。)
Alice和Bob都是从Central-Server获取某个存储库的副本(克隆)开始的。他们得到完全相同的克隆(这就是为什么他们被称为&#34;克隆&#34;):爱丽丝的克隆匹配鲍勃的克隆匹配了什么中央服务器。他们通过运行git clone <url>
来执行此操作,其中<url>
指向中央服务器(github或其他任何内容),并且他们的git将名称origin
下的网址保存起来(我们&#39;我很快会再次看到这个名字。)
让我们绘制所有三个实体现在拥有的git提交图(的一部分):
... - C7 - C8 <-- master
现在,Alice和Bob都进行了更改,但是他们进行了不同的更改。爱丽丝承诺改变:
... - C7 - C8 - A <-- master
然后Alice运行git push origin
将她的工作推回到中央服务器。中央服务器会查看她的请求,该请求会在A
处向链的末尾添加提交C8
,并使master
指向A
&# 34 ;.此操作将新的提交添加到链中,因此是允许的,因此中央服务器回复&#34;确定&#34;对爱丽丝来说,她已经完成了。 Central-Server的存储库现在看起来也和Alice一样,因为它们在旧提交A
之后都有新的提交C8
,而master
指向提交A
(并提交A
指向旧的C8
)。
同时Bob已做出改变并添加了一个新提交,他的提交图现在看起来像这样:
... - C7 - C8 - B <-- master
Bob不知道Alice已经提交了A
,也没有成功将它推送到Central-Server。他转到git push origin
,但这次Central-Server收到一条请求,说明&#34;将提交B
添加到C8链的末尾,然后将master
指向{ {1}}&#34 ;. 如果中央服务器执行此操作,效果将为:
B
也就是说,提交 A
/
... - C7 - C8 - B <-- master
将保持浮动,没有指向它的任何内容。 (分支A
将指向master
,而B
将指向B
,没有任何指向C8
。)这通常是一种糟糕的事态并且git拒绝它,所以Central-Server告诉Bob:
A
请注意,没有合并也没有变基。
现在 Bob 的工作是进行合并(或rebase)。他应该这样做:
从拥有它的人那里获取更新。谁拥有它?爱丽丝拥有它,但Central-Server也是如此。他刚刚要求推送到Central-Server,后者告诉Bob&#34; no&#34;,所以他也可以从Central-Server获取它。
进行合并(或变基),解决任何冲突。
重试推送。
如果Bob选择&#34;合并&#34;并且做了合适的合适工作,这是他的新提交图:
rejected (non-fast-forward)
请注意新的合并提交 ... - C7 - C8 - A - M <-- master
\ /
B
。现在,Bob可以重新尝试推送到Central-Server,后者目前的链以M
结尾。这次中央服务器将看到A
指向master
的请求,并且M
指向M
,此请求将被允许(现在是& #34;快进&#34;。)
当然,如果Alice(或Dave或Emily或Frank)通过添加A
之前的新提交并将其发送回Central-Server来击败Bob,那么Bob将不得不合并(或改组)再次,再试一次。
Bob的选择是合并还是变基。无论哪种方式,Bob都必须解决任何合并冲突 - 无论他使用哪种方法,他都会得到相同的合并冲突。并且,在任何一种情况下,他都应该开始运行:
A
(或仅git fetch origin
,会自动使用git fetch
。
在重组或合并之前,让我们先看看Bob的提交图:
origin
请注意,Bob的 A <-- origin/master
/
... - C7 - C8
\
B <-- master
指向提交master
,Bob有另外一件事 - 这个B
- 指向Alice的提交{{1} }。这就是origin/master
所做的:它从Central-Server中带来了最新版本(或者如果Bob直接从Alice获取,将其从她身上带过来,因为她有相同的提交),然后让一些标签指向承诺。标签以A
开头,因为这是我们允许git fetch
使用的名称:它只是将origin/...
粘贴在另一个名称前面git clone
,在此())以便我们区分它们。
如果Bob选择 rebase 而不是合并,他将把他的git 复制他的提交origin/
发送到新的提交master
:< / p>
B
Bob的原始B'
会怎样?答案是:它被废弃了。它保留在存储库中一段时间(默认为30天),以防Bob需要它,保存在Bob的 reflogs 中,但除非你(或Bob)明确要求git查看,你没有看到这些提交,所以他们似乎已经了。
如果Bob选择合并,他会得到这个:
A <-- origin/master
/ \
... - C7 - C8 B' <-- master
\
B
这是我们上面提到的相同的图,我们刚刚将B
节点抬起来,以便我们可以指向它的箭头(标记为{{1} })。
在任何一种情况下,Bob现在都可以尝试推送,因为他的新提交 - A <-- origin/master
/ \
... - C7 - C8 M <-- master
\ /
B
或A
- 指回提交origin/master
,因此他只询问Central-服务器添加新提交而不是忘记或放弃提交B'
。
Git将尝试通过比较Alice所做的更改(向M
添加一行)与Bob所做的更改(添加一行A
)来帮助Bob。如果git决定这些更改不相互冲突,它将保持两个更改。如果它确定这两个更改会影响文件的相同部分,它将为Bob提供合并冲突,标记文件的更改区域,并让Bob决定如何将它们结合起来。
A
文件的最终版本和100
提交更改。 1 如果他用来组合更改的命令是200
,那么这将进行合并提交。如果是git add
,则会生成新副本git commit
。
1 如果Bob选择了git merge
,他可以使用git rebase
,它将为他提交。 Bob先安排B'
然后执行git rebase
是安全的(但是在git 1.5左右的时候,人们必须手动执行提交部分,然后再继续变基)。
git rebase --continue
我鼓励新的git用户从git commit
开始,然后自己做git rebase --continue
或git pull
。许多文档都告诉你从git fetch
开始,但我认为这是一个错误。 git merge
命令是便利:它运行git rebase
然后运行git pull
或git pull
,但这有几个缺陷。没有一个是非常严重的,但这些对新用户不利:
在之前选择合并vs rebase ,您甚至可以查看更改。
默认是合并,这通常是新用户的错误答案,他们通常可能应该重新定价。您可以更改默认设置,但新用户不知道提前做到这一点。您可以添加git fetch
告诉它进行rebase,但您可以忘记包含此标记。
它所做的合并是"foxtrot merge":它让父提交的方向错误。
与手动合并相比,这些参数令人困惑:git merge
vs git rebase
。 (当然,如果你想避免foxtrot合并,你也不能使用后者,但你可能应该反驳。)
如果您提供的参数太多(--rebase
),则会产生章鱼合并,这不是新用户应该考虑的事情。 : - )
它曾经有过许多破坏工作的bug案例。我相信它们都是固定的,但使用git pull origin <branch>
后跟单独的git merge origin/<branch>
或git pull origin master develop
一直避免这些错误。
最后,这里发生的魔法太多了。它应该是方便的(对于那些使用git的老手来说,它很方便)但它只是模糊不清。
答案 1 :(得分:3)
最简单的答案是:如果两个开发人员在同一个文件(和同一个分支)中更改了同一行代码,git将假定存在冲突。
承诺和推动的人是“胜利者”。第二个必须处理冲突。他不能推动,直到他从原点撤下所有变化并解决冲突。答案 2 :(得分:0)
当B尝试推送时,会出现错误返回,因为A已被推送更改为master。 那你应该这样做,
git fetch
git rebase origin/master
执行rebase步骤时,不会发生冲突,因为A更改了文件的第3行,B更改了文件的第5行。 那么你可以做到,
git commit -m ""
git push
答案 3 :(得分:0)
当git不知道如何处理代码的相同部分中的两个更改(未按顺序执行)时,会发生合并冲突。在您的情况下,已更改的行是不同的,因此git将能够合并提交而不会发生冲突。但是,一旦推送了A中的提交,就不能在没有在A之上重新设置B的情况下推送B中的提交。
在这种情况下你不能推B:
----M-----A
\----B
如果你去B并输入并使用:
git rebase A
您的代码在本地存储库中将如下所示:
----M-----A-----B
你也可以推送提交B