在我的项目中,我几个月前发布了一个版本。在该版本之后,我对主分支进行了许多更改。
如果我遇到上一个版本中存在的一些错误,我会在主分支上修复它们,然后将它们挑选到我在上一个版本中创建的分支中。然后我可以提供一个只有错误修复的新版本,而不发布 master 分支上未完成的工作。
当我尝试为发布分支挑选某个错误修复时,我遇到了合并冲突。
据我了解,挑选某个提交会向目标分支引入一个新的提交,并在挑选的提交中完成更改。
但是,当我尝试修复合并冲突时,似乎 git 在主分支上应用了更改,这些更改不是由樱桃选择的提交引入我的发布分支的。樱桃选择的提交只在冲突文件中引入了几行。但是,当我尝试解决冲突时,我看到文件中还引入了其他几行,这些行被添加到具有不同提交的主分支中。
有人可以解释为什么将来自樱桃选择提交以外的提交的更改引入我的发布分支吗?
据我了解,樱桃选择某个提交会向目标分支引入一个新的提交,并在樱桃选择的提交中完成更改。
这是正确的。 但是,这些更改可能无法完全应用,在这种情况下:
。我遇到了合并冲突。
此时,git cherry-pick
正在进行三向合并,这需要选择一个合并基础。
我记得,哪些文件或提交用作合并基础部分取决于您的 Git 版本。 现代 Git,如果你运行git cherry-pick
,使用精心挑选的提交的父级作为合并基础,但至少一个表单(使用git am
或git apply
和--3way
选项,git rebase
仍然可以这样做)可以使用git diff
输出的index
行来挑选文件的早期版本。 最后,这可能无关紧要。
在任何情况下,合并实际上都会从基本提交运行git diff
到两个"提示"中的每一个(樱桃选择的提交,以及您尝试应用樱桃选择的 HEAD 提交)。 要直观地查看正在发生的事情,您应该像往常一样从绘制提交图开始。 (我没有你的存储库,所以我会画一个不同的图表,希望它足够接近。 但是你应该绘制自己的——或者让 Git 来做,或者使用gitk
或类似的东西。
o--@ <-- branch (HEAD)
/
...--o--o
I--P--C--o <-- otherbranch
我在这里为各种提交提供了单字母名称:C
是我们即将挑选的提交,P
是它的父级。 我在这里将我们当前的 (HEAD) 提交标记为@
,尽管所有实际工作都将在索引和工作树中进行。 (幸运的是,git cherry-pick
要求索引和工作树是"干净的",除非你使用-n
将多个樱桃组装成一个大选择,所以索引和工作树无论如何都会匹配提交@
。 而且,我将提交I
标记为"重要"。
现在,考虑如果我们进行三向合并,P
作为基础,C
作为其中一个提交,@
作为另一个提交,会发生什么。 当我们计算将P
更改为C
的指令时,我们得到了我们想要应用的差异:这非常简单。 但是当我们计算将P
更改为@
的指令时,嗯,呃。
我们在I
中做了一些重要的更改。 这些更改是P
的一部分,即它们在我们的合并基础中。 但他们不在@
. 合并的含义是,Git 会将这些重要的更改视为我们试图撤消的事情。 事实上,他们是! 我们没有挑选I
本身,因此我们必须撤消这些I
更改才能应用C
的更改。
只要我们"撤消"的那些I
更改一开始就不@
,并且不会影响C
的任何更改,我们都很好:它们已经撤消了。 如果出于某种偶然或目的,这些I
更改之一是@
(也许是通过@
的父母),那么这些更改甚至不在我们首先试图撤消的集合中,所以我们又很好。 当这些变化与P
到C
的变化相冲突,甚至只是与的变化相冲突时,我们就会遇到问题。
在这种情况下,Git 将在两个合并冲突区域之一中显示一些I
更改。 这些是我们试图挑选的部分。 它们不一定得到应用,它们只是我们必须解决的冲突的一部分。 如果你merge.conflictStyle
设置为diff3
——我通常建议这样做——I
更改将显示为合并库的一部分,因为合并库是提交P
,它本身基于I
(即,P
的快照包含来自I
的代码,除非我们在制作P
时更改了它)。
所以,我并不完全清楚你在问什么,但在合并冲突区域看到与你正在挑选的部分无关的变化是正常的。
我看到文件中还引入了其他几行,这些行被添加到具有不同提交的主分支中
确保您在该提交时没有不需要的更改。
$ git show <commit-sha>
挑选提交。
$ git checkout <release-branch>
$ git cherry-pick <commit-sha>
最好手动解决冲突。
或者,如果要保留提交的更改,请接受theirs
否则接受ours
(保留发布分支更改)
$ git checkout --theirs -- .
Or,
$ git checkout --ours -- .
$ git status # see the changes
$ git add .
$ git commit -m 'Fix conflicts'
$ git push origin HEAD
替代方法:如果要从目标提交到发布分支进行少量文件更改,则此解决方案将有效。
樱桃选择的提交只在冲突文件中引入了几行
$ git checkout <release-branch>
$ git checkout <commit-sha> <file> . # change the <file> to commit's version
$ git add .
$ git commit -m 'Fix the bug'
$ git push origin HEAD