假设我使用两台计算机:说,我在家用计算机上处理项目,但前一天我忘了从工作计算机上推送最新修改。
推/拉时会发生什么? 如果我推开计算机,我最终会选择两个分支机构吗? 如何解决冲突?
答案 0 :(得分:5)
在这种情况下,它与你和Bob(或Carol或其他任何人 - 不是你)在repos中工作完全相同,你们都是从共享位置克隆过来的,而你们其中一个人推动在另一个之前改变。第一个推动"赢得"。
Git不知道或不关心你是谁。 1 它只是看起来在推动时是否是快速前进的"操作。如果是这样的话,默认情况下允许推送。 2 当第一个让我们说鲍勃赢了 - 当鲍勃做出推动时,他所拥有的新提交直接叠加在接收推送的存储库分支的提示。这是一个快进的,所以它是允许的。然后你尝试推送,但是你的新提交在旁边堆叠现在在那个回购中提交了一些提交:
D-E <-- branch (updated by Bob)
/
...-A-B-C
\
F-G <-- what you're trying to push
[注意:这是遥控器看到的内容,即远程 branch
指向E
。 您 branch
指向G
,您的资源库中没有D
和E
。通过推送,您可以提供远程F
和G
,然后让它改变其对branch
指向的位置的想法。]
您要求遥控器将branch
设置为指向G
。如果遥控器执行此操作,则提交D
和E
会丢失,因此它只会告诉您不,除非您强制推送。
即使您也是Bob(在另一台计算机上)也是如此。
在这种情况下,您需要调整Bob推送的提交:
$ git fetch
在这种特殊情况下,这会带来提交D
和E
。完成后,您需要修改要推送的内容以某种方式将D
和E
合并到F
和G
。
有两种简单的方法可以使用git merge
和git rebase
。
此时您通常只需运行:
$ git merge
(因为git会知道一个上游)。 git merge
所做的是尝试组合分叉开发并进行新的&#34;合并提交&#34;这指向两个链:
D-E
/ \
...-A-B-C M <-- branch
\ /
F-G
[注意:此处和下方,这是您在本地存储库中拥有的内容。]
如果自动合并进展顺利,你应该确保结果是好的,因为git不是魔术,它只是遵循一堆做合并的规则。如果自动合并失败,你必须协助git,因为它的规则没有做到这一点。
如果您按此按钮,则要求遥控器将branch
设置为指向M
。虽然M
并未完全直接堆叠在E
之上,但将 指向<{1}}作为一个的父母,所以E
是一个(稍微复杂)的快进。 (实际上,M
只需要M
作为某些祖先,而不仅仅是直接的祖先,而是其历史中的任何地方。关键是不会丢失任何提交。 )
实际合并的优势在于它显示了真正发生的事情:鲍勃赢得了推进竞赛,然后你调整了你的东西以匹配。缺点是难以通过合并来回溯内容:如果Bob的更改中存在错误或者您的错误,则很难准确判断虫子进来了;历史&#34;看起来很复杂&#34;,并发症往往不是很有用。所以这就是人们使用第二种选择的原因。
而不是E
,通常只需运行:
git merge
(出于同样的原因,您可以运行$ git rebase
而没有额外的参数:git通常知道上游并且可以找出要重新定义的内容)。这样做的目的是&#34;复制&#34;你的提交,在这种情况下是git merge
和F
,只是稍微堆叠在最新提取的提交的末尾,在这种情况下是G
。如果一切顺利,结果如下:
E
您的原始 D-E
/ \
...-A-B-C F'-G' <-- branch
\
F-G [to be abandoned]
和F
仍然在那里(并且名称为G
,直到另一个rebase或其他任何覆盖ORIG_HEAD
;它们也会留在reflogs中默认情况下30天,如果你需要恢复它们)但很大程度上被遗忘 - 关于rebase顺利进行。
与合并案例一样,你需要确保rebase确实有效:即使git认为它一切正常,它只是遵循简单的规则,就像合并一样。 3 但通常它确实有效,原始的ORIG_HEAD
和F
可以忽略,因此我们可以像这样重绘提交图,调用副本G
和F
现在:
G
如果您现在尝试将其推送到遥控器,它会发现您只是在最后一次提交之后堆叠两个提交:这是一个快进,所以它是允许的
...-A-B-C-D-E-F-G <-- branch
怎么样? git pull
脚本实际上只是pull
后跟git fetch
或git merge
的便利。它实际上调用git rebase
(在稍微复杂的方式中,在旧版本的git中,可以阻止一些有用的东西发生,尽管这里的细节不是很重要)。获取完成后,它会直接调用git fetch
,除非您已告知它使用git merge
。如果 告诉它使用git rebase
,您也可以告诉它是否使用rebase
调用git rebase
。在所有情况下,它以稍微复杂的方式调用合并或rebase。但是,是否以及何时使用--preserve-merges
超出了本答案的范围。
在较旧(但不是太旧)的git版本中,如果你有--preserve-merges
进行rebase,它也能够从上游的rebase中恢复,其中常规git pull
序列可以&#39 ;吨。在较新版本的git中,git fetch; git rebase
使用新的rebase
内容来自行解决这个问题,因此--fork-point
脚本不再具有很大优势。< / p>
pull
?我曾经避免它,因为它有一堆错误。我认为他们现在大部分已经修好了,所以我主要是为了避免习惯。随意使用它,只要记住它只是git pull
然后fetch
- 或 - merge
的简称。决定你是喜欢合并还是重组,set your "rebase on pull" settings accordingly. As usual with git, it's overly complicated.或者像我一样避免rebase
,这样你就不必弄清楚所有git pull
值的含义。
1 通常推送的方法,例如,使用ssh和密钥。但是这种认证发生在涉及git之前;一旦git运行,它就不在乎了,因为它不需要关心。
即使您创建了提交,git也会使用您配置的名称和电子邮件。您可以随时将这些设置为任何内容,因此在特定意义上,仍并不关心您的身份。
2 关于什么是和不允许的准确规则取决于谁运行你推送的系统。 &#34;默认默认&#34;规则,即,如果你设置并且不做任何改变,你得到的是,如果它是快进或者如果设置了强制标志,则允许推送到分支。如果标签不存在或者设置了强制标志,则允许推送到标签。 (某些旧版本的git也会将分支规则应用于标记,但较新的版本更严格。)
3 事实上,所有工作都是通过公共代码完成的,&#34;合并引擎&#34;在git里面。这几乎用于所有事情:只要git可以在提交图中找到共同的祖先,它就可以进行3向合并。