Git:当我"推动"从不同计算机到同一个远程分支的不同代码?

时间:2014-12-03 09:40:00

标签: git push pull

假设我使用两台计算机:说,我在家用计算机上处​​理项目,但前一天我忘了从工作计算机上推送最新修改。

推/拉时会发生什么? 如果我推开计算机,我最终会选择两个分支机构吗? 如何解决冲突?

1 个答案:

答案 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,您的资源库中没有DE。通过推送,您可以提供远程FG,然后让它改变其对branch指向的位置的想法。]

您要求遥控器将branch设置为指向G。如果遥控器执行此操作,则提交DE会丢失,因此它只会告诉您不,除非您强制推送。

即使您也是Bob(在另一台计算机上)也是如此。

解决问题:两种方式

在这种情况下,您需要调整Bob推送的提交:

$ git fetch

在这种特殊情况下,这会带来提交DE。完成后,您需要修改要推送的内容以某种方式将DE合并到FG

有两种简单的方法可以使用git mergegit 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 mergeF,只是稍微堆叠在最新提取的提交的末尾,在这种情况下是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_HEADF可以忽略,因此我们可以像这样重绘提交图,调用副本GF现在:

G

如果您现在尝试将其推送到遥控器,它会发现您只是在最后一次提交之后堆叠两个提交:这是一个快进,所以它是允许的

...-A-B-C-D-E-F-G <-- branch 怎么样?

git pull脚本实际上只是pull后跟git fetchgit 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>

呃,TL; DR-so,我什么时候应该使用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向合并。