我应该将 master 变基到一个被推送的分支上吗?

Should I rebase master onto a branch that's been pushed?

我们在我们的小开发团队中使用 feature branch workflow。我们目前正在处理一个大型项目,因此其中一位开发人员已将他们的功能分支推送到 origin,其他人都可以在那里签出他们自己的本地副本。

[leonard@dev public]$ git branch -avv
  master                        9d53b40 [origin/master] Fix reviews
* responsive                    0c04643 [origin/responsive] Add media queries
  remotes/origin/HEAD           -> origin/master
  remotes/origin/master         9d53b40 Fix reviews
  remotes/origin/responsive     0c04643 Add media queries

在 master 上开发时,我们创建功能分支(即 master_hotfix),然后当我们准备合并它时,我们首先将 master 变基到它,然后再这样做。这给了我们一个我们喜欢的很好的线性历史。我们认为这也是对我们的响应式项目执行此操作的最佳方式,因此我们将基于响应式分支创建一个新分支(即 responsive_some-feature)。同样的git pullgit rebase responsive responsive_some-feature也可以在这里使用。

但我们对是否应该(如果是,在什么时候)将 master 变基到 responsive 有点困惑?在 responsive 分支被推送到 origin 之前,将 master 变基到它很简单,但是将 master 变基到 responsive 然后 responsiveresponsive_some-feature 正确吗?当我 时,我看到(以及一些冲突):

# On branch responsive
# Your branch and 'origin/responsive' have diverged,
# and have 112 and 109 different commit(s) each, respectively.
#
nothing to commit (working directory clean)

通常此时我会看到一个干净的工作目录,然后我可以在其中检出 master 并合并我的功能分支。唉,在这个 rebase 之后,来自 master 的提交就在那里, responsive 中的新提交在它们之后,正确地,但这是正确的方法吗?我应该如何进行,或者我应该使用不同的方法使 responsivemaster 保持同步?

编辑:我做了一张图来更好地说明我的工作流程:

TLDR

Should I rebase master onto a branch that's been pushed?

不,您应该遵循一般规则 - never rewrite the public history(=永远不要对已推送的分支进行变基)。

对于简单的功能分支,您可以在推送之前对其进行变基(重写历史记录)。或者,至少,如果您遇到 branches have diverged 情况,您可以确保只有一名开发人员使用功能分支并强制推送。

responsive 分支的情况下,它是 public 并且被许多开发人员使用。 所以你不能在 master 之上变基,为这个分支做常规合并。

注意:如评论中所述,您的 post 中的术语有点令人困惑。所以我假设 ...we first rebase master on to it [feature branch]... 实际上意味着相反,并且你在 master 之上重新设置功能分支。

说明

具有特征分支的 "normal"(无历史重写)流程如下所示:

1) we have a feature branch 

... O ---- O ---- A ---- B  master
                   \
                    C       feature-branch

2) we do the merge, usually with merge commit (D)
   sometimes it can be fast-forward without the merge commit

... O ---- O ---- A -- B -- D -  master
                   \       /
                    -- C --      feature-branch

与re-base的流量:

1) we have a feature branch 

... O ---- O ---- A ---- B  master
                   \
                    C       feature-branch

2) we rebase feature branch on top of master
   note, that we changed the history and have new C' commit on 
   the feature branch

... O ---- O ---- A ---- B  master
                          \
                           C'  branch_xxx (feature branch)

3) we do the merge, master is fast-forwarded since there is nothing new
   on master

... O ---- O ---- A -- B -- C' -  master (fast forwarded)
                        \  /
                         C'      feature-branch

如果只有一个开发人员在功能分支上工作,效果会很好。 所以历史重写是安全的。

但是当您添加 responsive 分支时,据我了解,流程是这样的:

1) we have a feature branch 

... O ---- O ---- A ---- B       master
                   \
                    R1 -- R2     responsive
                           \
                            F1   responsive-feature-branch

2) now see what happens if `responsive-feature-branch` is still active (someone works on it) and we rebase the `responsive` on top of `master`:

... O ---- O ---- A ---- B                master
                  \       \
                   \       R1' -- R2'     responsive'
                    \
                     R1 -- R2             responsive
                            \
                             F1           responsive-feature-branch

你看到问题了吗?现在你有两个 responsive 分叉的分支(另请参阅我的 post 中的解释)。

您可以使用“-f”(强制)标志推送重新设置的 responsive',但是在 responsive-feature-branch 上工作的开发人员会做什么?他将只有新的上游历史记录,并且必须相应地重写 his-own 本地历史记录。

如果您确定没有人拥有来自 responsive 的活动分支,则可以执行此强制更新,然后每个人都需要更新他们的本地存储库。

但我不推荐这样做,因为你不能保证没有活动的 sub-branches 并且总有一天你肯定会发现你的存储库已经搞砸了。 我认为相当线性的历史不值得您花时间解决这些问题。