Git
章节 ▾ 第二版

7.4 Git 工具 - 签名你的工作

签名你的工作

Git 是加密安全的,但并非万无一失。如果你从互联网上获取他人的工作,并且想要验证提交是否确实来自可信来源,Git 提供了一些方法可以使用 GPG 对工作进行签名和验证。

GPG 简介

首先,如果你想要签署任何内容,你需要配置 GPG 并安装你的个人密钥。

$ gpg --list-keys
/Users/schacon/.gnupg/pubring.gpg
---------------------------------
pub   2048R/0A46826A 2014-06-04
uid                  Scott Chacon (Git signing key) <[email protected]>
sub   2048R/874529A9 2014-06-04

如果你没有安装密钥,可以使用 gpg --gen-key 生成一个。

$ gpg --gen-key

一旦你有了用于签名的私钥,就可以通过设置 user.signingkey 配置设置来配置 Git 使用它进行签名。

$ git config --global user.signingkey 0A46826A!

现在,如果你想要签名标签和提交,Git 将默认使用你的密钥。

签名标签

如果你已经设置了 GPG 私钥,现在可以使用它来签名新的标签。你只需要使用 -s 而不是 -a 即可。

$ git tag -s v1.5 -m 'my signed 1.5 tag'

You need a passphrase to unlock the secret key for
user: "Ben Straub <[email protected]>"
2048-bit RSA key, ID 800430EB, created 2014-05-04

如果你对该标签运行 git show,可以看到你的 GPG 签名附加在上面。

$ git show v1.5
tag v1.5
Tagger: Ben Straub <[email protected]>
Date:   Sat May 3 20:29:41 2014 -0700

my signed 1.5 tag
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAABAgAGBQJTZbQlAAoJEF0+sviABDDrZbQH/09PfE51KPVPlanr6q1v4/Ut
LQxfojUWiLQdg2ESJItkcuweYg+kc3HCyFejeDIBw9dpXt00rY26p05qrpnG+85b
hM1/PswpPLuBSr+oCIDj5GMC2r2iEKsfv2fJbNW8iWAXVLoWZRF8B0MfqX/YTMbm
ecorc4iXzQu7tupRihslbNkfvfciMnSDeSvzCpWAHl7h8Wj6hhqePmLm9lAYqnKp
8S5B/1SSQuEAjRZgI4IexpZoeKGVDptPHxLLS38fozsyi0QyDyzEgJxcJQVMXxVi
RUysgqjcpT8+iQM1PblGfHR4XAhuOqN5Fx06PSaFZhqvWFezJ28/CLyX5q+oIVk=
=EFTF
-----END PGP SIGNATURE-----

commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <[email protected]>
Date:   Mon Mar 17 21:52:11 2008 -0700

    Change version number

验证标签

要验证签名标签,可以使用 git tag -v <tag-name>。此命令使用 GPG 来验证签名。你需要在你的密钥环中拥有签署者的公钥,以便此操作正常工作。

$ git tag -v v1.4.2.1
object 883653babd8ee7ea23e6a5c392bb739348b1eb61
type commit
tag v1.4.2.1
tagger Junio C Hamano <[email protected]> 1158138501 -0700

GIT 1.4.2.1

Minor fixes since 1.4.2, including git-mv and git-http with alternates.
gpg: Signature made Wed Sep 13 02:08:25 2006 PDT using DSA key ID F3119B9A
gpg: Good signature from "Junio C Hamano <[email protected]>"
gpg:                 aka "[jpeg image of size 1513]"
Primary key fingerprint: 3565 2A26 2040 E066 C9A7  4A7D C0C6 D9A4 F311 9B9A

如果你没有签署者的公钥,你将看到类似以下的内容

gpg: Signature made Wed Sep 13 02:08:25 2006 PDT using DSA key ID F3119B9A
gpg: Can't check signature: public key not found
error: could not verify the tag 'v1.4.2.1'

签名提交

在更新的 Git 版本(v1.7.9 及以上)中,现在也可以签名单个提交。如果你对直接签名提交而不是只签名标签感兴趣,你只需要在 git commit 命令中添加一个 -S 即可。

$ git commit -a -S -m 'Signed commit'

You need a passphrase to unlock the secret key for
user: "Scott Chacon (Git signing key) <[email protected]>"
2048-bit RSA key, ID 0A46826A, created 2014-06-04

[master 5c3386c] Signed commit
 4 files changed, 4 insertions(+), 24 deletions(-)
 rewrite Rakefile (100%)
 create mode 100644 lib/git.rb

要查看和验证这些签名,git log 还提供一个 --show-signature 选项。

$ git log --show-signature -1
commit 5c3386cf54bba0a33a32da706aa52bc0155503c2
gpg: Signature made Wed Jun  4 19:49:17 2014 PDT using RSA key ID 0A46826A
gpg: Good signature from "Scott Chacon (Git signing key) <[email protected]>"
Author: Scott Chacon <[email protected]>
Date:   Wed Jun 4 19:49:17 2014 -0700

    Signed commit

此外,你还可以配置 git log 检查它找到的任何签名,并在其输出中使用 %G? 格式列出它们。

$ git log --pretty="format:%h %G? %aN  %s"

5c3386c G Scott Chacon  Signed commit
ca82a6d N Scott Chacon  Change the version number
085bb3b N Scott Chacon  Remove unnecessary test code
a11bef0 N Scott Chacon  Initial commit

这里可以看到,只有最新的提交是签名且有效的,之前的提交不是。

在 Git 1.8.3 及更高版本中,git mergegit pull 可以被告知在合并没有携带可信 GPG 签名的提交时进行检查和拒绝,使用 --verify-signatures 命令。

如果你在合并分支时使用此选项,并且它包含未签名且无效的提交,则合并将无法进行。

$ git merge --verify-signatures non-verify
fatal: Commit ab06180 does not have a GPG signature.

如果合并只包含有效的签名提交,则合并命令将显示它检查的所有签名,然后继续进行合并。

$ git merge --verify-signatures signed-branch
Commit 13ad65e has a good GPG signature by Scott Chacon (Git signing key) <[email protected]>
Updating 5c3386c..13ad65e
Fast-forward
 README | 2 ++
 1 file changed, 2 insertions(+)

你也可以在 git merge 命令中使用 -S 选项来对产生的合并提交本身进行签名。以下示例既验证了要合并的分支中的每个提交都已签名,还对产生的合并提交进行了签名。

$ git merge --verify-signatures -S  signed-branch
Commit 13ad65e has a good GPG signature by Scott Chacon (Git signing key) <[email protected]>

You need a passphrase to unlock the secret key for
user: "Scott Chacon (Git signing key) <[email protected]>"
2048-bit RSA key, ID 0A46826A, created 2014-06-04

Merge made by the 'recursive' strategy.
 README | 2 ++
 1 file changed, 2 insertions(+)

所有人都必须签名

签名标签和提交很棒,但如果你决定在你的正常工作流程中使用它,你需要确保你的团队中的每个人都理解如何操作。可以通过要求每个使用仓库的人运行 git config --local commit.gpgsign true 来实现,以默认自动对他们仓库中的所有提交进行签名。如果你没有这样做,你最终将花费大量时间帮助人们弄清楚如何用签名版本重写他们的提交。在你将此作为你的标准工作流程的一部分之前,请确保你理解 GPG 和签名事物的益处。

scroll-to-top