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



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

例如,两个Python Flask应用程序,或者两个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"
....

没有冲突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 现在将执行完整的三向合并,使用 repo 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 的 blob(如果您还没有它(,这样就不需要仅仅是希望和愿望。

注意,你会看到:

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

但是,正如 Git 2.25(2020 年第 1 季度(中所述,这并不完全正确。

参见 Junio C Hamano (gitster(提交的 commit 80736d7(2019 年 10 月 23 日(.
(由 Junio C Hamano --gitster-- 合并于 提交 f1e2666,2019 年 11 月 10 日(

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

现有的措辞给人的印象是它只给出了$GIT_DIR/rebase-apply/patch文件的内容,即补丁本身,但该选项实际上发出了正在处理的整个电子邮件(iow,来自"git mailsplit"的输出文件之一(。

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

相关内容

最新更新