如何git backport(rebase / cherry-pick)已经合并的分支

时间:2013-05-22 11:08:03

标签: git branch rebase cherry-pick

在我们的Git流程中,“master”是当前发布周期的主题和修复分支的集成分支,但我们还维护一个“稳定”分支,我们必须谨慎地向后移植已经在master上成功测试的一些修复

所有困难都是分支已经合并回“master”(否则使用rebase非常容易 - 很多)

  • 我们不希望以另一种方式更改流程,因为a)我们不想修复“稳定”分支中的所有内容,并且b)我们有时必须对“稳定”分支进行一些更改我们不想合并“master”。
  • 显然,我们无法将修复程序合并到“稳定”分支中,因为这会向后移植许多不需要的功能。

我描述的初始情况图:

          I--J (stable)
         /
        /
       /
- A - B - C - D - E - F - G  (master) 
              \      /
               X -- Y (fix/123)

我们想要达到的情况图表:

          I--J (stable)
         /    \
        /      X'- Y' (fix/123-stable)
       /
- A - B - C - D - E - F - G  (master) 
              \      /
               X -- Y (fix/123)

更复杂的情况是可能的,例如多次合并以完成修复:

- A - B - C - D - E - F - G - H (master) 
               \     /       /
                X - Y ----- Z (fix/123)

但是我们不允许合并到修复分支,所以我们永远不会有这样的东西:

- A - B - C - D - E - F - G (master) 
               \   \     /
                X - Y - Z (fix/123)

为实现这一目标,我们可以挑选或修改修复分支:

1)cherry-pick(典型How do I backport a commit in git?):

git checkout -b fix/123-stable stable
git cherry-pick X Y

这似乎很容易,但在处理现实生活中的例子时并非如此;总是存在忘记一些提交或挑错的风险!

2)rebase --onto(https://www.kernel.org/pub/software/scm/git/docs/git-rebase.html):

2.a)“不工作”的方式:

git rebase --onto stable master fix/123

由于fix / 123已经合并为master,因此无效!  2.b)“不比樱桃挑选更好”的方式:

git rebase --onto stable D fix/123

这仍然存在风险,因为您需要使用D的SHA(例如,不是X)。

2.c)“使用临时起始参考”方式:

git tag begin D
git rebase --onto stable begin fix/123
git tag -d begin

这改善了以前的情况,因为标签可以更容易地进行操作或在图形工具中对其进行描绘,但仍然需要大量的手动工作。

3.d)“合并前重置硬主机”(到第一个分支点) 哼,似乎很难描述和去做。

所以,我正在寻找的是git 便携式(没有bash / grep / cut / sed暗示)的方式;

1)列出已经合并回“master”的分支上的所有提交(此处为X和Y,以及“多合并”情况下的Z)以便轻松地选择它们

2)获取已经合并回“master”

的分支的第一个分支点的提交

2.a)这不能通过“git merge-base”命令完成,因为合并已经完成(甚至多次)

2.b)我在这里找到Finding a branch point with Git?以下bash命令我稍微调整了一下:

git rev-list --boundary --date-order --reverse fix/123..master | grep -m 1 - | cut -c2-

但是他不是一个简单易用的便携式命令(即没有Bash或Cygwin工具就无法工作)

2 个答案:

答案 0 :(得分:5)

对于记录,这里是我最终使用的两个解决方案,基于answer of Craig Otis here指向answer of lindes on "Finding a branch point with Git",使用Bash别名“.gitconfig”文件(在Linux Ubuntu 12.10下测试)< / p>

初始状态,分支“fix / 123”已经合并回“master”

        I--J (stable)
       /
- A - B - C - D - E - F - G  (master) 
               \     /
                X - Y (fix/123)

1)将分支“fix / 123”从“master”开始变为“稳定”(对于大多数人来说,这是一个通用答案):

将以下Bash别名添加到“.gitconfig”文件中:

[alias]
    oldest-ancestor = !bash -c 'diff -u <(git rev-list --first-parent "${1:-master}") <(git rev-list --first-parent "${2:-HEAD}") | sed -ne \"s/^ //p\" | head -1' -
    rebase-onto     = !bash -c 'git rebase --onto $1 `git oldest-ancestor $2 $3` $3' -

然后使用命令行:

git rebase-onto stable master fix/123

你在这里:

          I--J (stable)
         /    \
        /      X'- Y' (fix/123)
       /
- A - B - C - D - E - F - G  (master) 
               \     /
                X - Y

2)从“master”开始重新分支“fix / 123”分支,在“stable”上创建一个新的分支“fix / 123-stable”(这是更具体的答案我我要用了。)

将以下Bash别名添加到“.gitconfig”文件中:

[alias]
    oldest-ancestor = !bash -c 'diff -u <(git rev-list --first-parent "${1:-master}") <(git rev-list --first-parent "${2:-HEAD}") | sed -ne \"s/^ //p\" | head -1' -
    rebase-onto     = !bash -c 'git branch $4 $2 && git rebase --onto $3 `git oldest-ancestor $1 $4` $4' -

然后使用命令行:

git rebase-onto master fix/123 stable fix/123-stable

你在这里:

          I--J (stable)
         /    \
        /      X'- Y' (fix/123-stable)
       /
- A - B - C - D - E - F - G  (master) 
               \     /
                X - Y (fix/123)

答案 1 :(得分:4)

我对Git很新,所以请原谅我在你的情况下可能产生的任何误解。

使用此代码段:

diff -u <(git rev-list --first-parent fix/123) <(git rev-list --first-parent master) | sed -ne 's/^ //p' | head -1

从这个回答:@lindes answer to "Finding a branch point with Git?"

如果您有这样的树:

Initial Tree

然后,some-fix代替fix/123的上述命令的结果将是:

f1efa4a9c029281a22d4fa8dd6607c523e7191f5

创建初始修复分支的提交。

然后,您还可以快速merge-base运行以确定some-fix结束的位置:

$ git merge-base master some-fix
1b9ebb7157a958e9adc3b8eda9bf4175cd821c4b

然后,使用修订范围的樱桃选择,你可以将这些变化拉出来:

$ git cherry-pick f1efa4a..1b9ebb7

你最终得到:

Final Tree

其中包含来自初始修复分支的其他提交。您可能需要执行额外的checkout -b来创建fix/123-stable分支,而不是仅将其添加到stable,但方法应该相同。

请注意,我引用的答案提到将这个冗长乏味的diff命令安装为名为oldest-ancestor的别名,这样可以节省大量时间。