将git commit应用于所有分支

21
如果我在分支branch_a中修复了一个bug,希望将更改应用于所有分支,是否有一种方法可以同时应用到所有分支,而不必逐个检出每个分支?
git commit -m 'commit msg' # on branch a 

git checkout branch_b
git cherry-pick branch_a

git checkout branch_c
git cherry-pick branch_a

我希望有一个 git commit --to-all-branches 命令,如果可能的话,尝试将更改传播到所有分支。

编辑

为了澄清我的情况,我编写用于计算问题的代码。 我经常陷入这样的情况:不清楚哪种方法最好解决给定的问题。 所以我创建了一个分支。 这些分支往往会发散,并且更像是分叉。 然而,为了保持所有文件在原处,我只使用一个 git 存储库来管理多个分支。 在所有分支/派生都相关的错误情况下,我正在寻找一种自动更新所有分支的方法。


我强烈建议在日常合并时使用git merge而不是git cherry-pick。 - Peter Bratton
1
频繁地将相同的补丁应用于大量分支,这表明您正在做一些奇怪的事情,而不应该这样做。例如,您可能正在使用分支,而静态配置更合适。 - Magnus Bäck
1
Atlassian Stash支持自动分支合并,但这不是Git的原生功能。 - Todd A. Jacobs
2
该问题的另一个用例是存储库根目录中的存储库侧ReadMe文件。分支在不同时间点“分支”,因此功能分支可能在repo-root中具有过时的ReadMe。因此,当我更新repo-root中的ReadMe时,我希望在所有分支中更新该ReadMe,因为它仅包含存储库本身的一般信息。 - Dohn Joe
2个回答

15
没有特别的方式,严格来说,“是的,但这样做同其他方式一样需要同样多的工作”。新提交总是添加到“当前分支”,即使它是一个“游离 HEAD”状态。(下面,我将展示如何使用“游离 HEAD”状态来完成此操作,虽然如果您要向现有分支添加提交,则比仅检出更加麻烦)。假设您有类似以下代码:
A-B-C          <-- br1
   \
    D   F      <-- br2
     \ /
      E
       \
        G      <-- br3

如果您需要对 CFG 进行某些修复,而且还需要额外的修复 X,则应该按照以下步骤进行操作:

A-B-C-X1       <-- br1
   \
    D   F-X2   <-- br2
     \ /
      E
       \
        G-X3   <-- br3

请注意,所有三个 Xn 提交都是不同的提交,因为它们有不同的父提交。然后,您必须将 "补丁 X" 添加到提交 C 中,然后将 "补丁 X" 添加到提交 F 中,最后将 "补丁 X" 添加到提交 G 中。
请注意,不能保证例如从 CX1 的更改与此处从 FX2 的更改完全匹配。您可以按照通常的方式构建任何三个 Xn 提交之一。然后(如在您的问题中),您只需移动到其他分支并使用 git cherry-pick 创建(并可能解决冲突)其他 X。但是,您需要 "在" 这些分支上添加提交。
$ git checkout br1
... make fix, "git add", "git commit" to create X1

$ git checkout br2
Switched to branch 'br2'.
$ git cherry-pick br1    # take diff of `C`-vs-`X1`, apply to `F` to make `X2`
... etc

对于需要复制补丁的所有分支重复此操作(如果必要,可以修改以适应该分支)。


这样做有替代方案。例如,假设分支br1实际上是正常的,并且您发现提交E存在问题,需要修复,影响提交FG。进一步假设没有其他人拥有提交FG,或者您愿意强制那些拥有这两个提交的人从即将进行的操作中恢复大量工作。在这种情况下,您可以检出提交D并创建一个新的提交E',它来自于D。让我们绘制起点,省略AC。我们将使用git checkout D(通过其SHA-1或等效地使用br2~2来命名)来获取“分离的HEAD”:

D       <-- HEAD
|
|   F   <-- br2
 \ /
  E
   \
    G   <-- br3

现在:

$ git cherry-pick -n br2^  # make a copy of E but don't commit yet
# edit to fix it
$ git commit               # make new commit E' that's fixed

一旦提交完成,我们就会得到以下结果(仍然是“分离的HEAD”状态):

  E'    <-- HEAD
 /
|
|
D
|
|   F   <-- br2
 \ /
  E
   \
    G   <-- br3

现在我们可以将提交记录F复制到F'

$ git cherry-pick br2

提供:

    F'  <-- HEAD
   /
  E'
 /
|
|
D
|
|   F   <-- br2
 \ /
  E
   \
    G   <-- br3

我们现在已经准备好让br2指向提交F'了。
$ git branch -f br2 HEAD

提供:

    F'  <-- HEAD, br2
   /
  E'
 /
|
|
D
|
|   F   [abandoned]
 \ /
  E
   \
    G   <-- br3

(这就是我之前写的“或者严格来说”的部分:您可以将提交添加到存储库,然后移动分支标签,使它们标记新的提交链,而不是旧的提交链。所有添加的提交都会移动HEAD:只是如果HEAD是对分支的引用,它们在工作时也会将该分支向前移动一步。让HEAD引用一个分支是“正常”工作的方式,但是您可以在“分离的HEAD”模式下使用git branch -f进行伪造。在这种情况下,我正在这样做以构建新的br2,而不使用分支名称,然后在准备好后将分支名称移动到新的提交链。)
现在我们需要将G复制到G',并将G'附加到E'。以下是步骤:
$ git checkout br2^      # get back on E' as a detached HEAD
[git says stuff here about moving the detached HEAD]
$ git cherry-pick br3    # copy commit G
$ git branch -f br3 HEAD # and move br3 label here

以下是我们复制FF'所做的事情(或者说类似的事情):

    F'  <-- br2
   /
  E'
 / \
|   G'  <-- HEAD, br3
|
D
|
|   F   [abandoned]
 \ /
  E
   \
    G   [abandoned]

当你完成所有操作后,应该使用git checkout somebranch命令,回到“分支”状态,远离“分离头指针”状态。

正如评论中所指出的那样,需要广泛地应用补丁可能意味着整个过程存在问题。(但这就是修复“零日漏洞”的情况,当你有许多不同的产品都共享代码库并存在“零日漏洞”时,就会出现这种情况。)


6

这个功能不存在,因为每次合并都可能导致不同的冲突,需要用户介入解决。您需要编写脚本来实现您想要的功能。


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