如何为特定提交生成 Git 补丁?
Posted
技术标签:
【中文标题】如何为特定提交生成 Git 补丁?【英文标题】:How can I generate a Git patch for a specific commit? 【发布时间】:2011-10-03 06:03:24 【问题描述】:我需要编写一个脚本,为 SHA-1 提交号列表创建补丁。
我尝试使用git format-patch <the SHA1>
,但自该 SHA-1 值以来,每次提交都会生成一个补丁。在生成了几百个补丁后,我不得不终止该进程。
有没有办法只为特定的 SHA-1 值生成补丁?
【问题讨论】:
【参考方案1】:假设您在提交 1 之后有提交 id 2,您将能够运行:
git diff 2 1 > mypatch.diff
其中 2 和 1 是 SHA-1 哈希。
【讨论】:
感谢dookehster 的回复。这意味着我需要脚本来找到我感兴趣的提交之前的提交。我希望我可以避免这种情况。 @elle,不,你没有——git diff hash^ hash
。 “hash^”给出了之前的提交。 (当然,manojlds 的回答更好)
git show HEAD > mypatch.diff
在提交时也应该这样做。
@dookehester 是正确的还是相反的,git diff 1 2
这将无法在 diff 中包含任何二进制文件。【参考方案2】:
试试:
git @987654321@ -1 <sha>
或
git format-patch -1 HEAD
根据上面的文档链接,-1
标志告诉 Git 应该在补丁中包含多少次提交;
-
从最顶层的提交中准备补丁。
使用命令应用补丁:
git am < file.patch
【讨论】:
应用补丁:git apply --stat file.patch
# show stats. git apply --check file.patch
# 申请前检查错误。 git am < file.patch
# 最后应用补丁。
如果最后一次提交是来自另一个分支的合并,它似乎不起作用。
使用git am -3 < file.patch
使用三向合并来申请,这将让您在之后使用git mergetool
(或手动编辑)found here 解决冲突。
此命令也仅适用于提交中的特定文件:git format-patch -1 <sha> path/to/file.js
这将创建一个仅包含 file.js 差异的补丁
如果你能解释一下-1
的目的会很有帮助【参考方案3】:
用于从特定 SHA-1 哈希的最顶部
git format-patch -<n> <SHA-1>
单个补丁文件中 head 的最后 10 个补丁:
git format-patch -10 HEAD --stdout > 0001-last-10-commits.patch
【讨论】:
能否请您提供第一个命令的示例git format-patch -1 HEAD
将为最近的提交生成补丁
请原谅我问这个问题,所以当它是 -2
时,它会为最近的 2 次提交生成补丁,还有一件事要澄清的是命令 got format-patch -2 HEAD
与该行相同git format-patch HEAD~2
【参考方案4】:
从特定提交(不是最后一次提交)生成补丁:
git format-patch -M -C COMMIT_VALUE~1..COMMIT_VALUE
【讨论】:
【参考方案5】:如果您想确保(单个提交)补丁将应用于特定提交之上,您可以使用新的 git 2.9(2016 年 6 月)选项git format-patch --base
git format-patch --base=COMMIT_VALUE~ -M -C COMMIT_VALUE~..COMMIT_VALUE
# or
git format-patch --base=auto -M -C COMMIT_VALUE~..COMMIT_VALUE
# or
git config format.useAutoBase true
git format-patch -M -C COMMIT_VALUE~..COMMIT_VALUE
参见Xiaolong Ye (``)commit bb52995、commit 3de6651、commit 3de6651、commit ded2c09(2016 年 4 月 26 日)。(由 Junio C Hamano -- gitster
-- 合并到 commit 72ce3ff,2016 年 5 月 23 日)
format-patch
:添加'--base
'选项来记录基础树信息
维护人员或第三方测试人员可能想知道确切的基础树 该补丁系列适用于。教 git format-patch 一个 '
--base
' 选项 记录基本树信息并将其附加到第一个的末尾 消息(求职信或系列中的第一个补丁)。基本树信息由“基本提交”组成,这是众所周知的 提交是项目历史中稳定部分的一部分 else 可以使用零个或多个“必备补丁”,它们是 尚未成为“基本提交”一部分的著名补丁 需要按拓扑顺序在“基本提交”之上应用 在应用补丁之前。
“基本提交”显示为“
base-commit:
”,后跟 40-hex 提交对象名称。 “必备补丁”显示为“prerequisite-patch-id:
”,后跟 40 位十六进制“补丁 id”,可以通过“git patch-id --stable
”命令传递补丁来获得。
Git 2.23(2019 年第三季度)将改进这一点,因为“format-patch
”的“--base
”选项以不稳定的方式计算了必备补丁的patch-ids
,该方法已更新为以一种方式计算与“git patch-id --stable
”兼容。
参见commit a8f6855、commit 6f93d26(2019 年 4 月 26 日)Stephen Boyd (akshayka
)。(由 Junio C Hamano -- gitster
-- 合并于 commit 8202d12,2019 年 6 月 13 日)
format-patch
: 使--base patch-id
输出稳定
我们没有在每次处理一个大块时刷新上下文
patch-id
在diff.c
中生成代码,但是当我们这样做的时候 使用“patch-id
”工具生成“稳定”补丁 ID。让我们将类似的逻辑从
patch-id.c
移植到diff.c
,这样当我们为“format-patch --base=
”类型的命令调用生成补丁ID 时,我们可以获得相同的哈希值。
在 Git 2.24(2019 年第四季度)之前,“git format-patch -o <outdir>
”相当于“mkdir <outdir>
”而不是“mkdir -p <outdir>
”,目前正在更正。
参见Bert Wesarg (bertwesarg
) 的commit edefc31(2019 年 10 月 11 日)。(由 Junio C Hamano -- gitster
-- 合并到 commit f1afbb0,2019 年 10 月 18 日)
format-patch
: 创建输出目录的主要组件签字人:Bert Wesarg
'git format-patch -o' 相当于 '
mkdir <outdir>
' 而不是 'mkdir -p <outdir>
',正在纠正中。
避免在可能有安全隐患的前导目录中使用“
adjust_shared_perm
”。通过像 'git init
' 一样暂时禁用 'config.sharedRepository
' 来实现。
在 Git 2.25(2020 年第一季度)中,“git rebase
”在设置 format.useAutoBase
配置变量时无法正常工作,已更正。
参见Denton Liu (Denton-L
) 的commit cae0bc0、commit 945dc55、commit 700e006、commit a749d01、commit 0c47e06(2019 年 12 月 4 日)。(由Junio C Hamano -- gitster
-- 合并到commit 71a7de7, 2019 年 12 月 16 日)
rebase
:修复format.useAutoBase
破损报告人:Christian Biesinger署名人:Denton Liu
对于
format.useAutoBase = true
,运行 rebase 会导致错误:fatal: failed to get upstream, if you want to record base commit automatically, please use git branch --set-upstream-to to track a remote branch. Or you could specify base commit by --base=<base-commit-id> manually error: git encountered an error while preparing the patches to replay these revisions: ede2467cdedc63784887b587a61c36b7850ebfac..d8f581194799ae29bf5fa72a98cbae98a1198b12 As a result, git cannot rebase them.
通过始终将
--no-base
从 rebase 传递给 format-patch 来解决此问题,从而取消format.useAutoBase
的效果。
在 Git 2.29(2020 年第四季度)中,“git format-patch
”(man) 学会将“whenAble
”作为format.useAutoBase
配置变量的可能值变为否-op 当自动计算的基数没有意义时。
参见Jacob Keller (jacob-keller
) 的commit 7efba5f(2020 年 10 月 1 日)。(由 Junio C Hamano -- gitster
-- 合并到 commit 5f8c70a,2020 年 10 月 5 日)
format-patch
:教format.useAutoBase
“whenAble
”选项签字人:Jacob Keller
format.useAutoBase
配置选项的存在允许用户默认为格式补丁启用“--base=auto
”。由于尝试格式化旧补丁时出现意外失败,这有时会导致工作流程不佳:
$ git format-patch -1 <an old commit> fatal: base commit shouldn't be in revision list
这可能非常令人困惑,因为用户请求
--base
不一定立即显而易见(因为这是在配置中,而不是在命令行中)。我们确实希望
--base=auto
在无法提供合适的基础时失败,因为如果格式化的补丁在请求时不包含基础信息,这同样会令人困惑。教
format.useAutoBase
一种新模式“whenAble
”。此模式将导致 format-patch 在可能的情况下尝试包含基本提交。但是,如果找不到有效的基本提交,则 format-patch 将继续格式化补丁而无需基本提交。
为了避免使另一个分支名称无法与
--base
一起使用,请不要教--base=whenAble
或--base=whenable
。相反,重构
base_commit
选项以使用回调,并依赖全局配置变量auto_base
。这确实意味着用户无法从命令行请求此可选的基本提交生成。然而,这可能不是太有价值。如果用户手动请求基本信息,他们将立即被告知未能获取合适的基本提交。这使用户可以就是否继续该格式做出明智的选择。
添加测试以涵盖
--base
的新操作模式。
git config
现在包含在其man page 中:
format-patch
默认情况下。 也可以设置为“whenAble
”允许 如果有合适的基地可用,则启用--base=auto
,但跳过 添加基本信息,否则格式不会消失。
在 Git 2.30(2021 年第一季度)中,“git format-patch --output=there
”(man) 没有按预期工作,而是崩溃了。
现在支持该选项。
参见Jeff King (peff
) 的commit dc1672d、commit 1e1693b、commit 4c6f781(2020 年 11 月 4 日)。(由 Junio C Hamano -- gitster
-- 合并于 commit 5edc8bd,2020 年 11 月 18 日)
format-patch
: 支持 --output 选项报告人:Johannes Postler签字人:Jeff King
我们从未打算在格式补丁中支持 diff 的
--output
选项。 直到baa4adc66a (parse-options: disable option abbreviation withPARSE_OPT_KEEP_UNKNOWN,
2019-01-27, Git v2.22.0-rc0),它是不可能触发的。我们首先解析格式补丁选项,然后将剩余部分交给setup_revisions()
。 在提交之前,我们接受“--output=foo
”作为“--output-directory=foo”的缩写。但之后,我们不检查缩写,并且 --output 被传递给 diff 代码。这会导致无意义的行为和错误。 diff 代码将在 rev.diffopt.file 中打开一个文件句柄,但我们将用我们为每个单独的补丁文件打开的句柄覆盖它。所以 --output 文件总是空的。 但更糟糕的是,差异代码还设置了 rev.diffopt.close_file,因此
log_tree_commit()
将自行关闭文件句柄。然后cmd_format_patch()
中的主循环会尝试再次关闭它,从而导致双重释放。最简单的解决方案是使用 format-patch 禁止 --output,因为没有人打算让它工作。但是,我们不小心记录了它(因为 format-patch 包含 diff-options)。它确实适用于 "
git log
"(man) ,它将整个输出写入指定的文件。也很容易让 format-patch 工作:它实际上与 --stdout 相同,但指向特定文件。我们可以通过
"close_file"
标志检测到 --output 选项的使用(请注意,我们不能使用 rev.diffopt.file,因为 diff 设置会将其设置为 stdout)。所以我们只需要取消设置那个标志,但不需要做任何其他事情。我们的情况与 --stdout 完全一样(请注意,我们不会 fclose() 文件,但 stdout 情况也不会;退出程序会为我们解决这个问题)。
【讨论】:
【参考方案6】:这个命令(正如@Naftuli Tzvi Kay 已经建议的那样),
git format-patch -1 HEAD
将HEAD
替换为特定的哈希或范围。
将为最新的提交生成补丁文件,格式类似于 Unix 邮箱格式。
-<n>
- 从最上面的个提交中准备补丁。
然后您可以通过以下方式重新应用邮箱格式的补丁文件:
git am -3k 001*.patch
请参阅:man git-format-patch
。
【讨论】:
谢谢!我认为值得注意的是,应用补丁将创建一个带有以 [PATCH] 为前缀的提交消息的提交。不过这很容易解决 现象级的。 OP,你还没有接受这个,因为......? @MikeS 不,与其他任何git
-formatted 补丁相比,它不会,至少如果用户以正确的方式应用它。
@MikeS 我并没有真正调查原因,但是省略了-k
标志(git am -3
)修复了这个表单(没有PATCH[0/10]
提交消息)。 Git 版本 2.20.1.windows.1【参考方案7】:
仅针对特定 SHA-1 值生成补丁的方法是什么?
很简单:
选项 1。git show commitID > myFile.patch
选项 2。git commitID~1..commitID > myFile.patch
注意:将 commitID
替换为实际的提交 ID(SHA-1 提交代码)。
【讨论】:
选项 1 完全错误,与问题无关。 选项 2 也是无效命令。你会得到这样的错误:混帐a5f4bcaeb7fa7de27ae79d9522332e872889bbf0〜1..a5f4bcaeb7fa7de27ae79d9522332e872889bbf0混帐: 'a5f4bcaeb7fa7de27ae79d9522332e872889bbf0〜1..a5f4bcaeb7fa7de27ae79d9522332e872889bbf0' 不是一个git命令。请参阅“git --help”。请在发布答案前检查 选项 1 实际上是我在搜索如何执行此操作时所寻找的。来自我的 +1! @AnshumanManral 我不太明白为什么git show
是错误的且不相关;除了声称之外,也许可以解释一下。【参考方案8】:
git format-patch commit_Id~1..commit_Id
git apply patch-file-name
快速简单的解决方案。
【讨论】:
另外,在应用补丁之前不要忘记致电git apply --check patch-file-name
。这将有助于避免问题。【参考方案9】:
如果你只想区分指定的文件,你可以使用:
git diff master 766eceb --connections/ > 000-mysql-connector.patch
【讨论】:
【参考方案10】:以我的Mercurial 背景,我打算使用:
git log --patch -1 $ID > $file
但我现在正在考虑使用git format-patch -1 $ID
。
【讨论】:
【参考方案11】:使用 commit-id 创建补丁
$ git format-patch -1 commit-id
此命令使用以下文件名创建补丁
0001-commit-message.patch
应用补丁。
$ git am 0001-commit-message.patch
【讨论】:
您能澄清一下-1
的说法吗?我无法在文档或在线找到对它的引用。以上是关于如何为特定提交生成 Git 补丁?的主要内容,如果未能解决你的问题,请参考以下文章