Git:如何为合并创建补丁?
当我使用 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”。我该如何处理这个问题?
——杰弗里·李
When I use git format-patch
, it doesn't seem to include merges. How can I perform a merge and then e-mail it to someone as a set of patches?
For example, let's say that I merge two branches and perform another commit on top of the merge:
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"
This creates the following tree:
B
/ \
A M - D
\ /
C
Now I try to checkout the initial commit and replay the above changes:
git checkout -b replay master
git format-patch --stdout master..bar | git am -3
This produces a merge conflict. In this scenario, git format-patch master..bar
only produces 3 patches, omitting "Commit M". How do I deal with this?
-Geoffrey Lee
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
似乎没有一个解决方案可以像
git format-patch
那样生成单独的提交,但是FWIW,您可以格式化包含有效合并提交的补丁,适合/与git am
兼容code>:显然, Git 参考 指南提供了第一个提示:
现在, git-log 的手册页给出了第二个提示:
这又意味着具体的步骤:
并且这可以按预期应用:
同样,这不会包含单独的提交,但它会从合并提交中生成一个 git am 兼容的补丁。
当然,如果您一开始就不需要
git am
兼容补丁,那么这就简单得多:但我想您已经想到了这一点,如果您登陆此页面,您就会发现实际上正在寻找我上面描述的解决方法/解决方案。 ;)
There does not seem to be a solution producing individual commits à la
git format-patch
, but FWIW, you can format a patch containing the effective merge commit, suitable/compatible withgit am
:Apparently, the Git Reference guide provides the first hint:
Now, the manual page of git-log gives the second hint:
Which in turn means in concrete steps:
And this can be applied as intended:
Again, this won't contain the individual commits, but it produces a
git am
compatible patch out of a merge commit.Of course, if you don't need a
git am
compatible patch in the first place, then it's way simpler:But I guess you already figured as much, and if you landed on this page here, you are actually searching for the workaround/solution I've described above. ;)
如果您检查前两个补丁的内容,您将看到问题:
从您当时正在处理的分支(foo 和 bar)的角度来看,这两个提交都删除了“初始文件”行并将其替换完全是别的东西。 AFAIK,当您生成具有重叠更改的非线性进程的补丁时,无法避免这种冲突(在这种情况下,您的分支提交了 B 和 C)。
人们通常使用补丁来添加单个功能或修复已知良好的先前工作状态的错误 - 补丁协议根本不够复杂,无法像 Git 本身那样处理合并历史记录。如果你想让别人看到你的合并,那么你需要在分支之间推/拉,而不是回退差异/补丁。
If you examine the content of the first two patches you'll see the issue:
from the perspective of the branch you were working on at the time (foo and bar) both of these commits have removed the "initial file" line and replaced it with something else entirely. AFAIK, there's no way to avoid this kind of conflict when you generate a patch of a non-linear progression with overlapping changes (your branch commits B and C in this case).
People normally use patches to add a single feature or bug fix off a known good prior work state -- the patch protocol is simply not sophisticated enough to handle merge history like Git does natively. If you want someone to see your merge then you need to push/pull between branches not drop back diff/patch.
请注意,裸露的 git log -p 不会显示合并提交“M”的任何补丁内容,但使用 git log -p -c 确实可以将其显示出来。但是,
git format-patch
不接受任何类似于-c
(或--combined
、-cc< /code>) 被
git log
接受。我也仍然陷入困境。
Note that a bare
git log -p
won't show any patch content for the merge commit "M", but usinggit log -p -c
does coax it out. However,git format-patch
doesn't accept any arguments analogous to the-c
(or--combined
,-cc
) accepted bygit log
.I too remain stumped.
扩展
sun
的答案,我找到了一个命令,它可以生成一系列补丁,类似于git format-patch
生成的补丁(如果可以的话),并且您可以提供这些补丁到git am
以生成包含各个提交的历史记录:补丁将被命名为
xx0001.patch
到xxLAST.patch
Expanding
sun
's answer, I came to a command that can produce a series of patches similar to whatgit format-patch
would produce if it could, and that you can feed togit am
to produce an history with the individual commits :Patches will be named
xx0001.patch
toxxLAST.patch
在 Git 2.32(2021 年第 2 季度)中,“
format-patch
”文档更加清晰:它跳过合并。请参阅 提交 8e0601f(2021 年 5 月 1 日),作者:杰夫·金 (
peff
)。(由 Junio C Hamano --
gitster
-- 合并于 提交 270f8bf,2021 年 5 月 11 日)git format-patch
现在包含在其 手册页:使用 git format-patch 现在包含在其 手册页:
With Git 2.32 (Q2 2021), the "
format-patch
" documentation is clearer: it skips merges.See commit 8e0601f (01 May 2021) by Jeff King (
peff
).(Merged by Junio C Hamano --
gitster
-- in commit 270f8bf, 11 May 2021)git format-patch
now includes in its man page:git format-patch
now includes in its man page:根据 Philippe De Muyter 的解决方案,我制作了一个版本,该版本以与 git-format-patch 相同的方式格式化补丁(据我所知)。只需将 RANGE 设置为所需的提交范围(例如 origin..HEAD)并执行:
请注意,如果您将其与 git-quiltimport 一起使用,那么您将需要排除任何空的合并提交,否则您将收到错误“补丁为空”是不是分错了?”
Working from Philippe De Muyter's solution I made a version that formats the patches the same way as git-format-patch (as far as I can tell). Just set RANGE to the desired range of commits (e.g. origin..HEAD) and go:
Note that if you are using this with git-quiltimport then you will need to exclude any empty merge commits or you will get the error "Patch is empty. Was it split wrong?".