如何为特定提交生成Git补丁?

我需要编写一个脚本,为SHA-1提交编号列表创建补丁。

我尝试使用git format-patch <the SHA1>,但这会为自SHA-1值以来的每次提交生成一个补丁。生成几百个补丁后,我不得不终止该进程。

有没有办法只为特定的SHA-1值生成补丁?

899386 次浏览

假设您在提交1之后有提交id 2,您将能够运行:

git diff 2 1 > mypatch.diff

其中2和1是SHA-1哈希。

尝试:

git format-patch -1 <sha>

git format-patch -1 HEAD

根据上面的留档链接,-1标志告诉Git补丁中应该包含多少提交;

-

    从最上面的提交准备补丁。


使用命令应用补丁:

git am < file.patch

或者,您也可以申请(应该适用于包括Windows在内的所有操作系统):

git apply --verbose file.patch

-v--verbose将显示失败的地方,如果有的话。给你一个如何修复的线索。

对于从特定SHA-1哈希的最顶层提交生成补丁:

git format-patch -<n> <SHA-1> --stdout > <name_of_patch_file>.patch

单个补丁文件中head的最后10个补丁:

git format-patch -10 HEAD --stdout > 0001-last-10-commits.patch

要从特定提交(不是最后一次提交)生成补丁:

git format-patch -M -C COMMIT_VALUE~1..COMMIT_VALUE

如果您想确保(单一提交)补丁将应用于特定提交之上,您可以使用新的git 2.9(2016年6月)选项git format-patch --base

git format-patch --base=COMMIT_VALUE~ -M -C COMMIT_VALUE~..COMMIT_VALUE
# orgit format-patch --base=auto -M -C COMMIT_VALUE~..COMMIT_VALUE
# orgit config format.useAutoBase truegit format-patch -M -C COMMIT_VALUE~..COMMIT_VALUE

提交bb52995提交3de6651提交fa2ab86提交ded2c09(2016年4月26日)by叶小龙(")
(由提交72ce3ff中的Junio C Hamano----#0----合并,2016年5月23日)

format-patch:添加'--base'选项来记录基本树信息

维护人员或第三方测试人员可能想知道确切的基础树补丁系列适用于。教git格式补丁'--base'选项记录基本树信息并将其附加到第一个树的末尾消息(求职信或系列中的第一个补丁)。

基本树信息由“基本提交”组成,这是一个众所周知的提交是项目历史中稳定部分的一部分,每个人其他作品关闭,和零个或多个“先决条件补丁”,这是众所周知的补丁在飞行中,还不是“基本提交”的一部分需要按拓扑顺序应用于“基本提交”之上在补丁可以应用之前。

“基本提交”显示为“base-commit:”,后跟40十六进制提交对象名称。
“先决条件补丁”显示为“prerequisite-patch-id:”,后跟40十六进制“补丁ID”,可以通过“git patch-id --stable”命令传递补丁来获得。


Git 2.23(2019年第三季度)将改进这一点,因为“format-patch”的“--base”选项以不稳定的方式计算先决条件补丁的patch-ids,该方法已更新为以与“git patch-id --stable”兼容的方式计算。

提交a8f6855提交6f93d26(2019年4月26日)by斯蒂芬·博伊德(#0)
(由提交8202d12中的Junio C Hamano----#0----合并,2019年6月13日)

format-patch:使--base patch-id输出稳定

我们每次处理大块时都没有刷新上下文diff.c中的patch-id生成代码,但当我们这样做时使用“patch-id”工具生成“稳定”的patch-id。

让我们将类似的逻辑从patch-id.c移植到diff.c,这样我们就可以在为format-patch --base=类型的命令调用生成patch-id时获得相同的哈希值。


在Git 2.24(2019年第四季度)之前,“git format-patch -o <outdir>”相当于“mkdir <outdir>”而不是“mkdir -p <outdir>”,这正在被纠正。

提交edefc31(2019年10月11日)byBert Wesarg(#0)
(合并于f1afbb0提交中的Junio C Hamano----#0----,2019年10月18日)

#0:创建输出目录的主要组件

签名人:Bert Wesarg

'git format-patch-o'做了一个等效的'mkdir <outdir>'而不是'mkdir -p <outdir>',这正在被纠正。

避免在前导目录上使用“adjust_shared_perm”,这可能会产生安全影响。通过像“git init”一样暂时禁用“config.sharedRepository”来实现。


在Git 2.25(Q1 2020)中,当设置format.useAutoBase配置变量时,“git rebase”无法正常工作,这已被纠正。

提交cae0bc0提交945dc55提交700e006提交a749d01提交信息0c47e06(2019年12月4日)byDenton Liu(#0)(由提交71a7de7中的Junio C Hamano----#0----合并,2019年12月16日)

#0:修复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> manuallyerror:git encountered an error while preparing the patches to replaythese revisions:
ede2467cdedc63784887b587a61c36b7850ebfac..d8f581194799ae29bf5fa72a98cbae98a1198b12
As a result, git cannot rebase them.

通过始终将--no-base从rebase传递给format-patch来修复此问题,以便否定format.useAutoBase的效果。


在Git 2.29(2020年第四季度)中,“#0man)学习将“whenAble”作为format.useAutoBase配置变量的可能值,当自动计算的基数没有意义时,它将成为no-op。

提交7efba5f(01 Oct 2020)by雅各布·凯勒(#0)
(合并于提交5f8c70a中的Junio C Hamano----#0----,2020年10月5日)

#0:教format.useAutoBasewhenAble”选项

签名人: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现在包含在其手册页中:

默认为0。
也可以设置为“whenAble”以允许如果有合适的基础可用,则启用--base=auto,但要跳过添加基本信息,否则格式不会死亡。


在Git 2.30(2021年第一季度)中,“#0man)没有按预期工作,而是崩溃了。

现在支持该选项。

提交dc1672d提交1e1693b提交4c6f781(2020年11月4日)by杰夫·金(#0)
(由Junio C Hamano----#0----合并于提交5edc8bd,2020年11月18日)

#0:支持--输出选项

作者:Johannes Postler
签名人:Jeff King

我们从来没有打算在format-patch中支持diff的--output选项。直到baa4adc66a(parse-选项:使用PARSE_OPT_KEEP_UNKNOWN, 2019-01-27禁用选项缩写,Git v2.22.0-rc0),它是不可能触发的。我们首先解析格式补丁选项,然后将其余部分交给setup_revisions()
在提交之前,我们会接受“--output=foo”作为“--outport-目录=foo”的缩写。但是之后,我们不检查缩写,并且--out会传递给diff代码。

这会导致无意义的行为和错误。diff代码将在rev.diffopt.file打开一个文件句柄,但我们将用我们为每个单独的补丁文件打开的句柄覆盖它。所以--out文件永远是空的。但更糟糕的是,diff代码还设置了rev.diffopt.close_file,因此log_tree_commit()将关闭文件句柄本身。然后cmd_format_patch()中的主循环将尝试再次关闭它,导致双自由。

最简单的解决方案是不允许使用format-patch来输出,因为没有人打算让它工作。然而,我们不小心记录了它(因为format-patch包括diff选项)。它确实适用于“#0man),它将整个输出写入指定的文件。使其适用于format-patch也很容易:它实际上与--stdout相同,但指向一个特定的文件。

我们可以通过"close_file"标志检测--out选项的使用(请注意,我们不能使用rev.diffopt.file,因为diff设置会将其设置为stdout)。所以我们只需要取消设置该标志,但不必做其他任何事情。我们的情况与--stdout完全相同(请注意,我们不使用文件,但也不使用stdout案例;退出程序会为我们处理这件事)。

这个命令(如@纳夫图利·茨维·凯所建议的),

git format-patch -1 HEAD

HEAD替换为特定的哈希或范围。

将为最新提交生成格式类似于Unix邮箱格式的补丁文件。

-<n>-从最上面的提交准备补丁。

然后,您可以通过以下方式以邮箱格式重新应用补丁文件:

git am -3k 001*.patch

见:#0

仅为特定的SHA-1值生成补丁的方法是什么?

这很简单:

选项1.git show commitID > myFile.patch

选项2.git commitID~1..commitID > myFile.patch

注意:将commitID替换为实际的提交ID(SHA-1提交代码)。

git format-patch commit_Id~1..commit_Idgit apply patch-file-name

快速简单的解决方案。

如果您只想diff指定的文件,您可以使用:

git diff master 766eceb--连接/>000-mysql-connector.patch

在我的Mercurial背景下,我将使用:

git log --patch -1 $ID > $file

但我现在正在考虑使用git format-patch -1 $ID

创建一个git补丁

$ git format-patch -1 commit-id

此命令使用以下文件名创建补丁

0001-commit-message.patch

要应用补丁:

$ git am 0001-commit-message.patch