(道歉,如果这是一个骗局 - 我在搜索中出现的答案似乎与我的确切情况无关,和/或建议的动作都没有解决我的问题问题)。
我的Git仓库中有以下(近似)结构。我已修补缺陷并将该修补程序合并到Production
分支中。
A--B--C--D--E--F--G [Master]
| |
| \--K--L--M [Release Candidate]
|
\--H--I--J--N--O--P [Production]
|
\--N--O--P [Patch]
现在,我需要将完全相同的修补程序(提交N
,O
和P
)应用于Master
和Release Candidate
分支,自从Production
分支开始以来已经移动了(批次),但是我所影响的文件没有变化。然而,H
,I
和J
需要不来进入这些分支。
有没有办法在不需要使用提交ID进行操作的情况下执行此操作?
理想情况下,我正在寻找可以通过其分支名称引用Patch
的内容。 (毕竟,Git知道Patch
分支上有什么变化,不是吗?我不应该再告诉它了!)
P.S。我尝试了git cherry-pick Patch
因为这似乎是一个明显的猜测,但这只是提交P
。
Master
分支。
请注意,即使图中的每个分支上只显示了一些提交,但除了Production
之外,每个分支上实际上有几十个(可能是数百个,我没有计算它们),这只有三次(这次)。理想情况下,当Patch
分支也可能有大量提交时,我理想地寻找一种情况。
为什么告诉git"使用自分支以来对该分支进行的提交是如此困难?#/ p>
答案 0 :(得分:1)
如果你的补丁确实是3次提交:git cherry-pick N O P
会做
否则,你可以rebase
摘录一个分支:
# starting from branch Patch
# create a fresh branch :
$ git checkout -b wip/patch-on-master
# tell rebase to rebase 'commits from (but not including) J' :
$ git rebase --onto master J wip/patch-on-master
答案 1 :(得分:1)
更新 - 正如torek指出的那样,我对运行多个rebase的后果过于乐观了。建议的程序相应调整......
在选择解决方案时需要考虑的一些事情可能很容易被忽视:
是否已经与其他开发者共享了这些内容?共享的内容越少,重写历史记录的灵活性就越大。我不是历史重写的最大倡导者 - 我通常不会仅仅为了使拓扑更加线性 - 但在这样的情况下,具有灵活性可以使您的未来生活更轻松。 (如果你有一个团队可以协调到#34;切换到#34;到一个重写的回购,那么你可以做任何重写的重写;但根据经验,我们假设你可以' ; t重写你已经分享的丢弃提交。)
如果你有多个提交在不同的分支上执行相同的更改会导致多少麻烦?如果这些分支最终会合并,那么这种事情会导致不必要的合并冲突。因此,您可能希望支持使用单个提交进行任何给定更改的解决方案。
您希望最终使用哪种分支拓扑?有些人真的不喜欢在历史记录中看到合并。不同的解决方案将产生更多或更少的合并提交。
好的,那又怎样呢?那么,你可能不得不在这三个问题上做出妥协。如果您不想进行任何合并,并且只想对任何给定的更改进行一次提交,那么您必须重写几乎所有内容。您只需重写Patch
(以及Patch
到Production
的应用程序),但需要进行一些合并。如果连Patch
都不能被重写,那就是另一种方式(但最后会有一些合并和一些有点愚蠢的分支拓扑)。或者您可以在没有重写的情况下获得不合并的情况(技术性除外),但代表补丁的多组提交。让我们来看看一些选项...
在您将patch
合并到production
之前,首先让我们回复。我之所以这样做主要是因为我并不清楚合并是如何失败的,所以我从一个更清楚的"开始?#34;州。如果需要,你可以实际做到这一点
git checkout Production
git reset --hard J
在一般情况下,J
是提交ID;但如果它是非ff合并,你可以使用HEAD^
。
A--B--C--D--E--F--G <--(Master)
\ \
\ K--L--M <--(Release Candidate)
\
H--I--J <--(Production)
\
N--O--P <--(Patch)
无论如何,如果我们要将N
,O
和P
应用于所有这些分支而不重复更改且没有合并,那么首先要做的是do将它们变为C
。 (您可能希望标记C
;当然,设置标记将需要一些提交ID使用...)
git rebase --onto C Production Patch
N'--O'--P' <--(Patch)
/
A--B--C--D--E--F--G <--(Master)
\ \
\ K--L--M <--(Release Candidate)
\
H--I--J <--(Production)
请注意&#34; prime&#34;新补丁的提交标记;这些是重写的提交而不等于原始文件,但它们包含完全相同的更改(假设Patch
真正独立于Production
上的任何内容。)
如果您不担心重写,那么您可以将其他分支重新绑定到Patch
。这并不像我想的那么容易,因为一些提交由多个分支共享,并且多个rebase操作会创建多个重写(由于时间戳)。所以
git rebase --onto Patch Patch master
git rebase --onto Patch Patch rc
git rebase --onto Patch Patch Production
不有效。相反,你必须做
git rebase --onto Patch Patch master
git rebase --onto Patch Patch Production
然后识别E
&#39;,然后
git rebase --onto E' Master rc
或者,您可以在合并(可能是章鱼合并)您想要重新分支的分支的地方玩游戏,然后使用--preserve-merges
选项对该新合并进行单一变更。它可以排序,但是你可能会有一些手动工作来移动你原来的分支引用。
好吧,如果你做其中一件事,你会得到
(Patch)
|
A--B--C--N'--O'--P'--D'--E'--F'--G' <--(Master)
\ \
\ K'--L'--M' <--(Release Candidate)
\
H'--I'--J' <--(Production)
当然,现在你已经改写了几乎所有东西。假设Patch
是唯一可以安全重写的东西......所以我们回到
N'--O'--P' <--(Patch)
/
A--B--C--D--E--F--G <--(Master)
\ \
\ K--L--M <--(Release Candidate)
\
H--I--J <--(Production)
然后
git checkout Master
git merge Patch
git checkout rc
git merge Patch
git checkout Production
git merge Patch
请注意,不与将原始合并投放到生产位置相同。通过返回并重新合并重写的Patch
,您可以保留&#34;每次更改一次提交&#34;情况。
但也许你不能重写Patch
- 或者更有可能的是,你可以重写Patch
到Production
的合并。不幸的是,已经完成合并可能已经取消了一些选择。在这种情况下,你必须做出更多妥协,老实说,不要让多组提交代表Patch
变得非常困难。你可能只需要考虑其他人已经阐明的答案。
作为最后一个沟通,你可能会想到,嗯,我可以查看Patch
并使用revert
添加到其中,提交撤消H
,{{1} }和I
,然后我有一个补丁我可以合并到J
和Master
&#34; ......好吧,你可以 - 我认为 - 并且它会解决立即问题,但它会产生更大的问题,因为现在Release Candidate
(以及H
), ~H
(以及I
)和~I
(以及J
)已经存在于这些分支的历史记录中,因此未来的合并形式生产将不会&# 39; t自动重新引入这些变化。因此,如果您希望~J
.. H
合并的任何未来状态,则最后一个选项不太好。