Git Cherry-pick vs合并工作流程


302

假设我是仓库的维护者,并且想从贡献者那里获取更改,那么可能有一些工作流程:

  1. cherry-pick每个人都从远程提交(按顺序)。在这种情况下,git将提交记录为与远程分支无关。
  2. merge分支,拉动所有的变化,并增加了新的“冲突”提交(如果需要)。
  3. merge每个人都从远程分支分别提交(再次按顺序提交),从而允许为每个提交记录冲突,而不是将所有冲突归为一个组。
  4. 为了完整起见,您可以做一个rebase(与cherry-pick选项相同?),但是我的理解是,这可能会使贡献者感到困惑。也许消除了选项1。

在2和3的情况下,git都记录提交的分支历史,这与1不同。

使用cherry-pickmerge描述的方法之间的优缺点是什么?我的理解是方法2是规范,但是我觉得用单个“冲突”合并来解决大型提交并不是最干净的解决方案。

Answers:


296

这两个rebase(和cherry-pick),并merge有自己的优点和缺点。我在merge这里主张,但是两者都值得理解。(在此处找到一个替代的,争论不休的答案,列举了rebase首选的情况。)

merge优于cherry-pickrebase一对夫妇的原因。

  1. 坚固性。的的SHA1标识提交识别它不仅在其本身,而且相对于它前面的所有其他的提交。这样可以保证给定SHA1上所有克隆的存储库状态都相同。从理论上讲,几乎没有人进行过相同的更改,但实际上是在破坏或劫持您的存储库。您可以选择单个更改,它们可能是相同的,但是您不能保证。(作为次要的次要问题,如果其他人再次在同一提交中进行新的挑选,则新的挑选出的承诺将占用额外的空间,因为即使您的工作副本最终相同,它们也会出现在历史记录中。)
  2. 易于使用。人们倾向于merge相当容易地理解工作流程。 rebase往往被认为更高级。最好同时理解两者,但是不想成为版本控制专家的人(根据我的经验,其中包括许多非常擅长于他们的工作,但又不想花费额外时间的同事)会更轻松时间只是合并。

即使是繁重的工作流程rebasecherry-pick在某些情况下仍然有用:

  1. merge混乱的历史是其缺点之一。 rebase可以防止一连串的提交分散在您的历史记录中,就像您定期合并其他人的更改一样。实际上,这就是我使用它的主要目的。您要非常小心,永远不要rebase编码与其他存储库共享的代码。一旦完成了提交,push其他人可能已经在其上提交了,重新定基充其量将最多导致上面讨论的那种重复。在最坏的情况下,您可能会得到一个非常混乱的存储库和细微的错误,这将使您花费很长的时间来查找。
  2. cherry-pick 有助于从您基本上决定放弃的主题分支中抽取一小部分更改,但是意识到其中有一些有用的内容。

至于更喜欢将许多更改合并为一个:这只是简单得多。一旦开始拥有大量变更集,那么合并各个变更集可能会变得非常乏味。git(以及Mercurial和Bazaar)中的合并分辨率非常好。大多数时候,即使合并很长的分支,您也不会遇到重大问题。通常,我会一次全部合并所有内容,并且只有遇到大量冲突时,我才备份并重新运行合并程序。即使那样,我也会大块地做。作为一个非常真实的例子,我有一位同事,他有3个月的变更要合并,并且在250000行代码库中遇到了9000个冲突。我们要解决的问题是一次合并一个月的价值:冲突不是线性累积的,而逐步进行合并会产生很大的结果少于9000个冲突。这仍然是一项艰巨的工作,但不如一次完成一次提交那么多。


1
实际上,从理论上讲,Mallory有可能通过创建具有相同SHA1但内容不同的提交来破坏您的存储库,这实际上可能永远不会发生。:)
孟买

1
哈:)我的意思是“理论上可能性很小,以至于您可以依靠它不会发生”,但是您说对了,它读起来很混乱。
夸克

您如何看待“合并-壁球”?
cmcginty

@Bombe如果Mallory想要成功,则必须专门构建具有相同SHA1的原始提交和第二个提交。因此,另一个问题可能是:出现两次(有些)虚假提交而您没有注意到的几率是多少?;)
JoãoPortela

64
9000冲突?我辞掉工作,成为养蜂人。
塞巴斯蒂安·帕滕2014年

95

我认为应在需要的情况下保留樱桃采摘,例如,如果您直接在“主”分支(树干,主开发分支)上进行了一些修复,然后意识到也应将其应用于“维护” '。您应该基于合并或重新设置工作流(或“ git pull --rebase”)。

请记住,从Git(具有不同的SHA-1标识符)的角度来看,精心挑选或基于基础的提交不同于原始提交,因此它不同于远程存储库中的提交。(Rebase通常可以处理此问题,因为它检查补丁程序ID,即更改,而不是提交ID)。

同样在git中,您可以一次合并许多分支:所谓的octopus merge。请注意,章鱼合并必须成功而没有冲突。但是,它可能有用。

HTH。


19
对于rebase / cherry-picking实际上是“复制”提交并因此失去与原始提交的链接这一点,+ 1。
studgeek 2011年

1
我们以这种方式使用cherry-pick,专门用于将针对错误修复的提交(也许非常小的功能)移至现有的发行分支中以准备补丁。跨多个提交的功能通常需要进入基于master的发布分支。
foxxtrot 2011年

3
@foxxtrot:另一个解决方案是基于显示此错误的最旧提交为错误修正创建一个单独的分支,并将其合并到“ maint”和“ master”中,尽管在这种情况下,您需要知道该错误修正适用于两个分支。
2011年

4
@Jakub创建和合并错误修正分支必不可少的两个命令:git blame查找引入错误的提交,并git branch --contains确定合并分支的位置。这篇文章
gcbenison,2012年

-10

Rebase和Cherry-pick是保持干净提交历史记录的唯一方法。避免使用合并,并避免产生合并冲突。如果使用的是gerrit,则在必要时将一个项目设置为Merge,将一个项目设置为Cherry-pick模式,然后尝试一下。


完全不清楚如何回答这个问题,也许一些例子会带来一些启发。
Adrian Nasui

1
您的历史记录看起来直截了当,但这并不意味着您会更容易理解。
nicolimo86 '18 -10-16

合并是获得干净记录的常用方法。Cherry-pick和rebase主要用于必须修改历史记录的情况。这意味着合并应该始终是首选。当您与遥控器和多人一起工作时,导致重新设置密码会很危险。
Radon8472

这个家伙在这里值得一枚奖牌。他知道自己将继续被否决,但这是正确的答案。荣誉
PW Kad

抱歉,直到现在我还没有看到这些评论,请在结束测试之前在您的测试环境中进行尝试,并为您做些有用的事情!我有大约600个开发人员为多个产品分支做出了贡献,我不在乎开发人员在本地工作区中做什么,当提交更改以进行集成时,应该可以选择开发分支,有时也可以发布或修复漏洞。仅供参考...我使用Gerrit。
Nagaraj Magadum
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.