在Git中,有没有一种方式可以使用GPG密钥自动签署提交?

310

有没有一种简便的方法使Git始终对创建的每个提交或标签进行签名?

我尝试了以下内容:

alias commit = commit -S

但这并没有奏效。

我不想安装其他程序来实现这一点。这可行吗?

只是一个小问题,也许提交不应该被签名,只有我从未创建过的标签(像Homebrew等项目的单个提交)。


8
你的别名无法生效的原因是因为你无法创建一个覆盖已存在命令的别名。(参考链接:https://dev59.com/CW025IYBdhLWcg3wqX1o https://dev59.com/fnE95IYBdhLWcg3wApHl https://dev59.com/9XM_5IYBdhLWcg3wq1GF) - Dan D.
2
仅供参考:重写所有要推送的提交以签名它们:git filter-branch -f --commit-filter 'git commit-tree -S "$@"' HEAD@{u}..HEAD(我并不是说你应该使用这个命令)。 - Vi.
6个回答

377
注意:如果您不想一直添加-S以确保您的提交已签名,则有一个提议(分支'pu',目前为2013年12月,因此不能保证它将被包含在git发行版中)添加一个配置项,可以为您处理该选项。
更新于2014年5月:它已在Git 2.0中(在此补丁系列中重新发送后)。
请参阅提交2af2ef3 by Nicolas Vigier (boklm)

添加commit.gpgsign选项以对所有提交进行签名

如果你想对所有提交进行 GPG 签名,你必须始终添加 -S 选项。
commit.gpgsign 配置选项可自动签名所有提交。
commit.gpgsign

一个布尔值,用于指定是否应该对所有提交进行GPG签名。
在执行rebase等操作时使用此选项可能会导致大量提交被签名。使用代理可以避免多次输入GPG密码,这可能更加方便。
那个配置通常是针对每个仓库设置的(您不需要为私有实验本地仓库签名):
cd /path/to/repo/needing/gpg/signature
git config commit.gpgsign true

你需要将 user.signingKey 与全局设置结合使用(在所有想要签署提交的仓库中使用的唯一密钥)。
git config --global user.signingkey F2C7AB29!
                                           ^^^

正如ubombi评论中建议的那样(并在“GPG硬件密钥和Git签名”中解释,基于“如何指定用户ID”),当使用gpg时,可以添加感叹号()来强制使用指定的主要或次要密钥,而不是尝试计算要使用哪个主要或次要密钥。

请注意Rik评论中添加了以下内容:

如果您正在使用像YubiKey这样的设备(推荐),则不需要担心感叹号,因为对于主密钥对,您应该只有以下签名密钥可用:

  • 主密钥本身,其后面应该有一个#表示它不可用,
  • 以及带有>的私有子密钥,表示它是指向YubiKey作为唯一可用签名密钥的存根。

仅当您将所有私钥保留在系统上时(不好的做法),才可能有必要防止自动选择可用的签名密钥。


user.signingKey 在 git 1.5.0(2007年1月)引入,commit d67778e

我不应该被要求在我的 git 存储库和我的 gpg 密钥中使用相同的名称形式。
此外,我可能在我的密钥环中有多个密钥,并且可能想要使用一个与我在提交消息中使用的地址不匹配的密钥。

此补丁添加了一个配置条目 "user.signingKey",如果存在,将传递给 gpg 的 "-u" 开关,允许覆盖标签签名密钥。

这是通过 commit aba9119(git 1.5.3.2)强制实施的,目的是为了捕获这样一种情况:如果用户在其.git/config中错误配置了user.signingKey或者在其密钥环中没有任何秘密密钥。
注:

1
这真的很酷。在Github上有没有一种简单的方法可以像git describe一样做某些事情,而不必下载整个仓库? - user1115652
33
你不需要签署你的私有实验存储库...但为什么不呢? - Andy Hayden
2
不要忘记在键ID后面加上 !。例如:git config --global user.signingKey 9E08524833CB3038FDE385C54C0AFCCFED5CDE14! - ubombi
1
@ubombi 为什么?我不熟悉那个语法(或者在 https://stealthpuppy.com/signing-git-commits-for-sweet-verified-badges/ 中没有看到 !)。 - VonC
1
@VonC,这就是我使用它的原因。简而言之:!强制gpg使用您指定的密钥,否则行为将非常不确定。(当您开始使用子密钥时存在问题) - ubombi
显示剩余4条评论

268
git config --global user.signingKey 9E08524833CB3038FDE385C54C0AFCCFED5CDE14
git config --global commit.gpgSign true

请将9E08524833CB3038FDE385C54C0AFCCFED5CDE14替换为您的密钥ID。请记住:不要使用短ID

更新:根据新的git规定,所有配置键都应该是驼峰式命名。


26
不行。从编辑历史记录中可以看到,有人将我的示例添加到了他的回答中。ED5CDE14是我的个人密钥。但没关系。 - Felipe
8
奇怪。明天我会撤销这个更改,因为它对你不利。 - scrowler
1
这可能对Linux用户有所帮助:为了使其在某些情况下正常工作(例如在Vim上,使用存储在智能卡中需要输入PIN的密钥),我不得不编辑~/.gnupg/gpg-agent.conf并添加pinentry-program /usr/bin/pinentry-gtk-2(遵循此指南https://wiki.archlinux.org/index.php/GnuPG#pinentry)。 - Iakovos Gu
3
@MarcusJ gpg --list-keys --fingerprint 会显示密钥的长格式(我想你得手动去掉空格)。 - Suzanne Soy
1
@SuzanneSoy gpg --list-keys --keyid-format long 显示长格式,没有空格 :) - Ictus
显示剩余2条评论

50

编辑:截至Git版本1.7.9,可以使用 GPG 密钥签署 Git 提交(git commit -S)。稍微更新答案以反映这一点。

问题的标题是:

有没有办法在 Git 中使用 GPG 密钥“自动签名”提交?

简短回答:是的,但不要这样做。

纠正问题中的拼写错误:git commit -s 不会签名提交。相反,根据man git-commit 页面:

-s,--signoff
添加由提交者签署的 Signed-off-by 行到提交日志消息的末尾。

这将产生类似以下的日志输出:


± $ git log                                                                                 [0:43:31]
commit 155deeaef1896c63519320c7cbaf4691355143f5
Author: User Name 
Date:   Mon Apr 16 00:43:27 2012 +0200

    Added .gitignore

    Signed-off-by: User Name 
请注意"Signed-off-by: ..."部分; 这是由-s 标志在 git-commit 上生成的。
引用发布公告电子邮件
“git commit”学会了“-S”来对提交进行GPG签名;可以使用“--show-signature”选项向“git log”显示。
因此,是的,您可以签署提交。但是,我个人敦促谨慎使用此选项;自动 签署提交几乎毫无意义,请参见下文:
只是一个侧面的问题,也许不应该签署提交,只有标记需要签署,我从不创建标记,因为我提交单个提交。
那是正确的。提交没有被签署; 标签是。其原因可以在Linus Torvalds的这封消息中找到,其中的最后一段声明:
签署每个提交是完全愚蠢的。这只是意味着你自动化了它,并使签名变得微不足道。它也没有添加任何真正的价值,因为git DAG链的SHA1的工作方式是,您只需要一个签名,就可以使所有从该签名可达的提交都受到该签名的有效覆盖。因此,签署每个提交只是在错过要点。
我鼓励浏览链接的消息,这比我能做得更好地澄清了为什么自动签署提交不是一个好主意。
但是,如果您想自动签署标记,则可以通过在别名中包装git-tag -[s|u]来实现; 如果您要这样做,您可能需要在〜/ .gitconfig或项目特定的.git / config文件中设置密钥ID。有关该过程的更多信息,请参见git社区书籍。签署标记比签署您进行的每个提交有无限用处。

90
当有一个“耍滑的”开发者喜欢提交伪造作者和提交者的代码时,签署每个提交都是完全愚蠢的。有没有更好的方法来确保提交的安全性?除非服务器上有一些钩子魔法可以将git blame指向他想要的任何人。 - Vi.
12
  1. 一篇文章;1. “is sufficient to sign all of them” -> 如何表达“我声称这是真正属于我的差异(但不确定之前和之后的提交)。我想在我的提交上签名,而不断言任何关于我从中央服务器/任何地方拉取的提交的事情。”;2. 在不受信任的环境中,仍应该有可靠的工具来找出谁有罪。如果服务器检查所有提交是否都使用提交者电子邮件的密钥进行签名,则很难伪造提交(如果您的计算机安全) 。
- Vi.
32
我觉得Linus有点误解了重点。他好像对签署提交的用途有完全不同的想法,与帖子中的原帖者不同。(验证整个项目的完整性,而不是验证单个提交的作者身份。) - Ajedi32
9
现在在 git 中已经提供了 commit.gpgsign 选项(始终对每个提交进行签名),这是否意味着参数已丢失?如果这是“完全愚蠢”的话,为什么还要提供这个选项? - Andy Hayden
15
“对于‘是的,但不要这样做’的回答,应该直接回答‘是’。在提交时签名可以证明作者身份,否则提交者可能会说谎。” - Urda
显示剩余6条评论

16

为了在 Git 版本 2.0 之前使自动签名生效,您需要为提交添加 Git 别名。

# git config --global alias.commit "commit -S"
[alias]
    commit = commit -S

15

首先设置你想要签署所有提交、标签和推送的公钥。要获取公钥,请使用以下命令

% gpg --list-keys --keyid-format=short
/home/blueray/.gnupg/pubring.kbx
-------------------------------
pub   rsa3072/F6EED39A 2021-12-25 [SC] [expires: 2023-12-25]

在这种情况下,公钥是F6EED39A。现在运行以下命令。

git config --global user.signingkey F6EED39A
git config --global commit.gpgSign true // sign all commits
git config --global tag.gpgSign true // sign all tags
git config --global push.gpgSign true // sign all push

请注意,如果您使用push.gpgSign true,当服务器不支持签名推送时,推送将失败。另一种选择是使用:
git config --global push.gpgSign "if-asked" 

如果服务器支持,建议签署所有推送操作。

现在,您的所有提交、标签和推送都将自动使用您提供的公钥进行签名。

有时您可能需要覆盖这些设置

对于提交,请使用 git commit --no-gpg-sign -m "Unsigned commit"

对于标签,请使用git tag --no-sign <tag-name>

对于推送,请使用git push --no-signed--signed=false


2
签署推送是一个很好的补充。这个功能很容易被忘记。我应该补充说明它也可以设置为“if-asked”。这样,只有在服务器支持时才会签署推送。 - Iizuki

0

你需要明确表示,如果你签署了一个提交或标签,那么你并不意味着你批准了整个历史记录。在提交的情况下,你只签署了当前的更改,而在标签的情况下,你需要定义你的意思。你可能已经拉取了一个声称来自你的更改,但实际上不是(因为其他人将其推送到了你的远程仓库)。或者这是一个你不想要的更改,但你只是签署了标签。

在典型的开源项目中,这种情况可能较少见,但在企业场景中,你只偶尔接触代码,而且你不会阅读整个历史记录,这可能会被忽视。

如果提交将被重新基于或挑选到其他父级,则签署提交是一个问题。但如果修改后的提交可以指向实际验证的“原始”提交,那就很好了。


3
重新基础化有点像说谎。它应该非常少被使用。另一件事是,用签名提交是在“签署”代码,所以务必要确保它既不是反自我保护,也不是白白浪费的努力。 - user246672
15
“Rebasing is like lying. It should be used exceedingly sparingly”这句话不太准确。基于rebase的工作流程和基于merge的工作流程一样有效。使用rebase非常强大,不应该吝啬使用。 - Lukas Juhrich
2
当仅与GitHub一起使用时,这不是问题,合并提交将不会由您签名,因为GitHub不支持此功能。在此环境中签署每个(非合并)提交的优点是,当通过PR添加了一个流氓提交时,它会非常明显,因为它不会用您的GPG密钥进行签名。 - Arran Cudbard-Bell
3
如果你签署了一个提交或标签(两者都会签署整个历史记录),而你可能曾经拉取了一个声称来自于你的更改,则这是危险的。但如果你只是签署一个提交,我不会将其解释为对你可访问的每个提交的认可。你并不一定声明那些过去的更改是有效的或得到你的认可,只是说你基于那些更改创建了一个提交。 (虽然对于标签,我同意你确实正在签署所有可以通过标签访问的提交。) - Ajedi32
1
@ArranCudbard-Bell,更新一下,如果你按照@VonC的建议将commit.gpgsign设置为true,则合并提交将由您签名。 - Jay
显示剩余4条评论

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