我有一个项目(基于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
分支的原始提交。到目前为止一切都很正常。
现在,我想做的是将M
、Y
和Z
一起放入master
中。但这里有一个警告-我不希望W
或X
在master中。为什么?CCD_ 13和CCD_;Bump to our hotfix release version";在CCD_ 15中没有位置。所以最后,我希望master
是A - B - C - D - Y - Z - M
。
如果我在M
上git cherry-pick
,我只得到M
,并且我丢失了Y
和Z
的历史。这就是我所做的,但后来我在git blame
中失去了功能,作者最终会被隐藏(因为GitHub提交的合并是由合并者而不是原始提交者编写的)。
如果我在M
上git merge
,我会得到整个分支,包括我不想要的W
和X
。
如何才能做到这一点?
让我再向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分支后,新的提交(B
、C
、D
)已添加到Master分支中。
现在,这就是我问题的关键:我想将Pull Request的整个历史记录——来自Alice的原始提交(Y
和Z
)和来自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
结束。)
那么,如果不在标记为W
和X
的提交中引入仅限版本的更改,如何做到这一点?这里有两种方法:
- 您可以进行两次合并。首先在
X
中进行合并,但使用-s ours
选项放弃更改。然后在release
中合并。除了W
和X
中的变化之外,最终结果将具有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
合并是不寻常的,因为它完全忽略了合并中的所有更改,因此我建议在第一次合并时,在提交消息中添加一条注释,大意是";合并并忽略发布版本更改";所以合并的目的很清楚。
- 另一种方法是只对
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
中。但是,如果我一开始总是像你描述的那样只有一个版本升级,我可能不会像以前那样花时间自动撤销版本文件。
您的关系图缺少A
和Y
之前的历史记录(即提交),但通常要做的是将错误修复直接合并到所有受影响的分支中。在这里,你会得到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