我能否将推送的提交从一个分支移动到另一个现有的分支?

19
我有三个分支:developfeature-1feature-2。我一直在 feature-1 上工作,然后转而开始了 feature-2 的工作。然后我完成了 feature-2 的工作,提交并推送到仓库,然后创建了一个合并请求。之后我发现 feature-2 包含了一些原本应该在 feature-1 中的提交。我能否在本地将它们从 feature-2 移动到 feature-1,然后使得这些更改在仓库中也反映出来?

2个回答

24

git cherry-pick <commit-id>可以帮助您移动代码。

  1. 切换到feature-2分支
  2. 复制要从feature-2移动到feature-1的提交ID
  3. 切换到feature-1分支
  4. 现在,使用步骤2中复制的所有提交ID执行cherry pick操作。

    git cherry-pick <commit-id>

    如果您要移动多个提交到feature-1,则按照它们的提交日期/时间顺序将所有提交ID放在一起。

    例如:

    git cherry-pick <commit-id-1> <commit-id-2> . . <commit-id-n>


3
从技术上讲,您并不是在“移动”提交,而是创建一个具有相同内容的新提交,并且Git在合并时会记住此副本。 - Timothy Truckle
@curiousManish 谢谢。当我移动了提交后,git push 命令会在仓库中显示相同的更改吗? - GluePear
没错 @GluePear。 - beingmanish

16

根据您的问题,涉及的提交应该属于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 文档。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接