Git:如何为合并创建补丁?

时间:2010-02-18 01:21:52

标签: git merge patch

当我使用git format-patch时,它似乎不包含合并。如何执行合并,然后将其作为一组补丁通过电子邮件发送给某人?

例如,假设我合并了两个分支并在合并之上执行另一个提交:

git init

echo "initial file" > test.txt
git add test.txt
git commit -m "Commit A"

git checkout -b foo master
echo "foo" > test.txt
git commit -a -m "Commit B"

git checkout -b bar master
echo "bar" > test.txt
git commit -a -m "Commit C"

git merge foo
echo "foobar" > test.txt
git commit -a -m "Commit M"

echo "2nd line" >> test.txt
git commit -a -m "Commit D"

这将创建以下树:

    B
  /   \
A       M - D 
  \   /
    C

现在我尝试检查初始提交并重播上述更改:

git checkout -b replay master
git format-patch --stdout master..bar | git am -3

这会产生合并冲突。在这种情况下,git format-patch master..bar仅生成3个补丁,省略“Commit M”。我该如何处理?

-Geoffrey Lee

6 个答案:

答案 0 :(得分:28)

似乎没有一个解决方案可以生成单个提交({1}},但是FWIW,您可以格式化包含有效合并提交的补丁,适合/兼容git format-patch

显然,Git Reference指南提供了第一个提示:

  

git log -p 显示每次提交时引入的补丁

     

[...]这意味着对于任何提交,您都可以获得提交给项目的提交补丁。您可以通过使用特定提交SHA运行git am来执行此操作,也可以运行git show [SHA],它告诉Git在每次提交后放置补丁。 [...]

现在,git-log的手册页给出了第二个提示:

  

git log -p

     

...显示包含更改差异的历史记录,但仅限于“主分支”透视图,跳过来自合并分支的提交,并显示合并引入的完整变更差异。只有当遵循严格的合并所有主题分支的策略时,这才有意义。

反过来又意味着具体步骤:

git log -p -m --first-parent

这可以按预期应用:

# Perform the merge:
git checkout master
git merge feature
... resolve conflicts or whatever ...
git commit

# Format a patch:
git log -p --reverse --pretty=email --stat -m --first-parent origin/master..HEAD > feature.patch

同样,这不会包含单个提交,但会从合并提交中生成git am feature.patch 兼容的修补程序。


当然,如果您首先不需要git am兼容补丁,那么它会更简单:

git am

但我想你已经想到了,如果你在这里登陆这个页面,你实际上正在寻找我上面描述的解决方法/解决方案。 ;)

答案 1 :(得分:9)

请注意,裸git log -p不会显示合并提交“M”的任何修补程序内容,但使用git log -p -c会将其哄骗。但是,git format-patch不接受与-c接受的--combined(或-ccgit log)类似的任何论据。

我也很难过。

答案 2 :(得分:5)

如果您检查前两个补丁的内容,您将看到问题:

diff --git a/test.txt b/test.txt
--- a/test.txt
+++ b/test.txt
@@ -1 +1 @@
-initial file
+foo

diff --git a/test.txt b/test.txt
index 7c21ad4..5716ca5 100644
--- a/test.txt
+++ b/test.txt
@@ -1 +1 @@
-initial file
+bar

从您当时正在处理的分支(foo和bar)的角度来看,这两个提交都删除了“初始文件”行并完全替换了其他内容。 AFAIK,当你生成一个具有重叠变化的非线性进程的补丁时,没有办法避免这种冲突(在这种情况下你的分支提交B和C)。

人们通常使用补丁来添加单个功能或修复已知良好的先前工作状态的错误 - 补丁协议根本不够复杂,无法像Git本身那样处理合并历史。如果你想让某人看到你的合并,你需要在分支之间推/拉而不是退回差异/补丁。

答案 3 :(得分:5)

扩展sun的答案,我找到了一个命令,可以生成一系列补丁,类似于git format-patch会产生的补丁,并且可以提供给git am通过个人提交生成历史记录:

git log -p --pretty=email --stat -m --first-parent --reverse origin/master..HEAD | \
csplit -b %04d.patch - '/^From [a-z0-9]\{40\} .*$/' '{*}'
rm xx0000.patch

将修补程序命名为xx0001.patchxxLAST.patch

答案 4 :(得分:0)

根据Philippe De Muyter的解决方案,我制作了一个版本,以与git-format-patch相同的方式格式化补丁(据我所知)。只需将RANGE设置为所需的提交范围(例如origin..HEAD),然后转到:

{ 

     name: 'whatever',
     translations: {
          ru: 'без разницы',
          he: 'οτιδήποτε',
          de: 'was auch immer'
    }
}

请注意,如果您使用git-quiltimport,那么您将需要排除任何空的合并提交,否则您将收到错误“Patch为空。它是否错误?”。

答案 5 :(得分:0)

在 Git 2.32(2021 年第二季度)中,“format-patch”文档更加清晰:它跳过合并。

参见commit 8e0601fJeff King (peff)(2021 年 5 月 1 日)。
(2021 年 5 月 11 日于 Junio C Hamano -- gitster --commit 270f8bf 合并)

<块引用>

docs/format-patch:提及合并处理

签字人:Jeff King

<块引用>

Format-patch 无法通过 git-am(或任何其他工具)可以应用的方式来格式化合并,因此它只是省略了它们。
然而,对于不熟悉该工具如何工作的用户来说,这可能是一个令人惊讶的暗示。
让我们在文档中添加一条注释,使其更加清晰。

git format-patch 现在包含在其 man page 中:

<块引用>

准备每个非合并提交及其“补丁”

git format-patch 现在包含在其 man page 中:

<块引用>

注意事项

请注意,format-patch 将省略输出中的合并提交,即使 如果它们是请求范围的一部分。
一个简单的“补丁”不会 包括足够的信息让接收端重现相同的信息 合并提交。