我可以将推送的提交从一个分支移动到另一个现有分支吗?
Can I move pushed commits from one branch to another existing branch?
我有 3 个分支:develop
、feature-1
和 feature-2
。我在 feature-1
上工作,然后切换到 feature-2
上工作。然后我完成了 feature-2
的工作,提交并推送到存储库,然后为该功能创建了一个合并请求。然后我看到 feature-2
包含一些应该在 feature-1
中的提交。我可以在本地将它们从 feature-2
移动到 feature-1
,然后在 repo 中反映相同的移动吗?
git cherry-pick <commit-id>
是你亲爱的朋友
- 继续 feature-2 分支
- 复制
commit-id(s)
你想从feature-2
移动到feature-1
- 切换到 feature-1 分支
现在挑选您在上面第 2 步中复制的所有提交。
git cherry-pick <commit-id>
如果您有多个提交要移至 feature-1
,则将所有提交 ID 按其提交顺序排列 date/time.
例如:
git cherry-pick <commit-id-1> <commit-id-2> . . <commit-id-n>
你的问题说有问题的提交属于 in feature-1
而不是 feature-2
branch。已接受的答案无法做到这一点。
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
作为将提交标识为 "moved" 的表达式(您通常可以使用提交 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
。
如果您想要 "move" 提交很多,那么您可能希望将 cherry-pick
替换为交互式 rebase
,如下所示:
git checkout feature-2
git branch temp
git rebase -i feature-1 temp
将打开一个编辑器,显示 rebase
的 "todo" 列表。列表中的每个条目都是关于如何处理提交的说明。删除您想要 "leave behind" 的提交行。 (对于如何在 feature-1
上表示提交,您还可以进行其他调整;但这是一个很长的兔子洞,因为到目前为止您所问的只是如何 "move" 提交,所以只有这些步骤将保留它们 "as is"。)
当您保存并退出编辑器时,rebase
将开始,重写所有选定的提交。通过
完成对feature-1
的更新
git checkout feature-1
git merge temp
git branch -d temp
您仍然需要前往 feature-2
来恢复不应该存在的提交;您可能希望在带有 -n
标志的单个命令中执行此操作,以便您可以只创建一个还原提交。 (这会降低我上面提到的某些 rebase
操作在您执行 revert
之后发生的风险;但是我希望您不会再做这些类型的操作rebase
无论如何考虑到这个问题隐含的限制。)
现在有些人不喜欢对这种事情使用 revert
,因为历史显示了发生的事情 - 包括进行更改和后来删除更改,这可能看起来很烦人,因为更改永远不应该已制作。
避免这种情况的唯一方法是 "rewrite the history" of feature-2
,无论你怎么做,都不会 push
干净。你可以得到它到push
,但这样做你会为拥有feature-2
副本的所有其他开发者创造工作——如果他们有做错了,它会毁掉你的工作。因此,如果您想重写历史记录,您必须与使用该存储库的其他所有人协调。有关详细信息,请参阅 "recovering from upstream rebase" 下的 git rebase
文档。
我有 3 个分支:develop
、feature-1
和 feature-2
。我在 feature-1
上工作,然后切换到 feature-2
上工作。然后我完成了 feature-2
的工作,提交并推送到存储库,然后为该功能创建了一个合并请求。然后我看到 feature-2
包含一些应该在 feature-1
中的提交。我可以在本地将它们从 feature-2
移动到 feature-1
,然后在 repo 中反映相同的移动吗?
git cherry-pick <commit-id>
是你亲爱的朋友
- 继续 feature-2 分支
- 复制
commit-id(s)
你想从feature-2
移动到feature-1
- 切换到 feature-1 分支
现在挑选您在上面第 2 步中复制的所有提交。
git cherry-pick <commit-id>
如果您有多个提交要移至
feature-1
,则将所有提交 ID 按其提交顺序排列 date/time.例如:
git cherry-pick <commit-id-1> <commit-id-2> . . <commit-id-n>
你的问题说有问题的提交属于 in feature-1
而不是 feature-2
branch。已接受的答案无法做到这一点。
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
作为将提交标识为 "moved" 的表达式(您通常可以使用提交 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
。
如果您想要 "move" 提交很多,那么您可能希望将 cherry-pick
替换为交互式 rebase
,如下所示:
git checkout feature-2
git branch temp
git rebase -i feature-1 temp
将打开一个编辑器,显示 rebase
的 "todo" 列表。列表中的每个条目都是关于如何处理提交的说明。删除您想要 "leave behind" 的提交行。 (对于如何在 feature-1
上表示提交,您还可以进行其他调整;但这是一个很长的兔子洞,因为到目前为止您所问的只是如何 "move" 提交,所以只有这些步骤将保留它们 "as is"。)
当您保存并退出编辑器时,rebase
将开始,重写所有选定的提交。通过
feature-1
的更新
git checkout feature-1
git merge temp
git branch -d temp
您仍然需要前往 feature-2
来恢复不应该存在的提交;您可能希望在带有 -n
标志的单个命令中执行此操作,以便您可以只创建一个还原提交。 (这会降低我上面提到的某些 rebase
操作在您执行 revert
之后发生的风险;但是我希望您不会再做这些类型的操作rebase
无论如何考虑到这个问题隐含的限制。)
现在有些人不喜欢对这种事情使用 revert
,因为历史显示了发生的事情 - 包括进行更改和后来删除更改,这可能看起来很烦人,因为更改永远不应该已制作。
避免这种情况的唯一方法是 "rewrite the history" of feature-2
,无论你怎么做,都不会 push
干净。你可以得到它到push
,但这样做你会为拥有feature-2
副本的所有其他开发者创造工作——如果他们有做错了,它会毁掉你的工作。因此,如果您想重写历史记录,您必须与使用该存储库的其他所有人协调。有关详细信息,请参阅 "recovering from upstream rebase" 下的 git rebase
文档。