我可以将推送的提交从一个分支移动到另一个分支吗?

时间:2018-05-17 12:32:18

标签: git git-branch

我有3个分支:developfeature-1feature-2。我正在feature-1工作,然后转而使用feature-2。然后我完成了feature-2的工作,提交并推送到了repo,然后为该功能创建了合并请求。然后我看到feature-2包含一些应该在feature-1中的提交。我可以在本地将它们从feature-2移动到feature-1,然后在回购中反映相同的动作吗?

2 个答案:

答案 0 :(得分:2)

您的问题是有问题的提交属于feature-1中的,而不属于feature-2分支。接受的答案没有达到这个目的。

cherry-pick是一种在一个分支上创建新提交的好方法,它可以复制另一个分支上的提交所做的更改;但它不会改变另一个分支。

例如,如果您是从

开始的话
x <--(master)
|\
| A1 -- A2 <--(feature_1)
 \
  B1 -- A3 -- B2 <--(feature_2)

其中A3适用于feature_1,遵循cherry-pick程序后您将拥有

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

如果您想要“移动”多次提交,那么您可能希望将cherry-pick替换为交互式rebase,如下所示:

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文档。

答案 1 :(得分:0)

亲爱的,

git cherry-pick <commit-id>是你的朋友。

  1. 继续使用功能-2分支
  2. 复制commit-id(s)您希望从feature-2移至feature-1
  3. 切换到功能1分支
  4. 现在,请选择您在上面的步骤2中复制的所有提交。

    git cherry-pick <commit-id>

    如果要将多个提交移动到feature-1,则将所有提交ID按其提交日期/时间顺序排列。

    例如:

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