我很抱歉提出关于合并与rebase的哲学辩论,但我有一个实际的问题,关于典型的公司工作流程(不是开源项目工作流程,可能会有所不同)。
重新定位,如 这里指出,如果您推动了更改,则不应使用。这是如此,因为其他人可能已从你的分支分支,然后重写该分支的历史(通过强制推动)将使他们很难。
因此,使用变基的正确方法是仅在本地提交。但至少在我的简短经历中,这是不可取的:
- 如果你的电脑被盗怎么办?
- 如果由于磁盘故障导致数据丢失怎么办?
- 如果你必须在两个地方工作(如 这个人)
将功能分支保持在本地对我来说是违反直觉的。不仅由于以上几点,而且由于以下用例:您正在开发一项功能,但要么被拖到更紧急的地方,要么去度假,或生病。一位同事必须完成它。然后你改变和推动(除非你生病了,在这种情况下,它保持在本地,没有人可以完成它),而另一个人完成它。
在此期间,主人有变化。但另一个人已经基于一个远程分支,所以他应该使用merge,或rebase和force-push(如果其他人同时将其分支基于那个分支,那么这可能会使事情变得棘手)。
这听起来像边缘情况,但它们不是。这些条件中的至少一个(在家工作,生病,去度假,完成别人的工作等)经常发生。
那么,使用“rebase”是一种很好的方式进入这些用例,或者合并(使用额外的“merge commit”)是更安全,更直接的选择吗?
所以我倾向于支持变革。 Git图历史很重要。您希望它有一些关于功能分支的信息以及它们如何合并,但是一旦您有多个人,图表就会很快陷入混乱。通常,您希望了解过去几天发生的事情,图表的质量是能否从git图中获取信息之间的差异。
另外,请注意力推 功能分支 这不是什么大不了的事。强制推送的问题是你必须通过非git手段通知人们git活动 - 在Slack等上ping它们。这显然不适用于开源项目或具有多个贡献者的分支。但是大多数功能分支只有一个贡献者,因此他们可以根据需要强制推送。即使有两三个人正在处理它,你也可以通过强制推动来解决它 - 我们组织的典型情况是在打开拉取请求之前和合并之前。你偶尔会在工作过程中从上游获取一些东西,但通常你不需要,除非你想要。
当我们合并时,我们会做两件事 - 我们在最重要的时候 master
然后我们合并 --no-ff
。这会创建一个带有空左路径的合并气泡,其中(1)组一起提交,(2)使直接进入主设备的提交脱颖而出(偶尔有效 - 修补程序,小改进,拼写错误,空格等)。
这种方法的警告是需要一段时间才能学习。你不能使用GitHub合并按钮(它不能达到我们的预期),你必须有足够的git chops来做一个rebase并注意图形。我见过的大多数开发人员都不在。每个新的团队成员需要花一点时间来解决这个问题,并且通常会将历史混乱一两次(我们有git hooks帮助)。但我发现这笔交易值得花时间。好处是:
- 功能分支不是本地的。
- 历史保持相当干净。
- 主题提交通过合并气泡进行分组。
- 强制推动通常不是问题,因为(1)它很少发生,(2)你要么独自工作,要么最多只能成对工作。
作为一个旁注,“不要把你已经推到原点的东西变废”对我来说总是听起来像一个新手规则。是的,当你不知道自己在做什么时,你可能会陷入困境。但是一旦你熟练掌握了git,就应该开始训练。
精确陈述的规则是:“不要改变可能成为另一个分支基础的分支”。通常,只有不发布您的分支才能轻松实现它 - 没有人看到它,所以没有人可以使用它。所以这就是为什么 “如果你推了就不应该使用”。但在某些情况下,它是可以接受的工作流程 - rebase / push / rebase / push / ...你只需要与他人达成一致意见,他们不会使用推送的分支来满足他们的需求,或者明确同意下一个改变/推动的rota (如果是生病/假期/等),或者你只是在几个地方工作(我希望你能在某些时候同意自己)。
顺便说一下,有一个 --force-with-lease
选择避免可能由推动的rebase引起的某些伤害。
您可以安全地使用rebase来更新本地分支 相同 远程跟踪分支(如git pull --rebase),而正如您所说,当您与其他协作者一起工作“共享”分支时,最好使用合并,而您不想重写远程历史记录(使用git push - 力)。
所以,根据你的git工作流程,由于git的分布式特性,如果你更喜欢rebase而不是merge,最好使用一个单独的分支(或者像一个单独的repo,比如github“forks”)来推送你的更改并最终合并它到目的地分支。
我倾向于同意保守的规则,不要反对推动分支。正如其他答案所指出的,它不一定是问题所在 --force-with-lease
选项消除了很多痛苦。保守策略仍然有两个优点:
- 它很容易记住,没有ifs和buts,你甚至可以通过禁止强制执行它
push --force
。
- 你总是在安全的一面 - 也许是某人 没有 在你的分支上工作而你却没有意识到这一点。
然而,存在一种推动分支并仍然使用rebase的策略,即每次重写历史时只需创建一个新分支:
$ git checkout -b my_branch/WIP/01
... do some work, add some commits ...
$ git push
... notice that you want to clean up your history ...
$ git checkout -b my_branch/WIP/02
$ git rebase ...
$ git push
这样一来,如果有人依赖你之前发表的作品,它仍然在那里,历史是可重复的,没有 push --force
参与其中。
这种方法的缺点是其他人 没有 从事于 my_branch/WIP/01
必须手动挑选他们在最新分支上的工作。