5

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

所有的困难是分支已经被合并回“master”(否则使用 rebase --onto 真的很容易)

  • 我们不想以其他方式更改流程,因为 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(通常我如何在 git 中反向移植一个提交?):

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

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

2)变基--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) “reset hard master before the merge”(到第一个分支点) 嗯,似乎很难描述和做。

所以,我正在寻找的是一种可移植的 git (没有隐含的 bash/grep/cut/sed)方式;

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

2)获取已经合并回“master”的分支的第一个分支点的提交

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

2.b)我在这里找到了用 Git 找到一个分支点?我稍微调整了以下 bash 命令:

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

但他不是一个 git 简单或可移植的命令(即没有 Bash 或 Cygwin 工具就不能工作)

4

2 回答 2

6

作为记录,这里是我最终使用的两个解决方案,基于Craig Otis 的答案,这里指向lindes 的“Finding a branch point with Git”的答案,使用 Bash 别名“.gitconfig”文件(在 Linux 下测试Ubuntu 12.10)

初始状态,其中分支 "fix/123" 已经合并回 "master"

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

1)将分支“fix/123”从“master”重新定位到“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 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)
于 2013-05-23T16:11:04.287 回答
4

我对 Git 还很陌生,所以请原谅我对您的情况可能造成的任何误解。

使用此代码段:

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

从这个答案:@lindes 回答“用 Git 找到一个分支点?”

如果你有一棵这样的树:

初始树

那么上述命令的结果some-fixfix/123是:

f1efa4a9c029281a22d4fa8dd6607c523e7191f5

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

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

$ git merge-base master some-fix
1b9ebb7157a958e9adc3b8eda9bf4175cd821c4b

然后,使用修订范围的精选,您可以将这些更改拉入:

$ git cherry-pick f1efa4a..1b9ebb7

你最终得到:

最终树

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

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

于 2013-05-22T12:05:34.700 回答