如何修复级联分支变基混乱

How to fix cascading branches rebasing mess

我们有一个工作流,其中 只有一个 团队成员在多个功能分支上工作。工作是这样的,每个下一个分支都依赖于他所做的前一个分支。默认分支是 develop.

让我们说这个场景:

  1. 他创建 featureA 分支,执行工作,推送分支,并在 GitHub
  2. 上创建 PR
  3. 他创建了 featureB 分支(基于 featureA 分支),完成工作并 PRs
  4. 他创建了 featureC 分支,(基于 featureB)完成了工作并对其进行了 PR
  5. 他创建了 featureD 分支,(基于 featureC)完成了工作并对其进行了 PR

None 个 PR 尚未合并。

现在,项目经理介入并开始合并。以这种方式合并:

  1. 项目经理将 featureA 合并到 develop
  2. 开发者在他这边做:

    git checkout develop
    git fetch origin
    git rebase origin/develop
    git checkout featureB
    git rebase origin/develop
    git push origin featureB
    

此时我们得到错误:

machine /c/Work/ (featureB)
$ git push origin featureB
To https://github.com/x.git
 ! [rejected]        featureB -> featureB (non-fast-forward)
error: failed to push some refs to 'https://github.com/x.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

为什么会这样?

我们认为将 featureB 变基到 origin/develop(合并后现在包含 featureA)将使 featureB 准备好推送。但显然我们看到了错误。

解释所发生情况的最简单方法是查看存储库的历史记录。这是您的历史记录在合并前的样子(精简版):

*--*--*--* [develop, origin/develop]
          \
           *--*--* [featureA, origin/featureA]
                  \
                   A--B--C [featureB, origin/featureB]

与post-合并:

*--*--*--*---------* [develop, origin/develop]
          \       /
           *--*--*
                  \
                   A--B--C [featureB, origin/featureB]

然后你将 featureB 重新设置为 develop:

*--*--*--*---------* [develop, origin/develop]
          \       / \
           *--*--*   A'--B'--C' [featureB]
                  \
                   A--B--C [origin/featureB]

此处,A'B'C'包含与ABC相同的更改,分别 但它们不是相同的提交 ,因为 A' 具有不同的父提交。

因此,在每次变基之后,您必须强制推送变基分支:

git push --force-with-lease origin featureB

(--force-with-lease 确保自上次获取以来没有推送新的提交。虽然这里可能并不严格需要,但最好养成在 --force 上使用它的习惯.)

正如我在上一张图中看到的那样,任何时候分支(例如featureB)和它的远程跟踪分支(例如origin/featureB)已经分叉,您必须强制推送。因此,只要重新设置已经推送到远程的分支,就需要这样做。