你如何使用 git format-patch 将提交压缩到一个补丁中?
Posted
技术标签:
【中文标题】你如何使用 git format-patch 将提交压缩到一个补丁中?【英文标题】:How do you squash commits into one patch with git format-patch? 【发布时间】:2010-10-11 14:54:03 【问题描述】:我在一个分支上有 8 个提交,我想通过电子邮件发送给一些尚未了解 git 的人。到目前为止,我所做的一切要么给了我 8 个补丁文件,要么从一开始就开始给我分支历史中的每个提交的补丁文件。我使用 git rebase --interactive 来压缩提交,但现在我尝试的一切从一开始就给了我无数的补丁。我做错了什么?
git format-patch master HEAD # yields zillions of patches, even though there's
# only one commit since master
【问题讨论】:
我很好奇您最终会在以下命题中使用哪种方法。让我们知道;) 我将按照 Rob Di Marco 的建议使用 git diff。但是我下班两周了,昨晚刚刚见证了我的第二个女婴的出生,所以我还需要一段时间才能使用它! :) 我很想看看 git format-patch --squash master HEAD 尝试 master..HEAD 指定转速范围。 【参考方案1】:我建议在一次性分支上执行此操作,如下所示。如果您的提交在“换行”分支中并且您已经切换回“主”分支,那么这应该可以解决问题:
[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
【讨论】:
这是我想在本地保存历史记录时使用的(以防我需要编辑补丁)。否则我只使用 rebase -i 并压缩提交。 对我来说,它与git comit -m "My squashed commits"
一起工作更可靠,否则它会添加其他未跟踪的文件
另外,您可以切换到特定提交而不是主提交,并执行此操作以创建从提交到提交的补丁:git checkout 775ec2a && git checkout -b patch && git merge --squash branchname
【参考方案2】:
只是在锅中再添加一种解决方案: 如果你改用这个:
git format-patch master --stdout > my_new_patch.diff
那么它仍然是 8 个补丁......但它们都将在一个补丁文件中,并将作为一个补丁应用:
git am < my_new_patch.diff
【讨论】:
我喜欢这个解决方案。值得注意的是,它有时可能会创建比@Adam Alexander 描述的方法大得多的补丁。这是因为某些文件可能通过提交被多次编辑。即使某些文件被还原,此方法也会单独处理每个提交。但大多数时候这不是问题。 如果您想避免合并,这个选项非常棒! (例如,您想跳过一些提交)。您仍然可以git rebase -i ...
并将它们全部压缩为一个。【参考方案3】:
我总是使用 git diff 所以在你的例子中,像
git diff master > patch.txt
【讨论】:
除非您丢失所有提交消息和元数据。 git format-patch 的美妙之处在于它可以从一组补丁中重建整个分支。 create-branch-and-squash 方法的好处是可以将所有提交消息合并为一个,但是如果您想编写自己的提交消息,此方法要快得多 实际上,可以使用git log
完成合并消息,示例见my answer
不错的选择,但考虑到 'git diff' 不能包含二进制差异(也许有一个选项可以这样做)。【参考方案4】:
如您所知,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
或者,这将是一个更好的解决方案,在新分支上重放来自 X
的所有 8 次提交(8 次提交之前的提交)
git branch delivery X
git checkout delivery
git merge --squash master
git format-patch HEAD
这样,你在“delivery”分支上只有一个提交,它代表了你最近的 8 个提交
【讨论】:
git merge master
只是快进,并没有将提交压缩为一个。更改为 git merge --squash master
以使所有提交都被压缩并在暂存区域中可见。您的流程将适用于此更改。 (我使用的是 git 版本 2.1.0。)【参考方案5】:
这是对 Adam Alexander 答案的改编,以防您的更改在 master 分支中。执行以下操作:
从我们想要的点创建一个新的一次性分支“tmpsquash”(查找运行“git --log”或使用 gitg 的 SHA 密钥。选择您想成为 tmpsquash 头的提交,之后的提交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)$
【讨论】:
如果您不将它们推送到远程自己,则在 master 中进行更改是一种反模式。如果愿意,您可能不需要为它们生成补丁文件。【参考方案6】:最简单的方法是使用git diff
,如果您想要squash 方法输出的组合提交消息,则添加git log
。例如,在提交 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
,例如图片或视频。
【讨论】:
【参考方案7】:两个标签之间的格式补丁:
git checkout <source-tag>
git checkout -b <tmpsquash>
git merge --squash <target-tag>
git commit -a -m "<message>"
git format-patch <source-tag>
【讨论】:
【参考方案8】:根据亚当亚历山大的回答:
git checkout newlines
## must be rebased to master
git checkout -b temporary
# squash the commits
git rebase -i master
git format-patch master
【讨论】:
以上是关于你如何使用 git format-patch 将提交压缩到一个补丁中?的主要内容,如果未能解决你的问题,请参考以下文章
“git format-patch”和“git diff”有啥区别?
痞子衡嵌入式:第一本Git命令教程- 提交(commit/format-patch/am)
git merge --squash & git format-patch 将多个commit生成一个patch
利用 git format-patch 和 git send-email 把修改的 patch 文件发送给 ffmpeg-devel