使用 rebase 向后移植 git 分支

Backporting a git branch with rebase

让我们考虑以下情况

    m1-m2------m3-------m4--------m5 (master)
        \                \
         \                \
          \                \---f1-f2-f3(feature)
           \                \
            \                \-P1-P2-P3(patch)
             \
              \
               r1-r2-r3-r4 (release)

Masterm5 提交,因为人们正在贡献,而 releaser4 完成某个版本后。

现在我在应用程序中发现了一个适用于所有版本的错误。出于某种原因,我从 m4 分支了一个分支(为什么不是 m5?可以说 m5 在那一刻还没有提交是现实的)并解决了 P1..P3 的问题。

对完成的工作感到满意,我将补丁合并到 m5 但我被要求将补丁反向移植到 release 并生成更新。

    m1-m2------m3-------m4--------m5-----------m6 (master)
        \                \                    /
         \                \                  /
          \                \-P1-P2-P3(patch)/
           \                \
            \                \                  
             \                \---f1-f2-f3(feature)
              \
               r1-r2-r3-r4 (release)

如果patch是单次提交,我会很容易做到

git checkout release
git cherry-pick patch

好的,但是 patch 是一系列提交。我想我应该变基。

问题是将 patch 变基到 release 涉及提交 m3,它不能是 release 分支的一部分。它可能是整个系列的提交。

所以场景如下。我知道 feature 生成的 从一个特定的提交(通常是我们工作流程中的一个标签),所以我想重新设置 m4 的所有提交(排除)包含 patch,将 release 指向新的 P3'

我曾尝试滥用 onto rebase命令的选项,所以我在这里寻求建议,因为我可能对rebase命令的了解不够

git checkout release #pick r4
git branch experiment #destructive actions will try not to destroy precious branches
git checkout experiment
git rebase --onto experiment m4 patch # detaches head, but I don't want that!

低于预期结果

    m1-m2------m3-------m4--------m5-----------m6 (master)
        \                \                    /
         \                \                  /
          \                \-P1-P2-P3(patch)/
           \                \
            \                \                  
             \                \---f1-f2-f3(feature)
              \
               r1-r2-r3-r4-P1'-P2'-P3' (release)

问题是:如何在不交互的情况下将这些补丁提交反向移植到较早的分支?

交互地(实际上这是一个答案),我可以做以下事情,特别是如果我通过问题 ID 跟踪提交:

git rebase -i patch
##and skip all commits until m4 (included)

但如您所见,我的问题是关于寻求一种自动化方式

您想要的是应用修订 m5m6 之间的差异。 git cherry-pick 可以在 -m 选项的帮助下做到这一点:

-m parent-number, --mainline parent-number

Usually you cannot cherry-pick a merge because you do not know which side of the merge should be considered the mainline. This option specifies the parent number (starting from 1) of the mainline and allows cherry-pick to replay the change relative to the specified parent.

因此步骤如下:

  1. 运行 git show m6 并注意 m5 的(基于 1 的)索引 k 16=] 行.

  2. git cherry-pick -m k m6

git rebase --onto experiment m4 patch 之后,您就快到了。 git checkout release;git reset P3' --hardgit branch -D release;git branch release P3'.

#create a new branch, based on `patch` and switch to it
git checkout -b backported-patch patch
#rebase this new `backported-patch` branch onto release:
git rebase --onto release m4 backported-patch
# now we have backported patch branch, merge it into release:
git checkout release
git merge backported-patch

顺便说一句,我认为最好将分支合并到分支的基础上,即 git rebase --onto m2 m4 backported-patch,在这种情况下,向后移植的补丁将可合并到它们两个,提供更清晰的历史记录。

因此,最终结果将是:

m1-m2------m3-------m4--------m5-----------m6 (master)
    \                \                    /
     \                \                  /
      \                \-P1-P2-P3(patch)/
       \                \
        \                \                  
         \                \---f1-f2-f3(feature)
          \--P1'-P2'-P3'(backported-patch)
           \           \
            r1-r2-r3-r4-M (release)

此外,不合并发布分支更改是个坏主意,即 r1-r4 提交应合并到 master 分支,- 使历史更清晰。

它给你:

m1-m2------m3-------m4--------m5-----------m6-----m7 (master)
    \                \                    /      /
     \                \                  /       |
      \                \-P1-P2-P3(patch)/        |
       \                \                        |
        \                \                       |
         \                \---f1-f2-f3(feature)  |
          \--P1'-P2'-P3'  ----------------------/
           \           \ /
            r1-r2-r3-r4-M (release)