您如何使用git format-patch将提交压入一个补丁?


163

我在一个分支上有8个提交,我想通过电子邮件将这些提交发送给尚未被git启发的一些人。到目前为止,从时间开始,我所做的一切要么给我8个补丁文件,要么就开始为分支历史中的每次提交提供补丁文件。我使用git rebase --interactive压缩提交,但是现在我尝试的所有事情从一开始就给了我成千上万的补丁。我究竟做错了什么?

git format-patch master HEAD # yields zillions of patches, even though there's 
                             # only one commit since master

我很好奇您最终会在以下命题中使用哪种方法。让我们知道;)
VonC

4
我将使用Rob Di Marco建议的git diff。但是我下班已经两个星期了,昨晚刚刚目睹了我的第二个女婴的出生,所以使用它还需要一段时间!:)
skiphoppy

2
我很想看看git format-patch --squash master HEAD
schoetbi 2011年

1
尝试使用master..HEAD指定转速范围。
康拉德·克莱因

Answers:


186

我建议按如下所示在一次性分支上执行此操作。如果您的提交位于“ newlines”分支中,并且您已经切换回“ master”分支,则可以解决这个问题:

[adam@mbp2600 example (master)]$ git checkout -b tmpsquash
Switched to a new branch "tmpsquash"

[adam@mbp2600 example (tmpsquash)]$ git merge --squash newlines
Updating 4d2de39..b6768b2
Fast forward
Squash commit -- not updating HEAD
 test.txt |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

[adam@mbp2600 example (tmpsquash)]$ git commit -a -m "My squashed commits"
[tmpsquash]: created 75b0a89: "My squashed commits"
 1 files changed, 2 insertions(+), 0 deletions(-)

[adam@mbp2600 example (tmpsquash)]$ git format-patch master
0001-My-squashed-commits.patch

希望这可以帮助!


2
这是我要在本地保留历史记录时使用的(以防我需要编辑补丁)。否则,我只使用rebase -i并压缩提交。
sebnow

5
对我来说,它可以更可靠地工作,git comit -m "My squashed commits"否则会添加其他未跟踪的文件
Sebastian

另外,您可以切换到特定的提交而不是主提交,并执行此操作以创建从提交到提交的补丁:git checkout 775ec2a && git checkout -b patch && git merge --squash branchname
Berry

131

只是向锅中添加另一种解决方案:如果您使用它来代替:

git format-patch master --stdout > my_new_patch.diff

然后它仍然是8个补丁...但是它们全部都在一个补丁文件中,并与以下命令一起应用:

git am < my_new_patch.diff

13
我喜欢这个解决方案。值得注意的是,有时它会创建比@Adam Alexander描述的方法更大的补丁。这是因为某些文件可能会通过提交多次编辑。即使还原了某些文件,此方法也将分别处理每个提交。但这在大多数情况下都不是问题。
gumik 2012年

1
如果您要避免合并,此选项非常有用!(例如,您想跳过一些提交)。您仍然可以将git rebase -i ...它们全部压缩到一个。
Jorge Orpinel '17

21

我总是使用git diff,所以在您的示例中,类似

git diff master > patch.txt

15
除了您丢失所有提交消息和元数据。git format-patch的优点在于可以从一组补丁中重建整个分支。
mcepl 2011年

create-branch-and-squash方法的优点是将所有提交消息合并为一个,但是如果您想编写自己的提交消息,则此方法要快得多
woojoo666

实际上,可以使用合并消息git log,请参见的示例示例
woojoo666

2
不错的选择,但是考虑到'git diff'不能包含二进制差异(也许有一个选择可以做到)。
圣地亚哥·比利亚弗尔特

18

这是对亚当·亚历山大(Adam Alexander)答案的改编,以防您的更改在主分支中进行。执行以下操作:

  • 从我们想要的点创建一个新的一次性分支“ tmpsquash”(寻找运行“ git --log”或gitg的SHA键。选择要成为tmpsquash head的提交,之后在master中的提交将是压缩的提交)。
  • 合并从master到tmpsquash的更改。
  • 提交对tmpsquash的压缩更改。
  • 使用压缩的提交创建补丁。
  • 回到主分支

laura@rune:~/example (master)$ git branch tmpsquash ba3c498878054e25afc5e22e207d62eb40ff1f38
laura@rune:~/example (master)$ git checkout tmpsquash
Switched to branch 'tmpsquash'
laura@rune:~/example (tmpsquash)$ git merge --squash master
Updating ba3c498..40386b8
Fast-forward
Squash commit -- not updating HEAD

[snip, changed files]

11 files changed, 212 insertions(+), 59 deletions(-)
laura@rune:~/example  (tmpsquash)$ git commit -a -m "My squashed commits"
[test2 6127e5c] My squashed commits
11 files changed, 212 insertions(+), 59 deletions(-)
laura@rune:~/example  (tmpsquash)$ git format-patch master
0001-My-squashed-commits.patch
laura@rune:~/example  (tmpsquash)$ git checkout master
Switched to branch 'master'
laura@rune:~/example  (master)$

如果您不会强迫自己进行远程控制,则在主服务器中进行更改是一种反模式。如果愿意,您可能不需要为其生成补丁文件。
ivan_pozdeev '16

18

如您所知,a git format-patch -8 HEAD将给您八个补丁。

如果您希望8次提交显示为一次,并且不介意重写分支(o-o-X-A-B-C-D-E-F-G-H)的历史记录,则可以:

git rebase -i
// squash A, B, C, D, E ,F, G into H

或者,这将是一个更好的解决方案,在新分支上重播8个提交中的所有8个提交X(8个提交之前的提交)

git branch delivery X
git checkout delivery
git merge --squash master
git format-patch HEAD

这样,您在“交付”分支上只有一次提交,它代表了您最近的8次提交


git merge master只是做一个快进而不会压成一团。更改为git merge --squash master,使所有提交都被压缩并在舞台区域中可见。您的流程将适用于此更改。(我使用的是git版本2.1.0。)
Stunner

5

两个标签之间的格式补丁:

git checkout <source-tag>
git checkout -b <tmpsquash>
git merge --squash <target-tag>
git commit -a -m "<message>"
git format-patch <source-tag>

5

最简单的方法是使用git diff,并添加,git log如果您想要squash方法将输出的组合提交消息。例如,创建commit abcd和之间的补丁1234

git diff abcd..1234 > patch.diff
git log abcd..1234 > patchmsg.txt

然后在应用补丁时:

git apply patch.diff
git add -A
git reset patch.diff patchmsg.txt
git commit -F patchmsg.txt

在处理非文本文件(例如图像或视频)时,请不要忘记--binary争论git diff


0

根据亚当·亚历山大的回答:

git checkout newlines
## must be rebased to master
git checkout -b temporary
# squash the commits
git rebase -i master
git format-patch master
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.