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

Posted

技术标签:

【中文标题】从当前工作目录中未提交的更改创建一个 git 补丁【英文标题】:Create a git patch from the uncommitted changes in the current working directory 【发布时间】:2011-07-06 18:17:31 【问题描述】:

假设我的工作目录中有未提交的更改。如何在不创建提交的情况下从这些补丁中制作补丁?

【问题讨论】:

接受的答案可能应该更改,因为第二个答案的受欢迎程度几乎是四倍。 @TimOgilvy 同意了。 OP应该这样做。第二个答案更受欢迎,并提供更多信息 我认为值得一提的是,您也需要对标题中未提交的更改进行补丁。 【参考方案1】:

如果您尚未提交更改,则:

git diff > mypatch.patch

但有时您正在做的部分事情是未跟踪的新文件,不会出现在您的git diff 输出中。所以,打补丁的一种方法是为新的提交(git add 每个文件,或只是git add .)暂存所有内容,但不进行提交,然后:

git diff --cached > mypatch.patch

如果您想将二进制文件添加到补丁中(例如 mp3 文件),请添加“二进制”选项:

git diff --cached --binary > mypatch.patch

您可以稍后应用补丁:

git apply mypatch.patch

【讨论】:

我正是这样做的,并在执行 git apply 时得到“致命:无法识别的输入”。知道是什么原因造成的以及如何解决吗? @Vitaly:如果您使用文本编辑器打开补丁,您的补丁是否可读?它应该是干净的,没有奇怪的字符,例如,如果设置了 color.diff 设置,您的补丁将有一些“颜色字符”,可以使“git apply”失败,在这种情况下尝试git diff --no-color。否则,它看起来像一个编码问题。 要从已经暂存的更改中创建补丁,您也可以使用git diff --staged > mypatch.patch,因为--staged--cached 的同义词。我认为它更容易记住。 与“未跟踪的新文件”相关:“git diff”和“git diff --cached”仅在首先调用“git add ”时才有效。 (我是 git 新手,想知道为什么我每次都得到一个空补丁) 这很容易让我摆脱了奇怪的合并/变基地狱,谢谢:)【参考方案2】:

git diff 用于未暂存的更改。

git diff --cached 用于分阶段更改。

git diff HEAD 用于分阶段和非分阶段的更改。

【讨论】:

是的,git diff 是 git apply 的倒数 git format-patch 还包括二进制差异和一些元信息。实际上,这将是创建补丁的最佳选择,但 afaik 这仅适用于签入源/更改,对吧? 有时创建一个相对于当前目录的补丁可能很有用。为此,请使用git diff --relative git diff > a.patch 将其写入文件 简洁近乎讽刺,下面的答案更有帮助。【参考方案3】:

git diffgit apply 适用于文本文件,但不适用于二进制文件。

您可以轻松创建一个完整的二进制补丁,但您必须创建一个临时提交。完成临时提交后,您可以使用以下命令创建补丁:

git format-patch <options...>

制作补丁后,运行以下命令:

git reset --mixed <SHA of commit *before* your working-changes commit(s)>

这将回滚您的临时提交。最终结果使您的工作副本(故意)变脏,并带有您最初所做的相同更改。

在接收端,您可以使用相同的技巧将更改应用到工作副本,而无需提交历史记录。只需应用补丁和git reset --mixed &lt;SHA of commit *before* the patches&gt;

请注意,您可能必须进行良好的同步才能使整个选项正常工作。我在应用补丁时看到了一些错误,因为制作补丁的人没有像我一样拉下尽可能多的更改。可能有办法让它工作,但我还没有深入研究。


以下是在 Tortoise Git 中创建相同补丁的方法(我不建议使用该工具):

    提交您的工作更改 右击分支根目录,点击Tortoise Git -> Create Patch Serial
      选择合适的范围(Since: FETCH_HEAD 将在您同步良好的情况下工作) 创建补丁
    右击分支根目录,点击Tortise Git -> Show Log 在你的临时提交之前右击提交,然后点击reset "&lt;branch&gt;" to this... 选择Mixed 选项

以及如何应用它们:

    右击分支根目录,点击Tortoise Git -> Apply Patch Serial 选择正确的补丁并应用它们 右击分支根目录,点击Tortise Git -> Show Log 在补丁提交之前右击提交,然后点击reset "&lt;branch&gt;" to this... 选择Mixed 选项

【讨论】:

从技术上讲,这确实需要创建一个 OP 要求避免的提交,但这是一个临时的,无论如何答案都是有用的。【参考方案4】:

要使用修改过的文件和新文件(分阶段)创建补丁,您可以运行:

git diff HEAD > file_name.patch

【讨论】:

谢谢,就我而言,这个答案有效,但git diff --cached &gt; mypatch.patch 无效。 我有一个问题:file_name.patch 可以被patch 命令使用吗?它们相互兼容吗? git diff + git diff --cached/staged == git diff HEAD(显示自上次提交以来的所有更改) @RakshithRavi afaik,是的。您可以使用git diff HEAD &gt; file-name.patch 创建的补丁,例如如下:patch --forward --strip=1 &lt; file-name.patch【参考方案5】:

我喜欢:

git format-patch HEAD~<N>

其中&lt;N&gt; 是保存为补丁的最后提交数。

该命令的详细使用方法在DOC

UPDHere你可以找到如何应用它们。

UPD 对于那些不知道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 .

【讨论】:

有一种比创建提交和取消提交更简单的方法。 git diff --cached --binary @IgorGanapolsky:你注意到别名了吗? git config --global alias.make-patch .... 基于它会产生像../folder这样的路径,它不仅仅在当前工作目录中这样做。【参考方案6】:

如果您想执行二进制,请在运行 git diff 时提供 --binary 选项。

【讨论】:

【参考方案7】:

我们也可以指定文件,只包含有相对变化的文件,尤其是当它们跨越多个目录时,例如

git diff ~/path1/file1.ext ~/path2/file2.ext...fileN.ext > ~/whatever_path/whatever_name.patch

我发现这在答案或cmets中没有指定,它们都是相关且正确的,所以选择添加它。显式优于隐式!

【讨论】:

以上是关于从当前工作目录中未提交的更改创建一个 git 补丁的主要内容,如果未能解决你的问题,请参考以下文章

如何将我当前的更改提交到 Git 中的不同分支 [重复]

如何摆脱 Git 子模块未跟踪状态?

如何将 Git 补丁应用于具有不同名称和路径的文件?

如何详细显示 Git 中未提交的更改和一些 Git 差异

使用 SVN,如何选择性地创建补丁文件?

Git 补丁 - 补丁不适用