cherry pick 问题:还应用了以前提交的更改

Issue with cherry pick: changes from previous commits are also applied

在我的项目中,几个月前发布了一个版本。在那次发布后,我在 master 分支上做了很多更改。

如果我遇到上一个版本中存在的一些错误,我会在 master 分支上修复它们,然后将它们挑选到我在上一个版本中创建的分支。然后我可以提供一个只修复错误的新版本,而不发布 master 分支上未完成的工作。

当我尝试对发布分支进行 cherry pick 某个错误修复时,遇到了合并冲突。

据我了解,cherry picking 某个提交会向目标分支引入新的提交,并在 cherry picked 提交中完成更改。

但是,当我试图解决合并冲突时,似乎 git 已经在 master 分支上应用了更改,这些更改不是由 cherry picked 提交引入到我的发布分支的。 cherry picked 提交仅向冲突文件引入了几行。但是,当我尝试解决冲突时,我看到文件中还引入了其他几行,这些行已添加到具有不同提交的 master 分支。

有人可以解释为什么将来自 cherry picked 提交以外的提交的更改引入我的发布分支吗?

I see that several other lines are also introduced to the file, which were added to master branch with different commits

确保您在该提交上没有不需要的更改。

$ 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

备选方案:如果您想从目标提交到发布分支进行少量文件更改,此解决方案将很有效。

The cherry picked commit only introduced couple of lines to the conflicted file

$ 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

As I understand, cherry picking a certain commit introduces a new commit to the target branch, with the changes done in the cherry picked commit.

没错。但是,这些更改可能无法完全应用,在这种情况下:

... I encountered a merge conflict.

此时git cherry-pick正在做三向合并,需要选择一个合并基

哪些文件或提交被用作合并基础,部分取决于您的 Git 版本,我记得。现代 Git,如果你 运行 git cherry-pick,使用精心挑选的提交的 parent as the merge base,但至少使用一种形式(使用 git amgit apply使用 --3way 选项,git rebase 仍然可以)可以使用 git diff 输出的 index 行挑选出文件的更早版本。说到底,这应该没什么大不了的。

在任何情况下,合并实际上都会 运行 git diff 从基本提交到两个 "tips" (精心挑选的提交和 HEAD提交您尝试应用樱桃选择的内容)。要直观地查看发生了什么,您应该像往常一样从绘制提交图开始。 (我没有你的存储库,所以我会画一个 different 图,希望它足够接近。但是你应该自己画——或者让 Git 画,或者使用 gitk 或类似的东西。)

          o--@         <-- branch (HEAD)
         /
...--o--o
         \
          I--P--C--o   <-- otherbranch

我在这里为各种提交提供了单字母名称:C 是我们要挑选的提交,P 是它的父提交。我在这里将我们当前的 (HEAD) 提交标记为 @,尽管所有实际工作都将在索引和工作树中进行。 (幸运的是 git cherry-pick 要求索引和工作树为 "clean",除非您使用 -n 将多个樱桃 assemble 合并为一个大采摘,因此索引和工作-树将匹配提交 @ 无论如何。)而且,我将提交 I 标记为 "important".

现在,考虑如果我们以 P 作为基础,C 作为一个提交,@ 作为另一个提交进行三向合并会发生什么。当我们计算将 P 更改为 C 的指令时,我们得到了我们想要应用的差异:这非常简单。但是当我们计算将 P 更改为 @ 的指令时,嗯,嗯。

我们在 I 中进行了一些重要更改。这些更改是 P 的一部分,即它们在我们的合并基础中。但在 @ 中它们是 而不是 。合并的含义是 Git 会将这些重要更改视为我们正在尝试 un-做的事情。事实上,他们是!我们没有挑选 I 本身,因此我们必须撤消这些 I 更改以应用来自 C.

的更改

无论那些 I 变化我们 "undoing" 不在 @ 开始不影响任何来自 C 的更改,我们很好:它们已经撤消。如果,由于某种机会或目的,其中一个 I 改变 @ 中的 (可能通过 @ 的父级),那么这些都不是即使在 set 中,我们首先尝试撤消,所以我们再次很好。当这些变化 冲突,甚至只是 (的上下文)冲突时,P-to-C 变化,我们有问题。

在这种情况下,Git 将在两个合并冲突区域之一中显示一些 I 更改。这些是我们试图挑选的部分。它们不一定被应用,它们只是我们必须解决的冲突的一部分。如果您将 merge.conflictStyle 设置为 diff3——这是我通常推荐的——I 更改将显示为合并基础的一部分,因为合并基础 提交 P,它本身基于 I(即,P 的快照包括来自 I 的代码,除了我们在制作 [=22] 时更改它的地方=]).

所以,我不完全清楚你在问什么,但 正常看到,在合并冲突区域,更改与你正在处理的位无关-采摘。