develop
、feature-1
和 feature-2
。我一直在 feature-1
上工作,然后转而开始了 feature-2
的工作。然后我完成了 feature-2
的工作,提交并推送到仓库,然后创建了一个合并请求。之后我发现 feature-2
包含了一些原本应该在 feature-1
中的提交。我能否在本地将它们从 feature-2
移动到 feature-1
,然后使得这些更改在仓库中也反映出来?develop
、feature-1
和 feature-2
。我一直在 feature-1
上工作,然后转而开始了 feature-2
的工作。然后我完成了 feature-2
的工作,提交并推送到仓库,然后创建了一个合并请求。之后我发现 feature-2
包含了一些原本应该在 feature-1
中的提交。我能否在本地将它们从 feature-2
移动到 feature-1
,然后使得这些更改在仓库中也反映出来?git cherry-pick <commit-id>
可以帮助您移动代码。
现在,使用步骤2中复制的所有提交ID执行cherry pick操作。
git cherry-pick <commit-id>
如果您要移动多个提交到feature-1,则按照它们的提交日期/时间顺序将所有提交ID放在一起。
例如:
git cherry-pick <commit-id-1> <commit-id-2> . . <commit-id-n>
git push
命令会在仓库中显示相同的更改吗? - GluePear根据您的问题,涉及的提交应该属于feature-1
分支而不是feature-2
分支。 接受的答案未能实现这一点。
cherry-pick
是一种创建新提交的方法,该提交在一个分支上复制了另一个分支上进行的更改; 但它不会更改其他分支。
因此,例如,如果您开始时是使用以下内容:
x <--(master)
|\
| A1 -- A2 <--(feature_1)
\
B1 -- A3 -- B2 <--(feature_2)
在执行cherry-pick操作后,A3
将用于feature_1
。
x <--(master)
|\
| A1 -- A2 -- A3' <--(feature_1)
\
B1 -- A3 -- B2 <--(feature_2)
因此,feature_1
看起来像你想要的,但是 feature_2
仍然有一些变化,它可能不应该有。当你将这两个功能合并到 master
时,可能会引起一些麻烦。(我的意思是,可能会出现一些毫无意义的合并冲突。git
尝试在这里提供帮助,但不能完全解决。)
在你的问题中,你提到提交已经被推送了,并且针对cherry-pick
答案,你询问更改是否会干净地 push
,因此我假设你遇到了在已经推送过的分支上重写历史的一些问题。
虽然 cherry-pick
的结果将干净地 push
,但那是因为 cherry-pick
没有进行你所要求的所有更改(如上所述)。实际上,修复feature-2
才是导致 push
出现问题的原因。
一个解决方案是使用 cherry-pick
修复 feature-1
,然后使用 revert
修复 feature-2
。在我们的示例中,使用feature-2~1
作为标识要“移动”的提交(通常可以使用提交ID或适合您实际情况的表达式):
git checkout feature-1
git cherry-pick feature-2~1
git checkout feautre-2
git revert feature-2~1
给你
x <--(master)
|\
| A1 -- A2 -- A3' <--(feature_1)
\
B1 -- A3 -- B2 -- !A3 <--(feature_2)
这将仍然干净地 push
(因为没有删除任何分支历史记录中的提交),现在两个分支都有正确的更改。好处是这使得合并问题变得不太可能;坏处是,某些rebase
操作现在可能会出现问题。你可以采取一些措施来缓解这种情况,但如果你只担心进行干净的push
,那么你不会进行这种类型的rebase
。
如果您想要“移动”许多提交,则可能希望用交互式rebase
替换cherry-pick
,像这样:
git checkout feature-2
git branch temp
git rebase -i feature-1 temp
一个编辑器将会打开,显示一个 rebase
的 "待办事项" 列表。列表中的每个条目都是处理提交的指令。删除您想要 "留下" 的提交的行。(对于如何在 feature-1
上表示提交,您可以做出其他微调;但这是一条漫长的兔子洞,因为到目前为止,您只是询问如何 "移动" 提交,所以仅需这些步骤来保持它们的原样)。
当您保存并退出编辑器后,rebase
将开始,重写所有选定的提交。通过完成更新到 feature-1
来结束此操作。
git checkout feature-1
git merge temp
git branch -d temp
你仍需要前往 feature-2
来撤销那些不应该在那里的提交;你可能会想要使用 -n
标志在单个命令中完成这个过程,以便你可以创建一个撤销提交。 (这将有一个副作用,减少我上面提到的风险,即某些 rebase
操作在你执行 revert
后出现问题;但是,考虑到这个问题暗示的约束条件,我认为你不会进行这些类型的 rebase
。)
现在有些人不喜欢使用 revert
来完成这种事情,因为历史记录显示了发生了什么——包括进行更改和稍后删除更改,这可能看起来很烦人,因为不应该进行更改。
避免这种情况的唯一方法是“重写” feature-2
的历史记录,无论你如何做,它都不会干净地 push
。你可以让它 push,但这样做会给所有其他拥有 feature-2
副本的开发人员带来工作负担——如果他们做错事情,那么将会撤销你的工作。因此,如果您想重写历史记录,必须与使用存储库的所有其他人协调。有关此更多信息,请参见“从上游 rebase
恢复”的 git rebase 文档。