假设我有一个具有以下历史的分支:
A - B - C - D
在B和CI之间修改了一堆包含特定文件的文件,称之为foo.txt.
然后,在修订版D上,我修改了同一个文件foo.txt.
与此同时,我的一个朋友拍了我B目录的快照,并决定以某种方式调整foo.txt.让我们称之为修订版E.如果它们是同一个存储库的一部分,它们将如下所示:
A - B - C - D
\
E
然而,他们并非如此,我们只在我的存储库中安装了A - B - C - D然后他给我发了一个关于B和E之间差异的补丁.
由于我也搞乱了foo.txt,我不能直接将补丁应用到D,差异的上下文不匹配,它期待我在B或B附近.
看起来我想要创建我上面提到的假设存储库树,然后在此存储库中进行D和E之间的合并,以便以正确的顺序一起回放我的更改C和D.
所以我的问题:
你确实想要利用git的合并能力是对的.还有一些可能性.实际发生的事情的最具指示性的可能是合并,但是导致E应用的修改版本的方法D也不是那么糟糕.我们来谈谈如何做到这一点!
如果补丁包含它应用的blob(来自do的输出git format-patch),则git am能够尝试三向合并!差异中的blob SHA1记录如下所示:
diff --git a/foo.txt b/foo.txt
index ca1df77..2c98844 100644
Run Code Online (Sandbox Code Playgroud)
如果你有,那你很幸运.只是用git am --3way <patch>.不幸的是,git am确实需要格式化补丁生成的电子邮件样式的标题,所以如果补丁来自git diff而不是git format-patch,你必须克服一点.您可以自己添加:
From: Bobby Tables <bobby@drop.org>
Date: 2 Nov 2010
Subject: [PATCH] protect against injection attack
<original diff>
Run Code Online (Sandbox Code Playgroud)
git am应该能够使用它,如果你没有完全按照你想要的方式得到它,你可以随时git commit --amend修复它.(您也可以尝试使用git apply --build-fake-ancestor=foo.txt <patch>,但它确实无法以用户友好的方式工作.我认为欺骗git am更容易.)
如果补丁不包含任何blob SHA1(即它是用diff创建的,而不是git命令),再次告诉你的朋友如何使用git,我很确定你仍然可以使用它.你知道补丁应该适用于哪个版本的foo.txt!要从提交B获取其SHA1,请使用:
git ls-tree <SHA1 of B>:<directory containing foo.txt>
Run Code Online (Sandbox Code Playgroud)
它将是列出的blob之一.(我知道有一种直接的方法,但我现在无法想到它.)然后你可以添加一个假的git diff标头.假设它的哈希是abcdef12:
diff --git a/foo.txt b/foo.txt
index abcdef12..
Run Code Online (Sandbox Code Playgroud)
除了第一个哈希之外,Git实际上并不需要任何东西; 虽然git diff输出会有最终的哈希值和模式,但是am没有找到它,所以你可以放弃它.(是的,我刚试过这个.我之前没有这样做过!)
这将产生一个历史,例如A - B - C - D - E',E'你朋友的补丁在哪里,但适用于D; 它是一个三方的结果,在内容之间的合并D,B和你的朋友的补丁.
最后,如果你不想捣乱任何一个,你可以按照你说的做:
git checkout -b bobby <SHA1 of B>
# apply the patch
git commit --author="Bobby Tables <bobby@drop.org>"
git checkout master
git merge bobby
# or `git cherry-pick bobby` to grab the single commit and apply to master
# or `git rebase bobby master` to rebase C and D onto B
Run Code Online (Sandbox Code Playgroud)