如何合并/挑选单个提交



我有一个项目(基于GitHub),它有一个类似的分支结构

master:   A - B - C - D

release:      W - X - M
/
bugfix:       Y - Z

因此,一旦bugfix被合并,release将具有A - W - X - Y - Z - M,其中M是合并提交并且Y&Z是来自bugfix分支的原始提交。到目前为止一切都很正常。

现在,我想做的是将MYZ一起放入master中。但这里有一个警告-我不希望WX在master中。为什么?CCD_ 13和CCD_;Bump to our hotfix release version";在CCD_ 15中没有位置。所以最后,我希望masterA - B - C - D - Y - Z - M

如果我在Mgit cherry-pick,我只得到M,并且我丢失了YZ的历史。这就是我所做的,但后来我在git blame中失去了功能,作者最终会被隐藏(因为GitHub提交的合并是由合并者而不是原始提交者编写的)。

如果我在Mgit merge,我会得到整个分支,包括我不想要的WX

如何才能做到这一点?


让我再向Y澄清一下X:

我们的项目完全基于GitHub,使用fork和PR模型(在那里很正常)。

A之前的内容无关紧要;我们的发布分支是基于A的,然后我们添加了W和X来进行发布(标签在X上)。

因此,Random Contributor Alice从我们的发布分支进行了一个错误修复。

release:      W - X

bugfix:               Y - Z

我们的团队成员Bob将该pull请求合并到我们的Release分支中。

release:      W - X   - - -  M
       /
bugfix:               Y - Z

更重要的是,一旦bugfix被合并,我或项目中的任何人都无法接触它。它在Alice的项目分支上,我们的发布分支中有这个:

A - W - X - Y - Z - M

自从我们创建了Release分支后,新的提交(BCD)已添加到Master分支中。

现在,这就是我问题的关键:我想将Pull Request的整个历史记录——来自Alice的原始提交(YZ)和来自Bob的合并细节(通过合并提交M)——获取到我们的master分支中。

我很乐意选择合并,但由于GitHub处理PR合并的方式不同步,这意味着如果我这样做,Alice(和她的提交)的所有痕迹都会丢失。这是我们想要避免的。

首先对以下语句进行澄清:

我不想在master中使用W或X。为什么?W和X是类似于"0"的提交;Bump to our hotfix release version";在master中没有位置。

通常,并不是说不希望master中的提交,而是说不希望从master中的这些提交中进行更改。考虑到这一点,如果是我(我这样做),我会将release合并回master!有两种方法可以做到这一点,这样你就可以完成你想要的,并且仍然可以实现将整个release分支合并回master的所有其他好处,其中包括:

  • 假设这是一个非常糟糕的一天/一周,并且您在release分支上修复了10个错误。你真的想把它们单独合并回来吗?(可能不会。)
  • 如果你不需要旧的发布分支,那么不必保留它们是很好的。如果您能够将发布分支合并到master中,则可以删除它们。您需要的关于任何先前版本的所有信息都包含在master
  • master可以访问实际发布的提交ID以及任何相关的标记。(IMHO,这是最重要的原因,也是为什么我希望在发布之前的所有提交都以master结束。)

那么,如果不在标记为WX的提交中引入仅限版本的更改,如何做到这一点?这里有两种方法:

  1. 您可以进行两次合并。首先在X中进行合并,但使用-s ours选项放弃更改。然后在release中合并。除了WX中的变化之外,最终结果将具有release上的所有内容。例如:
git switch master
git merge -s ours X # or the tag name you used here
git merge release

注意,-s ours不应与-X ours(或theirs)混淆,后者完全不同,是关于自动冲突解决的。我认为-s ours合并是不寻常的,因为它完全忽略了合并中的所有更改,因此我建议在第一次合并时,在提交消息中添加一条注释,大意是";合并并忽略发布版本更改";所以合并的目的很清楚。

  1. 另一种方法是只对release分支进行一次合并,但在提交撤消版本更改之前停止。这可以很容易地在脚本中实现自动化。例如:
git switch master
git merge release --no-commit
# now the version file changes will be staged, so unstage them:
git reset some-path/some-version-file
# now restore the version file to the version on the master branch:
git restore some-path/some-version-file
# repeat the reset and restore commands for all version files modified in W and X
...
# and finally complete the merge
git commit # or git merge --continue

我个人做第二种选择。(我的脚本撤消了由生成自动更新的8个版本文件。)我更喜欢选项2的原因是,有时我的release分支上有多个生成,所以我需要多次进行双重合并,在-s ours合并和实际合并之间交替进行,以将release分支的全部内容返回到master中。但是,如果我一开始总是像你描述的那样只有一个版本升级,我可能不会像以前那样花时间自动撤销版本文件。

您的关系图缺少AY之前的历史记录(即提交),但通常要做的是将错误修复直接合并到所有受影响的分支中。在这里,你会得到git switch master,然后是git merge bugfix

(我还建议将分支名称作为带有箭头的实体放入,箭头指向当前分支上的最后一次提交,因为这就是名称在Git中的实际工作方式。通过添加更多提交来更新分支只需将箭头移动到新的最后一次提交。如果你"重置提交",则会将箭头向后移动——提交到提交箭头的方式,在Git中——到较旧的提交,将较新的提交从分支的末尾删除。)

好吧,这并不是一个真正的答案,而是对最初的cherry-pick想法的一种变通方法。

hub pr提供了关于谁提交了PR的详细信息,所以至少,我可以更改樱桃选择承诺,以显示谁写了PR。我想这就足够了,因为很明显,这永远不会像我希望的那样奏效。

对于任何好奇的人来说,这是为Jellyfin准备的,这是我们用来将PR从发布分支后台移植回master的脚本,并进行了调整,以显示PR的作者。希望另一个项目不会对此视而不见。

https://github.com/jellyfin/jellyfin-build/blob/master/backport-prs#L82

最新更新