没有特别的方式,严格来说,“是的,但这样做同其他方式一样需要同样多的工作”。新提交总是添加到“当前分支”,即使它是一个“游离 HEAD”状态。(下面,我将展示如何使用“游离 HEAD”状态来完成此操作,虽然如果您要向现有分支添加提交,则比仅检出更加麻烦)。假设您有类似以下代码:
A-B-C <-- br1
\
D F <-- br2
\ /
E
\
G <-- br3
如果您需要对 C
、F
和 G
进行某些修复,而且还需要额外的修复 X
,则应该按照以下步骤进行操作:
A-B-C-X1 <
\
D F-X2 <
\ /
E
\
G-X3 <
请注意,所有三个
Xn
提交都是不同的提交,因为它们有不同的父提交。然后,您必须将 "补丁 X" 添加到提交
C
中,然后将 "补丁 X" 添加到提交
F
中,最后将 "补丁 X" 添加到提交
G
中。
请注意,不能保证例如从
C
到
X1
的更改与此处从
F
到
X2
的更改完全匹配。您可以按照通常的方式构建任何三个
Xn
提交之一。然后(如在您的问题中),您只需移动到其他分支并使用
git cherry-pick
创建(并可能解决冲突)其他
X
。但是,您需要 "在" 这些分支上添加提交。
$ git checkout br1
... make fix, "git add", "git commit" to create X1
$ git checkout br2
Switched to branch 'br2'.
$ git cherry-pick br1
... etc
对于需要复制补丁的所有分支重复此操作(如果必要,可以修改以适应该分支)。
这样做有替代方案。例如,假设分支br1
实际上是正常的,并且您发现提交E
存在问题,需要修复,影响提交F
和G
。进一步假设没有其他人拥有提交F
和G
,或者您愿意强制那些拥有这两个提交的人从即将进行的操作中恢复大量工作。在这种情况下,您可以检出提交D
并创建一个新的提交E'
,它来自于D
。让我们绘制起点,省略A
到C
。我们将使用git checkout D
(通过其SHA-1或等效地使用br2~2
来命名)来获取“分离的HEAD”:
D <
|
| F <
\ /
E
\
G <
现在:
$ git cherry-pick -n br2^
$ git commit
一旦提交完成,我们就会得到以下结果(仍然是“分离的HEAD
”状态):
E' <-- HEAD
/
|
|
D
|
| F <-- br2
\ /
E
\
G <-- br3
现在我们可以将提交记录F
复制到F'
:
$ git cherry-pick br2
提供:
F' <-- HEAD
/
E'
/
|
|
D
|
| F <
\ /
E
\
G <
我们现在已经准备好让
br2
指向提交
F'
了。
$ git branch -f br2 HEAD
提供:
F' <-- HEAD, br2
/
E'
/
|
|
D
|
| F [abandoned]
\ /
E
\
G <
(这就是我之前写的“或者严格来说”的部分:您可以将提交添加到存储库,然后移动分支标签,使它们标记新的提交链,而不是旧的提交链。所有添加的提交都会移动
HEAD
:只是如果
HEAD
是对分支的引用,它们在工作时也会将该分支向前移动一步。让
HEAD
引用一个分支是“正常”工作的方式,但是您可以在“分离的HEAD”模式下使用
git branch -f
进行伪造。在这种情况下,我正在这样做以构建新的
br2
,而不使用分支名称,然后在准备好后将分支名称移动到新的提交链。)
现在我们需要将
G
复制到
G'
,并将
G'
附加到
E'
。以下是步骤:
$ git checkout br2^
[git says stuff here about moving the detached HEAD]
$ git cherry-pick br3
$ git branch -f br3 HEAD
以下是我们复制F
到F'
所做的事情(或者说类似的事情):
F' <-- br2
/
E'
/ \
| G' <-- HEAD, br3
|
D
|
| F [abandoned]
\ /
E
\
G [abandoned]
当你完成所有操作后,应该使用git checkout somebranch
命令,回到“分支”状态,远离“分离头指针”状态。
正如评论中所指出的那样,需要广泛地应用补丁可能意味着整个过程存在问题。(但这就是修复“零日漏洞”的情况,当你有许多不同的产品都共享代码库并存在“零日漏洞”时,就会出现这种情况。)