Git 跨具有不同提交历史记录的存储库应用修补程序
假设我有两个相似但不同的提交历史的存储库A和B 一个例子可能是两个PythonFlask应用程序,或者两个RubyonRails应用程序,它们共享许多相似的文件,但并不完全相同 我在存储库a上做了一个更改,我也希望将其应用于存储库B。在将其应用于存储库B时可能会有一些冲突,但没关系,我希望看到它们是什么,并解决它们 我尝试了以下方法从repo A生成补丁Git 跨具有不同提交历史记录的存储库应用修补程序,git,diff,patch,Git,Diff,Patch,假设我有两个相似但不同的提交历史的存储库A和B 一个例子可能是两个PythonFlask应用程序,或者两个RubyonRails应用程序,它们共享许多相似的文件,但并不完全相同 我在存储库a上做了一个更改,我也希望将其应用于存储库B。在将其应用于存储库B时可能会有一些冲突,但没关系,我希望看到它们是什么,并解决它们 我尝试了以下方法从repo A生成补丁 > cd ~/git/repoA/ > git format-patch HEAD~ 0001-My-Example-Commit
> cd ~/git/repoA/
> git format-patch HEAD~
0001-My-Example-Commit.patch
> mv 0001-My-Example-Commit.patch ~/git/repoB
然后我试着将补丁应用到回购协议B中
> cd ~/git/repoB
> git am 0001-My-Example-Commit.patch
Applying: My Example Commit
error: patch failed: Gemfile:20
error: Gemfile: patch does not apply
error: patch failed: Gemfile.lock:125
error: Gemfile.lock: patch does not apply
error: patch failed: app/assets/stylesheets/application.scss:29
error: app/assets/stylesheets/application.scss: patch does not apply
....
....
error: patch failed: spec/views/application/_mobile_navigation.html.erb_spec.rb:44
error: spec/views/application/_mobile_navigation.html.erb_spec.rb: patch does not apply
Patch failed at 0001 Using Devise for authentication
hint: Use 'git am --show-current-patch' to see the failed patch
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".
如图所示,它会导致多个错误/冲突。很好,我将尝试查看冲突并修复它们,就像我在常规合并中所做的那样:
git status
On branch test-git-apply
You are in the middle of an am session.
(fix conflicts and then run "git am --continue")
(use "git am --skip" to skip this patch)
(use "git am --abort" to restore the original branch)
nothing to commit, working tree clean
Git甚至没有将更改作为差异应用,因此没有差异/修改的文件,我甚至看不到冲突是什么,也无法尝试修复它们
有没有办法强制git显示冲突?
谢谢
编辑:
我知道--directory
选项存在,但我认为它不适用于这里,因为我的补丁文件已经相对于同一根生成。例如
diff --git a/Gemfile b/Gemfile
index c970c34..ffc812d 100644
--- a/Gemfile
+++ b/Gemfile
@@ -20,12 +20,17 @@ gem "webpacker", "~> 3.5", ">= 3.5.5"
#
gem "bcrypt", "~> 3.1", ">= 3.1.10"
gem "cancancan", "~> 3.0"
....
没有冲突。1修补程序无法应用。例如,补丁可能会说:第87行显示“foo”。在随后的第88行中,将“bar”更改为“baz”。第89行为“quux”。但是您的第87到89行没有读“foo”、“bar”和“qux”,并且附近也没有包含该序列的行。这取决于你,程序员,如何处理补丁
所以,使用它。阅读补丁。检查您的文件并决定如何处理此修补程序
1此处不能有冲突,因为修补程序本身并不表示对同一行的两组不同更改。当您有两个差异时,就会发生冲突:一个说在第88行将bar更改为baz(这是可能的),另一个说在第88行将bar更改为rab(这也是可能的)。这两个变化相互冲突 一个补丁只提供一个改变。它要么适用,要么不适用
修补的替代方案 这里有两种选择。从低效到高效的顺序:
- 确保来自repo A的修补程序是由
生成的。使用git格式的修补程序--full index
时,请使用git-am
(或将git-am-3
配置为am.threeWay
)。这样,true
上的diff将包含文件父版本的完整blob散列。如果父文件版本的blob在repob中可用,Git将能够使用blob散列和补丁来重建真正合并所需的三个输入:公共基本版本和从基本版本修改的两个输入A
- 或者,在repo B中使用
添加对repo A的直接访问。选择一个远程名称,该名称将在以后提醒您这是为了什么(或者在之后立即删除远程)。然后使用此远程名称运行git remote add
,将来自repo A的提交带到repo B中,以便所有提交在B中本地可用。现在,您可以运行以下命令,而不是git fetch
和git format patch
:git am
提供显示在存储库中的哈希ID。如果您还没有hash ID,那么执行git fetch实际上会获取具有该hash ID的blob,这样就不需要单纯的希望了。注意,您会看到:git cherry-pick <hash>
但是,正如Git2.25(2020年第1季度)中所记录的那样,这并不完全正确 参见(2019年10月23日)作者 (于2019年11月10日合并) :hint: Use 'git am --show-current-patch' to see the failed patch
提供完整的电子邮件消息 现有的措辞给人的印象是,它只给出了am--显示当前修补程序
文件的内容,即补丁本身,,但该选项实际上会发出正在处理的整个电子邮件(iow,来自“GIT mailspilt”的一个输出文件)$GIT_DIR/rebase apply/patch
因此,您可能必须从该电子邮件中提取导致冲突的确切部分。我理解您的意思,但在您的示例中,git仍然无法尝试对第87-89行进行这些更改,而只是强制与已有内容发生冲突,这似乎有些奇怪(使用
和>>>
的问题是,要构建一个适当的冲突,Git必须找到第三个文件,即要修补的两个文件都发生更改的共同祖先,以及要应用的修补程序发生更改的共同祖先。也就是说,要应用的修补程序说“对第87-89行进行此更改”例如,Git需要找到包含这些行的文件,如第87-89行,以便找到文件中对应的行。Git可以对一些Git修补程序执行此操作,因为它们的
索引
行:
索引
行包含原始文件的哈希ID。如果修补程序包含
索引
行,则原始文件(作为存储库中存储的blob),您使用
或git apply--3way
,git将尝试此操作。如果您使用git am--3way
生成补丁,它们将具有索引行(并且您可以使用git format patch
来防止可能使其模棱两可的缩写),但这些可能与存储库中的实际blob不对应。请注意,如果您可以直接访问repo A并希望选择一些提交从它到不相关的repo B,您可以--full index
A的提交到repo B,然后在repo B中运行git fetch
。此策略将进行三方合并,并提供您想要的冲突线。非常感谢您的更新和详细的提纲。这一解释非常有意义,并且可以添加另一个git cherry pick
和执行remote
合并更改正是我所需要的。git fetch
git diff <parent of hash> <hash> # what they changed
git diff <parent of hash> HEAD # what we changed
index a1539a7ce682f10a5aff3d1fee4e86530e058c89..98f88a28d3227c436ecf1765f75b7f4e8e336834 100755
hint: Use 'git am --show-current-patch' to see the failed patch