首页 > 解决方案 > 如何在提交树的其他地方应用来自特定 Git 提交的更改?

问题描述

假设我在 git repo 'master' 和 'feature' 中有两个分支。这两个分支在某个点上已经分道扬镳了。现在我想从'feature'分支上的提交'0123456789abcdef'中对'script.py'进行确切的更改,并将这些更改应用于'master'分支头部的'script.py'的相应行。
git cherry-pick对我来说似乎是显而易见的选择,但它并不完全符合我的要求。问题在于,git cherry-pick在提交 '0123456789abcdef' 之前,'feature' 上的所有更改都会使 'master' 分支保持最新。
我不希望应用所有这些更改。我只想要提交“0123456789abcdef”中发生的更改——仅此而已。我认为,如果我能以某种方式利用共同历史来确定相对于来自“功能”的提交,相应的更改行可能在“主”中移动的位置,而不在“主”上应用所有这些先前的更改,那将是明智的。
我怎样才能做到这一点?当然,我可以从 a 的输出中复制并粘贴它git diff,但对 Git 有一定了解,在我看来,它必须有更好的方法来做到这一点,而我还不知道。

编辑:看来上述行为一定是由于我无法再重现的错误造成的。根据@torek 的回答,我重复了正确的挑选樱桃的程序,它产生了我想要的结果。

标签: gitpatchcherry-pick

解决方案


在此声明中:

git cherry-pick对我来说似乎是显而易见的选择,但它并不完全符合我的要求。问题在于,git cherry-pick在提交 '0123456789abcdef' 之前,'feature' 上的所有更改都会使 'master' 分支保持最新。

您已将cherry-pick 与merge 混为一谈。如果您要运行:

git checkout master
git merge 0123456789abcdef

将找到 master 和 commit 的当前提示提交的合并基础0123456789abcdef,并按照您说的做。但是git cherry-pick 0123456789abcdef找到 的提交0123456789abcdef,然后在此处涉及的三个提交上调用 Git 的合并引擎。

效果是git cherry-pick会找到从—to0123456789abcdef^的父级的更改,并将它们应用到当前或提交。如果多个文件与to有任何不同,这将影响多个文件(使用,或更简单地说,, 来查看;注意不能是合并提交)。0123456789abcdef0123456789abcdefHEAD0123456789abcdef^0123456789abcdefgit diff 0123456789abcdef^ 0123456789abcdefgit show 0123456789abcdef0123456789abcdef

如果您只希望应用一个特定文件的0123456789abcdef^-to-0123456789abcdef更改,请使用git cherry-pick -nso 来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 最终会做的是一个三向合并,结合由以下产生的差异

git diff --find-renames 0123456789abcdef^ HEAD

(即,对 的父级所做的更改0123456789abcdef)与由以下人员生成的更改:

git diff --find-renames 0123456789abcdef^ 0123456789abcdef

(即,他们相对于自己的父母所做的改变)。然后将合并的更改应用到来自的快照0123456789abcdef^:这会将您的更改添加到其父级,以及它们对其父级的更改。最终结果(如果没有冲突)是您已将他们的更改添加到您当前的提交中,其中“他们的更改”是相对于他们提交的父快照的;但这也解释了提交的父级和您的提交之间的任何线运动,甚至文件名更改。

因此,根据您的问题,似乎樱桃挑选答案。如果不是,您将需要提供更多关于为什么会这样的信息。


推荐阅读