用 SSH 密钥签名 Git 提交
摘要
- 本文说明为什么要给提交签名,以及如何用现有的 ed25519 公钥签名,并让 GitHub 把该提交标成 Verified。签名从 Git 2.34 起可用。本文按 Git 2.56.0、
gh2.103.3。 - 密钥本身的生成见 Git安装和常用命令(最新) 第 17 节。两个账号各用各的密钥见 同一台电脑使用两个 GitHub 账号。仓库要求签名才能合并时,见 用 Rulesets 保护 GitHub 的 main 分支。
- Telling Git about your signing key,Adding a new SSH key to your GitHub account。
为什么要签名
提交里的作者名和邮箱来自本机的 user.name、user.email。Git 只把这两项写进记录,不会核对此人是否拥有这个邮箱。别人把配置改成你的名字再推送,历史里看起来就是你写的。
签名用私钥对这一次提交做校验。校验范围包括目录树、父提交、作者和说明。其中任何一项被改过,校验都会失败。GitHub 同时满足这三件事时,提交页面显示 Verified:签名能通过、公钥已加到该账号的 Signing Key、提交邮箱是该账号已验证的邮箱。
这样别人能区分两件事:邮箱栏写成了你,以及这次提交是由持有对应私钥的人生成的,生成之后内容没有被改过。仓库还可以要求 main 上的提交必须带这个标记,见 用 Rulesets 保护 GitHub 的 main 分支。
签名写进提交
user.signingkey 指向公钥文件。commit.gpgsign 打开后,之后每一次 git commit 都会签名。已经存在的提交不会被补签。这三项都写进 ~/.gitconfig,新开终端仍然生效。
1 | # gpg.format 改成 ssh 之后,签名不再走 GPG |
只想给某一次提交签名时,不要设置 commit.gpgsign,在那次提交上加 -S:
1 | git commit -S -m "只签这一次" |
标签一并签名时再执行下面这条。它同样写入 ~/.gitconfig。
1 | git config --global tag.gpgSign true |
提交用的邮箱来自 user.email,并且要和 GitHub 账号里已验证的邮箱一致。查看和修改配置见 Git安装和常用命令(最新) 第 15 节。
把公钥加到 GitHub
同一把公钥如果已经用来登录,还要再加一次,类型选 Signing Key。登录和签名在 GitHub 上是两条记录。
网页入口:头像 → Settings → SSH and GPG keys → New SSH key,Key type 选 Signing Key,Key 里粘贴 ~/.ssh/id_ed25519.pub 的整行。
当前 gh 活动账号也可以这样加。--type 不写时默认是 authentication,签名必须写明 signing。
1 | gh ssh-key add ~/.ssh/id_ed25519.pub --type signing --title "laptop signing" |
公司账号用另一把公钥时,先 gh auth switch 到那个账号,再执行一次,--title 和公钥路径换成公司的。本机则把 user.signingkey 写进 ~/.gitconfig-work,让 ~/work/ 下的仓库用那把公钥。目录切换见 同一台电脑使用两个 GitHub 账号。
本机先确认签名
GitHub 上的 Verified 依赖网站上的公钥和已验证邮箱。本机用 allowed_signers 做自己的校验,两处互不影响。
1 | mkdir -p ~/.config/git |
在临时仓库里做一次空提交。这个目录可以事后整个删掉。
1 | mkdir -p /tmp/sign-test && cd /tmp/sign-test |
输出里有 Good "git" signature 时,本机校验通过。报错时先看这三条实际读到的值,以及 allowed_signers 第一列邮箱是否就是这次提交的邮箱:
1 | git config --show-origin --get-regexp 'gpg.format|user.signingkey|commit.gpgsign' |
推到 GitHub 之后
把签过名的提交推上去,打开该提交页面。显示 Verified 时,公钥、签名和已验证邮箱三处都对上了。
本机已经是 Good "git" signature,网页仍是 Unverified 时,按这个顺序查:GitHub 上这把公钥的类型是不是 Signing Key,提交邮箱是不是该账号已验证的邮箱,gh 是否把公钥加到了另一个账号。
停止自动签名
下面这条关掉以后的自动签名,已经签过的提交保持原样。
1 | git config --global --unset commit.gpgsign |
连签名密钥一起去掉时,再执行:
1 | git config --global --unset gpg.format |
~/.config/git/allowed_signers 只影响本机校验,删掉对应行即可。GitHub 上的 Signing Key 在 SSH and GPG keys 页面删除。