在 GitHub 上,咱们可以对 commit 进行签名。可能会有人跟咱有一样的疑惑,GitHub 在 push 代码的时候,不是已经做过一次验证了吗,为什么还要对 commit 进行签名呢?咱就先来简单地解释一下这个问题。

为什么要签名?

一句话概括,commit 签名是用于证明 commit 的来源。下面讲讲 commit 签名与 push 验证的区别。

首先 push 验证在 GitHub 上是使用 ssh 进行验证的,用于验证某一用户对某仓库是否有访问权限(读写等)。这一验证过程只在 push 代码时进行检查。

如果用户对该仓库没有对应权限,就不能 pull/push 代码。而 ssh 在此处就是用于验证用户对于远程仓库的操作权限。

commit 签名是在本地、在你使用 git commit 的那一刻进行的签名,push 时会将签名信息原封不动地 push 到远程仓库。commit 签名只是用于验证这条 commit 确实来自于你本人,与是否有权限操作远程仓库无关。

举个栗子,你也可以 push 好友签名过的 commit,这时 commit 由好友签名,证明这些修改来自于你的好友,但是他并没有你的仓库的 push 权限,所以他并不能直接 push 到你的仓库上,但你可以使用你的 ssh 密钥将这个 commit push 上去。

在这个 commit 的 push 过程中,就使用到了好友的 commit 签名(证明 commit 来源于好友),还使用到了你的 ssh 密钥(用于验证 push 的这个人是不是对仓库有操作权限的人——你)。

如何签名?

生成密钥

如果有密钥可以跳过这一步。

在 GitHub 上,对 commit 签名通常是使用 GPG,咱们可以先下载好对应的 GPG 工具

对于 Windows 用户,建议下载 GnuGPG-cli,而不是 gpg4w(GPG for Windows,图形界面版的 GPG 管理工具)。因为并不好用

安装完成后,打开 GitBash(不知道为什么常规的命令行不能使用 GPG,只有 GitBash 可以)。

  1. 生成密钥:
1
gpg --full-generate-key

低版本如果使用报错,可以尝试这条:

1
gpg --default-new-key-algo rsa4096 --gen-key
  1. 然后会要求选择密钥类型,一般默认即可(直接按回车)。

  2. 再选择密钥长度,建议输入最大长度 4096。

  3. 选择密钥过期时间,默认是永久。

  4. 再次询问上面的选项是否正确,如果正确输入 y 回车即可。

  5. 输入用户名、邮箱以及备注。

    GitHub 支持使用所有你在 GitHub 验证过的邮箱(包括你注册使用的邮箱),以及一个 GitHub 自动配置的免打扰邮箱。

    官方说法,免打扰邮箱是 [email protected] 这样的格式(UID 是 GitHub 内部的 user id,UserName 就是你的账号,不是昵称,+是真的加号)。

    在咱的实际测试中,使用 [email protected] 这样的缩写格式也是会被判定是认证邮箱的。毕竟 UserName 本就是唯一的,此时还带上 UID 就显得啰嗦了。

  6. 输入密码,这个密码会将当前密钥加密保存在本地,之后使用密钥的时候都需要使用这个密码来解密密钥。

至此 GPG 密钥就生成成功了!

在 GitHub 上添加 GPG 密钥

要让 GitHub 认你的签名,必须将这个密钥告诉 GitHub。

显示当前的密钥:

1
gpg -K --keyid-format=long

会显示如下格式的内容:

sec 加密算法与长度/密钥 ID 生成时间 [SC] [expires: 到期时间]
公钥
uid [ultimate] 用户名 <邮箱>
ssb 加密算法与长度/密钥 ID 生成时间 [E] [expires: 到期时间]

然后咱们复制密钥 ID,输入:

1
gpg --armor --export <密钥 ID>

此时会输出大串的 GPG 密钥,复制 BEGIN PGP PUBLIC KEY BLOCK 这行开始到 END PGP PUBLIC KEY BLOCK 这行的内容。

在 GitHub 中点击自己头像,找到 settings。

然后在 Access 中找到 SSH and GPG keys。

此处点击 New GPG key,将刚刚复制的内容粘贴进去即可。

commit 时签名

现在咱们已经配置好了所有内容,可以在使用 git 的时候进行签名了~

与上一节中一样,使用下面的命令查看当前的密钥列表,然后复制密钥 ID。

1
gpg -K --keyid-format=long

告诉 git 你要使用哪个 GPG 密钥:

1
git config user.signingkey <密钥 ID>

然后在以前的 commit 时附带一个 -S 的参数即可!如:

1
git commit -S -m "msg"

如果你将这个 commit 给 push 到了 远程仓库上的话,GitHub 会自动验证签名是否属于 commiter。如果验证成功,则会显示 Verified

如果你开启了警戒模式,那么以前没有签名的 commit 会显示为 Unverified

最佳实践

单用户

直接在 git 中进行全局配置:

1
2
3
4
git config --global user.name <昵称>
git config --global user.email <邮箱>
git config --global user.signingkey <密钥 ID>
git config --global commit.gpgsign true

之后所有的 commit 都会自动签名。

多用户

~/ 下创建 .gitgpg 目录,并编写 gitconfig.bat

1
2
3
4
5
git config --local user.name <Your Name>
git config --local user.email <Your email>
git config --local user.signingkey <Your secret ID>
git config --local commit.gpgsign true
git checkout -b main

然后将 ~/.gitgpg 目录添加到系统环境。

之后如果需要在某个仓库配置签名,直接输入 gitconfig.bat 即可。

参考

  1. GitHub Docs