如何在不需要强制推送的情况下使用git rebase?

131

为了达到git境界,我正在花一天的时间学习如何利用rebase来处理我目前使用merge处理的情况。

当按照我认为是git 101的流程(如下所述)操作时,我必须在将更改推回原始版本时使用push --force命令。

我不是唯一一个这样想的人 - 我知道这已经是老生常谈了(参见1, 2, 3, 4, 5),而且我也理解为什么需要使用强制操作(why a force is necessary)。我的问题是 --- 有很多(很多)博客文章赞扬rebase并称它改变了他们的生活(参见1, 2, 3, 4等),但其中没有一个提到push --force是他们工作流程的一部分。然而,几乎所有现有的stackoverflow问题的答案都说:“是的,如果你要rebase,就得使用push --force”。

鉴于rebase支持者的数量和虔诚程度,我不得不相信使用“push --force”不是rebase流程的固有部分,如果一个人经常需要强制推送,那么他们可能做错了什么。

push --force一件坏事

所以这是我的流程。 如何在不使用force的情况下实现相同的结果?

简单的例子

两个分支:

  • v1.0 - 一个发布分支,只包含补丁
  • master - 下一个主要版本的所有内容。

我有几个补丁提交和几个用于下一个版本的提交。

premerge

我希望将这些补丁合并到我的主分支中,以便它们不会在下一个发布版本中丢失。在启蒙前,我会简单地执行以下操作:
git checkout master
git merge v1.0

但现在我正在尝试

git checkout master
git rebase v1.0

所以现在我在这里:

enter image description here

时间到了:

git push

没有结果。
6个回答

50

Rebasing是一个强大的工具,特别是当你用它来将主题分支快速合并到主分支时。例如,你可以将你的add-new-widget分支与主分支进行rebase操作:

git checkout add-new-widget
git rebase -i master

在将该分支快进合并到主分支之前,请执行以下操作。例如:

git checkout master
git merge --ff-only add-new-widget
这样做的好处是你的历史记录中不会有很多复杂的合并提交或合并冲突,因为在合并之前,所有更改都将被变基到主分支的最新版本。另一个好处是你已经进行了变基,但你不必使用git push --force命令,因为你不会破坏主分支上的历史记录。
当然,这并不是变基的唯一用例或工作流程,但这是我见过的其中一个更明智的用例。你的情况可能会有所不同。

4
谢谢CG,我认为“用它来创建快速合并”是关键。这不适用于我上面的情况,其中我有两个活动分支——开发分支和发布分支,但它似乎非常适用于仅在有限时间内需要的临时主题分支,一旦它们被合并,就可以删除它们。再次感谢。 - Roy Truelove
1
我确实理解这个问题,但原始问题仍然存在。我认为实际答案是由@Fabien Quatravaux给出的那个。 - IsmailS
7
那么,你仍然需要强制推送1.0分支,对吧?至少对我来说,事情总是这样的。法比安的方法可以防止这种情况发生。 - joerx
我进行了比较,并使用tig查看了差异:在合并之前强制推送,它显示[master] [branch-b] {origin/master} {origin/branch-b} b1,而在没有强制推送的情况下使用merge --ff-only,它显示[master] [branch2] {origin/master} {origin/HEAD} b1。请注意origin/branch-borigin/HEAD之间的差异。 - tomyhomie
这个工作流只适用于你被允许将主分支推送到远程的情况,对吗?例如,在GitHub上,我们现在经常使用“受保护的分支”功能锁定仓库,以便不允许任何人直接修改主分支。必须由GitHub进行修改。在这种情况下,您必须通过PR工作流程,让GitHub执行从PR合并或变基,对吗? - Matt Welke

29

@CodeGnome是正确的。你不应该在v1.0分支上变基master分支,而是在master分支上变基v1.0分支,这将使所有的区别。

git checkout -b integrate_patches v1.0
git rebase master
git checkout master
git merge integrate_patches

创建一个新分支,指向v1.0,在将新分支移动到主分支之上,然后将V1.0补丁的新版本集成到主分支中。 最终您将得到类似以下内容:

o [master] [integrate_patches] Another patch on v1.0
o A patch on v1.0
o Another change for the next major release
o Working on the next major release
|  o [v1.0] Another path on v1.0
|  o A patch on v1.0
| /
o Time for the release

这种使用rebase的方式是由官方git文档推荐的。

我认为你在关于git push --force的问题上是正确的:只有在你犯了错误并且推送了不想要的内容时才应该使用它。


我认为这是针对OP的特定问题最好的答案。您可以创建一个临时合并分支,然后在该分支上进行变基,然后合并到主分支并推送到源。临时分支不必推送到源。我唯一额外的建议是拥有一个开发或qa分支,可以在其中对合并/变基的代码进行资格认证。经过资格认证后,此代码将仅以ff-only方式合并到主分支中。如果您的资格认证过程时间太长,则可以轻松进行热修复。这基本上就是“git flow”流程。 - Javid Jamae
谢谢Fabien,非常好的回答。对于我们中想将更改集成到“master”中并不介意合并功能分支本身的人来说,可以使用以下命令完成:git checkout my-branch; git rebase master; git checkout master; git merge my-branch - Siavas

25

如果您已经发布了更改,那么在变基时必须强制推送。

我经常使用变基,但我要么发布到私人位置,这样强制推送无关紧要(例如:GitHub 上的我的自有克隆作为拉取请求的一部分),要么在第一次推送之前进行变基。

这是使用变基但不经常强制推送的工作流程的核心:直到准备好之前都不要发布内容,在推送后不要变基。


谢谢Dan。你能告诉我如何实现上述内容吗?这不就是适用于rebase的情况吗? - Roy Truelove
2
如果你将所有的工作都隔离到主题分支中,那么它为rebase设置了一个良好的场景。你可以将新拉取的更改rebase到你的主题分支中,但是当你完成了该分支的更改后,你需要将该分支merge回主开发分支。 - redhotvengeance
1
问题在于您已经发布了该分支 - 因此您需要强制推送到存储库。您需要放弃其中之一:以您目前的方式发布,或者进行变基。抱歉。 - Daniel Pittman
似乎对于这种情况,变基不起作用。v1.0不是一个主题分支,而是一个发布分支,因此它永远不会消失并且必须被发布。 - Roy Truelove
PR 评审期间,您将始终首先发布分支。 - Drenai

5
我认为在没有误推的情况下,这种rebase-then-force-push模式有一个很好的使用案例:通过多个位置(计算机)独自在特性分支上工作。我经常这样做,因为有时候我会在办公室用我的台式电脑工作,有时候又会回家或客户现场用我的笔记本电脑工作。我需要定期rebase来跟上主分支和/或使合并更加清晰,但是当我离开一台机器去另一台机器上工作时(只需拉取),我还需要进行force-push。只要我是唯一在该分支上工作的人,这个方法就非常好用。

2
我有相同的工作流程(从多台电脑/位置工作)。所以,假设您正在处理一个名为'mytopic'的主题分支。只要您始终将本地的一次性分支(仅是'mytopic'分支)rebase到“master”,然后将其合并回'mytopic',则永远不必强制推送。OP的情况略有不同,因此在这种情况下可能需要强制推送。但是,我认为OP重新定位的方式不正确--如果他按照我描述的方式操作,就不需要强制推送了。 - bwv549

4

这是我使用的方法(假设您的分支名称为foobar):

git checkout master              # switch to master
git rebase   foobar              # rebase with branch
git merge -s ours origin/master  # do a basic merge -- but this should be empty
git push origin master           # aaand this should work

8
重置主分支看起来很奇怪。 - Emil Vikström
2
git 不是没有个性的。 - redolent
1
git merge -s ours origin/<branch> 是我们解决问题的方法。 - Max

1
tl;dr:与共享分支合并,使用个人分支进行变基。 --force-with-lease 是替代强制推送的更安全的选择,可帮助你在不破坏性地实现 git nirvana。

一个经常被使用的团队工作流程的一般规则是,对于共享分支(即 master 或 develop 分支),使用 merge,而在自己的功能分支上工作时使用 rebase。 这是典型的功能分支生命周期。

git checkout master
git checkout -b new-feature
git commit -am "commit new work"
git push -u origin new-feature
# have code reviewed, run CI, etc.,
# meanwhile master has new commits
git checkout master
git pull origin
git checkout new-feature
git rebase -i master # -i for interactive rebase allows you to squash intermediate commits
git push --force-with-lease
git merge master

我们所做的事情的简明英文版:
1. 在主分支上创建一个新分支 2. 在该分支上进行工作并推送到远程 3. 从主分支上进行变基操作 4. 使用force-with-lease将工作推送到远程 5. 将其合并到主分支上,使用非常干净的git日志,减少了从共享分支到最新主分支(共享分支)的多个合并所带来的混乱
第四步非常重要,也是我开始倡导使用变基的主要原因之一。 force-with-lease检查远程是否添加了任何新提交。如果你的git push被证明是破坏性的,它就不会推送!
我希望这能让某些人更加有信心使用变基。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接