如何在提交树中的其他地方应用来自特定 Git 提交的更改?
How do I apply changes from a specific Git commit somewhere else in the commit tree?
假设我在 git 存储库 'master' 和 'feature' 中有两个分支。这两个分支在某些方面有所不同。现在我想从 'feature' 分支上的提交 '0123456789abcdef' 中对 'script.py' 进行确切的更改,并将这些更改应用到 [=24= 开头的 'script.py' 的相应行]分支。
git cherry-pick
对我来说似乎是显而易见的选择,但它并不完全符合我的要求。问题是 git cherry-pick
使 'master' 分支更新了 'feature' 上的所有更改,直到提交 '0123456789abcdef'。
我不希望应用所有这些更改。我只想要在提交“0123456789abcdef”中发生的确切更改 - 仅此而已。我认为如果我能够以某种方式利用共同的历史来找出相对于 'feature' 的提交,相应的更改行可能在 'master' 中移动的位置,而不是在 'feature' 上应用所有这些先前的更改,那将是明智的。 =24=].
我怎样才能做到这一点?当然,我可以从 git diff
的输出中复制并粘贴它,但是我对 Git 的了解有点好,在我看来它必须有更好的方法来做到这一点,我只是还不知道.
编辑: 看来上述行为一定是错误的结果,我无法再重现。基于,我重复了cherry-pick的正确过程,它产生了我想要的结果。
在此声明中:
git cherry-pick
seems like the obvious choice to me here, but it does not do exactly what I want. The trouble is that git cherry-pick
brings the 'master' branch up to date with all the changes on 'feature' up to commit '0123456789abcdef'.
您已将 cherry-pick 与合并混为一谈。如果你要 运行:
git checkout master
git merge 0123456789abcdef
that会找到master当前tip commit的merge base,然后commit 0123456789abcdef
,按你说的做。但是 git cherry-pick 0123456789abcdef
找到了 0123456789abcdef
的 parent 提交,然后在此处涉及的三个提交上调用 Git 的合并引擎。
效果是git cherry-pick
会找出从0123456789abcdef^
——0123456789abcdef
的parent——到0123456789abcdef
的变化,并应用到当前或 HEAD
提交。这会影响到不止一个文件,如果不止一个文件有任何从0123456789abcdef^
到0123456789abcdef
的差异(使用git diff 0123456789abcdef^ 0123456789abcdef
,或者更简单地说,git show 0123456789abcdef
,看看;注意0123456789abcdef
不能是合并提交)。
如果您只想应用一个特定文件的 0123456789abcdef^
到 0123456789abcdef
更改,请使用 git cherry-pick -n
以便 git cherry-pick
完成工作的初始部分, 但在提交结果之前停止。这使您有机会使用 git reset
或 git restore
撤销对其他文件的更改。 (如果使用 git reset
,请务必提供文件名;git restore
是 Git 2.23 中的新内容,在这方面是 git reset
的一个更有限但更灵活的变体.)
请注意 git cherry-pick
不 相当于:
git diff master 0123456789abcdef
也就是说,它不希望使任何文件的 master
版本 匹配 0123456789abcdef
中任何文件的版本。 Git 最终会做的是 three-way 合并,结合 diffs 产生的:
git diff --find-renames 0123456789abcdef^ HEAD
(即 you 相对于 0123456789abcdef
的 parent 所做的更改)与由以下人员生成的内容:
git diff --find-renames 0123456789abcdef^ 0123456789abcdef
(即,他们 相对于他们自己的 parent 发生了什么变化)。然后将合并的更改应用到来自 0123456789abcdef^
的快照:这会将您的更改添加到他们的 parent,加上他们对他们的 parent 的更改。最终结果(如果没有冲突)是您将他们的更改添加到当前提交中,其中“他们的更改”是相对于他们提交的 parent 的快照;但这也说明了他们的提交 parent 和您的提交之间的任何直线运动,甚至 file-name-changes。
因此,根据您的问题,cherry-pick似乎是的答案。如果不是,您将需要提供更多信息来说明为什么会这样。
假设我在 git 存储库 'master' 和 'feature' 中有两个分支。这两个分支在某些方面有所不同。现在我想从 'feature' 分支上的提交 '0123456789abcdef' 中对 'script.py' 进行确切的更改,并将这些更改应用到 [=24= 开头的 'script.py' 的相应行]分支。
git cherry-pick
对我来说似乎是显而易见的选择,但它并不完全符合我的要求。问题是 git cherry-pick
使 'master' 分支更新了 'feature' 上的所有更改,直到提交 '0123456789abcdef'。
我不希望应用所有这些更改。我只想要在提交“0123456789abcdef”中发生的确切更改 - 仅此而已。我认为如果我能够以某种方式利用共同的历史来找出相对于 'feature' 的提交,相应的更改行可能在 'master' 中移动的位置,而不是在 'feature' 上应用所有这些先前的更改,那将是明智的。 =24=].
我怎样才能做到这一点?当然,我可以从 git diff
的输出中复制并粘贴它,但是我对 Git 的了解有点好,在我看来它必须有更好的方法来做到这一点,我只是还不知道.
编辑: 看来上述行为一定是错误的结果,我无法再重现。基于
在此声明中:
git cherry-pick
seems like the obvious choice to me here, but it does not do exactly what I want. The trouble is thatgit cherry-pick
brings the 'master' branch up to date with all the changes on 'feature' up to commit '0123456789abcdef'.
您已将 cherry-pick 与合并混为一谈。如果你要 运行:
git checkout master
git merge 0123456789abcdef
that会找到master当前tip commit的merge base,然后commit 0123456789abcdef
,按你说的做。但是 git cherry-pick 0123456789abcdef
找到了 0123456789abcdef
的 parent 提交,然后在此处涉及的三个提交上调用 Git 的合并引擎。
效果是git cherry-pick
会找出从0123456789abcdef^
——0123456789abcdef
的parent——到0123456789abcdef
的变化,并应用到当前或 HEAD
提交。这会影响到不止一个文件,如果不止一个文件有任何从0123456789abcdef^
到0123456789abcdef
的差异(使用git diff 0123456789abcdef^ 0123456789abcdef
,或者更简单地说,git show 0123456789abcdef
,看看;注意0123456789abcdef
不能是合并提交)。
如果您只想应用一个特定文件的 0123456789abcdef^
到 0123456789abcdef
更改,请使用 git cherry-pick -n
以便 git cherry-pick
完成工作的初始部分, 但在提交结果之前停止。这使您有机会使用 git reset
或 git restore
撤销对其他文件的更改。 (如果使用 git reset
,请务必提供文件名;git restore
是 Git 2.23 中的新内容,在这方面是 git reset
的一个更有限但更灵活的变体.)
请注意 git cherry-pick
不 相当于:
git diff master 0123456789abcdef
也就是说,它不希望使任何文件的 master
版本 匹配 0123456789abcdef
中任何文件的版本。 Git 最终会做的是 three-way 合并,结合 diffs 产生的:
git diff --find-renames 0123456789abcdef^ HEAD
(即 you 相对于 0123456789abcdef
的 parent 所做的更改)与由以下人员生成的内容:
git diff --find-renames 0123456789abcdef^ 0123456789abcdef
(即,他们 相对于他们自己的 parent 发生了什么变化)。然后将合并的更改应用到来自 0123456789abcdef^
的快照:这会将您的更改添加到他们的 parent,加上他们对他们的 parent 的更改。最终结果(如果没有冲突)是您将他们的更改添加到当前提交中,其中“他们的更改”是相对于他们提交的 parent 的快照;但这也说明了他们的提交 parent 和您的提交之间的任何直线运动,甚至 file-name-changes。
因此,根据您的问题,cherry-pick似乎是的答案。如果不是,您将需要提供更多信息来说明为什么会这样。