在具有不同提交历史记录的存储库中应用补丁

时间:2019-09-04 21:12:55

标签: git diff patch

假设我有两个存储库A和B相似,但是提交历史不同。

示例可能是两个Python Flask应用程序,或者两个共享相似文件的 lot 但并不完全相同的Ruby on Rails应用程序。

我对存储库A进行了更改,我想也将其应用于存储库B。将其应用于B可能会有一些冲突,但是没关系,我想看看它们是什么并通过他们。

我尝试了以下操作,从存储库A生成补丁

> 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"
....

2 个答案:

答案 0 :(得分:1)

没有任何冲突 1 该补丁完全无法应用。例如,补丁可能会说:第87行显示为“ foo”。在随后的第88行中,将“ bar”更改为“ baz”。第89行显示为“ quux”。但是您的第87行至第89行不显示“ foo”,“ bar”和“ quux”,并且附近也没有包含该序列的行。由程序员(您)决定如何处理补丁。

hint: Use 'git am --show-current-patch' to see the failed patch

因此,请使用它。阅读补丁。检查文件并决定如何处理此补丁。


1 此处不能有冲突,因为补丁本身并不表示对同一行的两组不同更改。当您有两个差异时会发生冲突:一个告诉在88行将bar更改为baz(可能),另一个告诉在88行将bar更改为rab(也可能) 。这两个变化冲突。

补丁仅提供一个更改。它要么适用,要么不适用。


修补的替代方法

这里有两个替代选项。从效果不佳的订单到效果更好的订单:

  • 确保来自存储库A的补丁程序是由git format-patch --full-index生成的。使用git am时,请使用git am -3(或将am.threeWay配置为true)。这样,A上的差异将包含文件父版本的完整Blob哈希。如果该Blob(文件的父级版本)在存储库B中可用,则Git将能够使用blob-hash-and-patch重构实际合并所需的三个输入:通用基本版本和已修改的两个版本,从基础版本开始。

  • 或者,在存储库B中使用git remote add来添加对存储库A的直接访问。选择一个远程名称,该名称将提醒您以后要使用的名称(或之后立即删除该远程对象)。然后使用此远程名称运行git fetch,将来自仓库A的提交引入仓库B,以便所有提交都可以在B中本地使用。现在,代替git format-patchgit am ,您可以运行:

    git cherry-pick <hash>
    

    用于相关提交。 Git现在将使用回购A的两次提交作为合并基础及其更改来进行完整的三向合并:

    git diff <parent of hash> <hash>   # what they changed
    

    和您当前所做的更改:

    git diff <parent of hash> HEAD     # what we changed
    

    并结合它们,并酌情存在冲突。这里的第二个diff命令是“我们所做的更改”或合并的--ours部分;这里的第一个diff命令是“它们更改了什么”,因此是合并的--theirs部分。

请注意,git am -3或设置am.threeWay只是通过以下方式尝试尝试完全合并的一种方法:

index a1539a7ce682f10a5aff3d1fee4e86530e058c89..98f88a28d3227c436ecf1765f75b7f4e8e336834 100755

给出显示在您的存储库中的哈希ID。如果您还没有git fetch,实际上会用该哈希ID来获得 这个斑点,因此您只需要希望和愿望即可。

答案 1 :(得分:0)

注意,您会看到:

hint: Use 'git am --show-current-patch' to see the failed patch

但是,正如Git 2.25(第1季度2020)中所述,情况并非如此。

请参见commit 80736d7Junio C Hamano (gitster)(2019年10月23日)。
(由Junio C Hamano -- gitster --commit f1e2666中合并,2019年11月10日)

  

docam --show-current-patch提供了完整的电子邮件消息

     

现有措辞给人的印象是,它仅提供$GIT_DIR/rebase-apply/patch文件的内容,即补丁正确,,但该选项实际上发出了正在处理的整个电子邮件(现在,其中一个来自“ git mailsplit”的输出文件)

因此,您可能必须从该电子邮件中提取出导致冲突的确切部分。