使用 GPG 签名 Git Commit
本文使用 GnuPG 的 OpenPGP 签名方式,终端示例适用于 macOS / Linux 的 Bash 或 zsh。签名用于核对提交是否由对应密钥签发,不代表代码本身安全。
GPG 安装
macOS 已安装 Homebrew 时:
bash
brew install gnupg
gpg --versionLinux 使用所属发行版的软件包安装 GnuPG。无需为了 Git 签名额外安装 Keybase。
常用命令
bash
gpg --list-keys --keyid-format LONG
gpg --list-secret-keys --keyid-format LONG
gpg --fingerprint前两项分别列出公钥和可用的私钥记录,完整指纹用于准确识别密钥。为 GitHub 配置签名不需要发布到公共 keyserver。
生成 GPG key
已有可用签名私钥时可以复用,无需重复生成。创建新密钥:
bash
gpg --full-generate-key具体步骤如下
- 按本机 GnuPG 的选项选择支持签名的密钥类型和有效期。
- 填入用于提交的姓名、邮箱;希望在 GitHub 显示验证状态时,邮箱需与账户已验证的提交邮箱匹配。
- 设置私钥口令,并完成生成流程。
- 保存私钥备份与生成时提示的吊销证书,分开妥善保管;不要上传到仓库或公开聊天。
算法菜单和输出随 GnuPG 版本变化,以实际提示为准。公钥可以分享,私钥与口令不能当作公钥粘贴到平台。
查看 GPG key
bash
gpg --list-secret-keys --keyid-format LONG
gpg --fingerprint示例
输出字段可按下表理解,不要复制他人的密钥 ID 作为自己的配置:
| 字段 | 含义 |
|---|---|
pub | 主公钥 |
sub | 公共子密钥,不是私钥 |
sec | 主私钥记录 |
ssb | 私有子密钥记录 |
uid | 用户身份,如姓名与邮箱 |
[S] / [C] / [E] | 签名 / 认证 / 加密用途 |
密钥管理
下面用变量 GPG_KEY_FINGERPRINT 表示刚确认的完整指纹。先替换示例值;有公钥而无对应可用私钥时,无法创建签名。
bash
GPG_KEY_FINGERPRINT='替换为自己的完整密钥指纹'导出公钥
bash
gpg --armor --export "$GPG_KEY_FINGERPRINT"GPG key 格式
导出的 ASCII 公钥包含以下边界,复制时包括首尾两行:
text
-----BEGIN PGP PUBLIC KEY BLOCK-----
...
-----END PGP PUBLIC KEY BLOCK-----删除 GPG key
删除密钥与撤销已经公开的密钥不是同一件事。仅在确认不再需要、备份可恢复并核对完整指纹后,才删除本地记录;存在私钥时先删除私钥:
bash
gpg --delete-secret-keys "$GPG_KEY_FINGERPRINT"
gpg --delete-keys "$GPG_KEY_FINGERPRINT"这不是完成签名配置的必做步骤,删除私钥后将无法再用它签名。
GitHub 配置 GPG
将 GPG 公钥添加到账户
进入 GitHub 个人账户的 Settings → SSH and GPG keys → New GPG key,添加导出的公钥。密钥属于账户设置,不是把私钥提交到代码仓库。
本地代码仓库启用 GPG Sign
确认本机存在可用私钥后,选择全局或单仓库配置。若先前使用 SSH 签名,必须同时将 gpg.format 改为 openpgp。
全局设置
bash
git config --global gpg.format openpgp
git config --global user.signingkey "$GPG_KEY_FINGERPRINT"
git config --global commit.gpgsign true指定仓库设置,需要进入代码目录
bash
git config --local gpg.format openpgp
git config --local user.signingkey "$GPG_KEY_FINGERPRINT"
git config --local commit.gpgsign true局部配置覆盖全局配置。检查 git config user.email,使提交邮箱符合所选密钥和平台账户要求。
重启 gpg-agent
修改口令输入设置后,可结束当前 agent;下次需要时 GnuPG 会重新启动它:
bash
gpgconf --kill gpg-agent参数使用两个 ASCII 连字符 --。
检查配置结果
bash
git config --show-origin --get gpg.format
git config --show-origin --get user.signingkey
git config --show-origin --get commit.gpgsign
command -v gpg检查设置来自预期的全局或仓库配置文件,指纹与本机私钥匹配;不要依赖旧教程里带具体 Cellar 版本号的路径。
Git 使用
提交
先按正常流程暂存并审阅需要提交的改动,再创建签名提交:
bash
git diff --cached
git commit -S -m "Describe the change"
git verify-commit HEAD若已开启 commit.gpgsign,可以省略 -S。本地验证成功表示签名可被当前密钥环验证;GitHub 的 Verified 还取决于公钥是否添加到账户、邮箱匹配和平台规则,不能由一次 push 保证。
提交 tag 时签名
以下标签名应替换为项目实际要发布且尚不存在的名称:
bash
git tag -s v1.0.0 -m "Release v1.0.0"
git verify-tag v1.0.0查看日志
bash
git log --show-signature -1签名有效性与本地密钥信任级别是不同概念;出现身份信任提示时,应核对指纹及其来源,不能仅凭姓名判断。
常见问题
出现 gpg failed to sign the data 时,先检查私钥是否存在、是否过期,以及 Git 选择的格式、密钥和 GPG 程序是否正确。需要口令但无法弹出输入界面时,再检查终端与 pinentry。
解决办法
交互式终端可加载当前 TTY:
bash
export GPG_TTY=$(tty)需要持久设置时,将上面这一行按原样加入自己的 shell 配置文件,例如 ~/.zshrc 或 ~/.bashrc。不要在写入文件时先展开 $(tty),否则会把某次会话的终端路径写死。图形界面 Git 客户端和无交互 CI 还需要各自适用的口令输入方案。
如果没有解决,继续排查
bash
gpgconf --check-programs
gpgconf --kill gpg-agent可在私有测试目录创建一份无敏感内容的测试文件,再执行:
bash
printf 'GPG signing check\n' > gpg-sign-test.txt
gpg --armor --local-user "$GPG_KEY_FINGERPRINT" --detach-sign gpg-sign-test.txt
gpg --verify gpg-sign-test.txt.asc gpg-sign-test.txt这能把 GPG 本身的问题与 Git 配置问题分开;输出文件已存在时先处理旧文件,避免误覆盖或重复确认。