ChatGPT解决这个技术问题 Extra ChatGPT

Git Cherry-pick vs 合并工作流

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

我从远程挑选每个提交(按顺序)。在这种情况下,git 将提交记录为与远程分支无关。我合并分支,拉入所有更改,并添加新的“冲突”提交(如果需要)。我单独合并来自远程分支的每个提交(再次按顺序),允许为每个提交记录冲突,而不是全部组合在一起。为了完整起见,您可以做一个变基(与樱桃选择选项相同?),但我的理解是这可能会导致贡献者混淆。也许这消除了选项1。

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

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


C
Community

rebase(和 cherry-pick)和 merge 都有其优点和缺点。我在这里主张 merge,但两者都值得理解。 (在此处查找另一个有充分理由的 answer 列举了首选 rebase 的情况。)

出于几个原因,merge 优于 cherry-pickrebase

稳健性。提交的 SHA1 标识符不仅可以识别它本身,还可以识别它之前的所有其他提交。这为您提供了一个保证,即给定 SHA1 的存储库状态在所有克隆中都是相同的。 (理论上)不可能有人做了看起来相同的更改,但实际上正在破坏或劫持您的存储库。您可以挑选个别更改,它们可能相同,但您不能保证。 (作为一个次要的次要问题,如果其他人再次在同一个提交中进行挑选,那么新挑选的提交将占用额外的空间,因为即使您的工作副本最终相同,它们也会出现在历史记录中。)使用。人们倾向于相当容易地理解合并工作流程。 rebase 往往被认为更高级。最好同时了解两者,但是不想成为版本控制专家的人(根据我的经验,其中包括许多非常擅长他们所做的事情但不想花费额外时间的同事)更容易时间刚刚合并。

即使使用大量合并工作流,rebasecherry-pick 对于特定情况仍然有用:

合并的一个缺点是历史记录混乱。 rebase 可以防止一长串提交分散在您的历史记录中,就像您定期合并其他人的更改一样。这实际上是我使用它的主要目的。您要非常小心的是,永远不要对您与其他存储库共享的代码进行变基。一旦一个提交被推送,其他人可能已经在它之上进行了提交,并且变基充其量会导致上面讨论的那种重复。在最坏的情况下,您可能会得到一个非常混乱的存储库和细微的错误,这将需要您很长时间才能找出来。 cherry-pick 对于从您基本上决定丢弃的主题分支中抽取一小部分更改很有用,但意识到有几个有用的部分。

至于更喜欢合并多个更改而不是一个:它只是简单得多。一旦您开始拥有大量单个变更集,合并单个变更集可能会变得非常乏味。 git(以及 Mercurial 和 Bazaar)中的合并分辨率非常好。大多数时候,即使是长分支,您也不会遇到重大问题。我通常一次合并所有内容,只有当我遇到大量冲突时,我才会备份并重新运行合并。即便如此,我还是大块地做。作为一个非常真实的例子,我有一位同事需要合并 3 个月的更改,并且在 250000 行代码库中遇到了大约 9000 个冲突。我们要解决的问题是一次合并一个月的时间:冲突不会线性累积,并且分段执行会导致远远少于 9000 个冲突。这仍然是很多工作,但不如尝试一次提交一个提交。


实际上,理论上,Mallory 有可能通过创建具有相同 SHA1 但内容不同的提交来破坏您的存储库,这在实践中可能永远不会发生。 :)
哈 :) 我的意思是“理论上可能性很低,以至于你可以依靠它不会发生”,但你说得对,它读起来很混乱。
9000冲突?我会辞掉工作,成为养蜂人。
超过9000!
与其他开发人员隔离工作 3 个月然后合并?他是在没有网络的荒岛上吗?
J
Jakub Narębski

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

请记住,从 Git 的角度来看,cherry-picked 或 rebased 提交与原始提交不同(具有不同的 SHA-1 标识符),因此它与远程存储库中的提交不同。 (Rebase 通常可以处理这个问题,因为它检查补丁 id 即更改,而不是提交 id)。

同样在 git 中,您可以一次合并多个分支:所谓的章鱼合并。请注意,章鱼合并必须成功而不会发生冲突。尽管如此,它可能很有用。

HTH。


+1 表示 rebase/cherry-picking 实际上“复制”了提交,因此失去了与原始提交的链接。
我们以这种方式使用cherry-pick,专门用于将错误修复(可能是非常小的功能)的提交移动到现有的发布分支中以准备补丁。跨越多个提交的功能通常需要进入基于 master 的发布分支。
@foxxtrot:另一种解决方案是为错误修复创建一个单独的分支,基于显示此错误的最旧提交,并将其合并到'maint'和'master'中......尽管在这种情况下你需要知道那个错误修复适用于两个分支。
@Jakub 创建和合并错误修复分支必不可少的两个命令:git blame 查找引入错误的提交,git branch --contains 确定合并分支的位置。 this post 中有更详细的描述
N
Nagaraj Magadum

Rebase 和 Cherry-pick 是保持干净提交历史的唯一方法。避免使用合并,避免产生合并冲突。如果您正在使用 gerrit,请将一个项目设置为 Merge(如有必要),并将一个项目设置为樱桃挑选模式并尝试自己。


完全不清楚这如何回答这个问题,也许一些例子会带来一些启示。
您的历史看起来很直接的事实并不意味着它会更容易理解。
合并是拥有干净历史记录的常用方法。 Cherry-pick and rebase 主要用于必须修改历史的情况。什么意思,合并应该永远是首选。当您与遥控器和多人一起工作时,导致 rebase 更改了提交 sha 的内容是非常危险的。
这里的这个人应该得到一枚奖章。他知道他会继续被否决,但这是正确的答案。荣誉。
抱歉,直到现在我才看到这些评论,请在结束之前在您的测试环境中尝试一下,然后做对您有用的事情!我有大约 600 名开发人员为多个产品分支做出贡献,我不在乎开发人员在本地工作区做什么,当提交更改以进行集成时,它应该能够选择开发分支或有时发布或修复错误分支。仅供参考...我使用 Gerrit。