从当前工作目录中未提交的更改创建一个git补丁

1303

如果我的工作目录中有未提交的更改,我怎样可以制作补丁而不必创建提交记录呢?


52
鉴于第二个答案的受欢迎程度几乎是第一个答案的四倍,建议修改已接受的答案。 - Tim Ogilvy
6
@TimOgilvy同意了。楼主应该去做。第二个答案更受欢迎,提供了更多信息。 - John Demetriou
1
我认为值得一提的是,标题中需要包含未提交更改的补丁。 - 2i3r
8个回答

2583
如果您尚未提交更改,则:
git diff > mypatch.patch

但有时候你正在做的工作中,一些内容是新的文件,没有被追踪,也不会显示在你的git diff输出中。因此,一种制作补丁的方式是将所有东西都暂存为一个新的提交 (git add每个文件,或只使用 git add .),但不进行提交,然后执行以下操作:

git diff --cached > mypatch.patch

如果您想要将二进制文件(例如mp3文件)添加到补丁中,请添加“binary”选项:
git diff --cached --binary > mypatch.patch

您可以稍后应用此补丁:

git apply mypatch.patch

7
我确实这样做了,但在执行git apply时出现了“fatal: unrecognized input”的错误。你知道是什么原因导致的吗?如何修复呢? - Vitaly
11
@Vitaly:如果你用文本编辑器打开你的补丁,它是可读的吗?它应该是干净的,没有奇怪的字符。例如,如果设置了color.diff选项,则你的补丁将具有一些“颜色字符”,这可能会导致'git apply'失败。在这种情况下,请尝试git diff --no-color。否则,看起来像是一个编码问题。 - jcarballo
10
要从已经暂存的更改中创建补丁,您也可以执行git diff --staged > mypatch.patch,因为 --staged--cached 的同义词。我认为这更容易记住。 - matthaeus
4
关于“未跟踪的新文件”:只有在首先调用“git add <file>”后,“git diff”和“git diff --cached”才有效。(我刚开始使用 git,不明白为什么每次得到的补丁都是空的) - Anonymous
5
这让我轻松地摆脱了一个奇怪的合并/变基困境,谢谢 :) - John Hunt
显示剩余8条评论

588

git diff 用于比较未暂存的更改。

git diff --cached 用于比较已暂存的更改。

git diff HEAD 用于比较已暂存和未暂存的更改。


21
是的,"git diff"是"git apply"的相反操作。 - Spike Gronim
41
git format-patch 命令也包含二进制差异和一些元信息。实际上,这是创建补丁的最佳选择,但据我所知,这仅适用于已经检入的源代码/更改,对吗? - Eric
27
有时候创建与当前目录相关的补丁可能很有用。为了实现这个目的,请使用 git diff --relative 命令。 - ejboy
38
将 "git diff > a.patch" 写入文件中。 (将Git的差异输出保存到名为a.patch的文件中。) - qasimzee
154
以下的回答言辞简洁并带有讽刺意味,但更加有益。 - Air
显示剩余8条评论

105

git diffgit apply 可以用于文本文件,但无法用于二进制文件。

你可以轻松地创建一个完整的二进制补丁,但需要创建一个临时提交(commit)。一旦你创建了临时提交,就可以使用以下命令来创建补丁:

git format-patch <options...>

制作完补丁后,请运行此命令:

git reset --mixed <SHA of commit *before* your working-changes commit(s)>
这将撤销您的临时提交。最终结果是保留您的工作副本(故意地)带有与原始更改相同的未提交更改。
在接收端,您可以使用相同的技巧将更改应用于工作副本,而无需保留提交历史记录。只需应用补丁并输入命令:git reset --mixed <补丁之前提交的SHA>
请注意,您可能需要很好地同步才能使整个选项正常工作。当应用补丁时,我曾经看到一些错误,当制作补丁的人没有像我那样下载了许多更改时会出现这些错误。可能有方法使其正常工作,但我还没有深入研究过。
下面是如何在Tortoise Git中创建相同的补丁(尽管我不推荐使用该工具):
1. 提交您的工作更改。 2. 在分支根目录上右键单击,然后单击“Tortoise Git”->“创建补丁序列”。 a.选择任何有意义的范围(如果您已同步,则“自”:“FETCH_HEAD”将起作用)。 b.创建补丁文件。 3. 在分支根目录上右键单击,然后单击“Tortise Git”->“显示日志”。 4. 右键单击您的临时提交之前的提交,并单击“重置“<branch>”到这个…”。 5. 选择“Mixed”选项。
以下是如何应用它们:
1. 在分支根目录上右键单击,然后单击“Tortoise Git”->“应用补丁序列”。 2. 选择正确的补丁文件并应用它们。 3. 在分支根目录上右键单击,然后单击“Tortise Git”->“显示日志”。 4. 右键单击补丁提交之前的提交,并单击“重置“<branch>”到这个…”。 5. 选择“Mixed”选项。

6
技术上来说,这确实需要创建一个提交(commit),而 OP 要求避免这样做,但这只是暂时的,无论如何这个答案都是有用的。 - davenpcj

54

要创建一个包含修改和新增文件(已暂存)的补丁,您可以运行以下命令:

git diff HEAD > file_name.patch

1
谢谢,对于我的情况,这个答案有效,但是 git diff --cached > mypatch.patch 不起作用。 - mining
我有一个问题:file_name.patch 文件能否被 patch 命令使用?它们是否兼容? - Rakshith Ravi
1
git diff + git diff --cached/staged == git diff HEAD(显示自上次提交以来的所有更改) - K. Symbol
1
据我所知,是的。您可以使用由 git diff HEAD > file-name.patch 创建的补丁,例如:patch --forward --strip=1 < file-name.patch - whyer

32
我喜欢:
git format-patch HEAD~<N>

其中<N>是要保存为补丁的最后几个提交的数量。

如何使用该命令的详细信息在DOC中。

更新 当从顶级Git目录调用GIT_PREFIX时修复的解释

更新
在这里你可以找到如何应用它们。

更新 对于那些没有理解format-patch的想法的人
添加别名:

git config --global alias.make-patch '!bash -c "cd ${GIT_PREFIX:-.};git add .;git commit -m ''uncommited''; git format-patch HEAD~1; git reset HEAD~1"'

然后在您项目仓库的任何目录下运行:
git make-patch

这个命令将在当前目录下创建一个名为0001-uncommited.patch的补丁文件。该补丁文件将包含所有的更改和未跟踪的文件,这些文件将在下一个命令中可见。
git status .

3
有一个比创建提交和撤销提交更简单的方法。git diff --cached --binary - Gaurav Agarwal
@IgorGanapolsky:你注意到别名了吗?git config --global alias.make-patch .... - Eugen Konkov
基于它会生成 ../folder 这样的路径,所以它并不仅限于在当前工作目录下执行。 - luckydonald
好主意,但如果您有一些未经过故意提交的文件/目录,看起来会有点可疑。 - Adrian

10
如果您想进行二进制操作,请在运行 git diff时加上--binary选项。

5
我们还可以指定文件,只包括相对变化的文件,特别是当它们跨越多个目录时,例如。
git diff ~/path1/file1.ext ~/path2/file2.ext...fileN.ext > ~/whatever_path/whatever_name.patch

我发现这个问题在回答和评论中都没有被具体说明,这些回答和评论都是相关且正确的,因此我选择补充一下。显式优于隐式!

0

未被注释的

git diff --cached > name.patch

已提交(更加有用)

git diff HEAD~commit_count > name.patch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接