Git: How to create patches for a merge?
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 with git am
:
Apparently, the Git Reference guide provides the first hint:
git log -p show patch introduced at each commit
[...] That means for any commit you can get the patch that commit introduced to the project. You can either do this by running
git show [SHA]
with a specific commit SHA, or you can rungit log -p
, which tells Git to put the patch after each commit. [...]
Now, the manual page of git-log gives the second hint:
git log -p -m --first-parent
... Shows the history including change diffs, but only from the "main branch" perspective, skipping commits that come from merged branches, and showing full diffs of changes introduced by the merges. This makes sense only when following a strict policy of merging all topic branches when staying on a single integration branch.
Which in turn means in concrete steps:
# Perform the merge:
git checkout master
git merge feature
... resolve conflicts or whatever ...
git commit
# Format a patch:
git log -p --reverse --binary --pretty=email --stat -m --first-parent origin/master..HEAD > feature.patch
And this can be applied as intended:
git am feature.patch
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:
git diff origin/master > feature.patch
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. ;)
If you examine the content of the first two patches you'll see the issue:
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
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.
Note that a bare git log -p
won't show any patch content for the merge commit "M", but using git log -p -c
does coax it out. However, git format-patch
doesn't accept any arguments analogous to the -c
(or --combined
, -cc
) accepted by git log
.
I too remain stumped.
Expanding sun
's answer, I came to a command that can produce a series of patches similar to what git format-patch
would produce if it could, and that you can feed to git am
to produce an history with the individual commits :
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
Patches will be named xx0001.patch
to xxLAST.patch