Git 提交签名完整指南:GPG 与 SSH 签名详解
在现代软件开发中,确保代码提交的真实性和完整性变得越来越重要。Git 提供了强大的数字签名功能,让开发者可以对自己的提交进行加密签名,确保代码来源的可信度。本文将详细介绍如何配置和使用 GPG 签名,以及新兴的 SSH 签名方式。
为什么需要提交签名?
提交签名能够:
- 验证身份:证明提交确实来自声称的作者
- 防止篡改:确保提交内容在传输过程中未被修改
- 增强信任:在开源项目中建立代码贡献的可信度
- 合规要求:满足某些企业或项目的安全规范
在 GitHub 上,已签名的提交会显示绿色的 "Verified" 标记,未签名或签名无效的提交则不会有此标记。
GPG 签名详解
GPG 基础概念
GPG (GNU Privacy Guard) 是一个完整的加密和数字签名解决方案,基于 OpenPGP 标准。它使用非对称加密算法,包含一对密钥:
- 私钥:用于签名和解密,必须严格保密
- 公钥:用于验证签名和加密,可以公开分享
安装 GPG
Linux (Ubuntu/Debian):
sudo apt update
sudo apt install gnupg macOS:
brew install gnupg Windows:
下载并安装 Gpg4win
生成 GPG 密钥对
# 生成新的密钥对
gpg --gen-key 按提示依次输入:
- 真实姓名
- 邮箱地址(必须与 Git 配置的邮箱一致)
- 密钥密码(强密码保护私钥)
管理 GPG 密钥
查看密钥
# 查看所有公钥
gpg --list-keys
# 查看私钥(包含密钥 ID)
gpg --list-secret-keys --keyid-format LONG 导出公钥
# 导出 ASCII 格式的公钥
gpg --armor --export 你的邮箱地址
# 导出到文件
gpg --armor --export 你的邮箱地址 > public_key.asc 备份和恢复
# 备份私钥(重要!)
gpg --armor --export-secret-keys 你的邮箱地址 > private_key.asc
# 导入密钥
gpg --import private_key.asc 配置 Git 使用 GPG 签名
基本配置
# 设置用户信息(邮箱必须与 GPG 密钥匹配)
git config --global user.name "Your Name"
git config --global user.email "your_email@example.com"
# 获取密钥 ID(从 gpg --list-secret-keys 输出中获取)
gpg --list-secret-keys --keyid-format LONG
# 配置签名密钥
git config --global user.signingkey 你的密钥ID
# 启用自动签名
git config --global commit.gpgsign true
git config --global tag.gpgsign true 环境配置
# 设置 GPG TTY(解决签名时的输入问题)
export GPG_TTY=$(tty)
# 永久添加到 shell 配置
echo 'export GPG_TTY=$(tty)' >> ~/.bashrc
# 或者对于 zsh 用户
echo 'export GPG_TTY=$(tty)' >> ~/.zshrc macOS 特殊配置
# 安装 pinentry-mac(更好的密码输入体验)
brew install pinentry-mac
# 配置 gpg-agent
echo "pinentry-program /opt/homebrew/bin/pinentry-mac" >> ~/.gnupg/gpg-agent.conf
# 重启 gpg-agent
gpg-connect-agent reloadagent /bye 在 GitHub 上配置 GPG 公钥
- 导出你的 GPG 公钥:
gpg --armor --export 你的密钥ID - 复制输出的全部内容(包括
-----BEGIN PGP PUBLIC KEY BLOCK-----和-----END PGP PUBLIC KEY BLOCK-----) - 在 GitHub 上添加:
- 进入 Settings → SSH and GPG keys
- 点击 "New GPG key"
- 粘贴公钥内容
- 点击 "Add GPG key"
使用 GPG 签名
自动签名
配置完成后,每次提交都会自动签名:
git add .
git commit -m "Your commit message"
# 会自动使用 GPG 签名 手动控制签名
# 强制签名单次提交
git commit -S -m "Signed commit"
# 禁用单次提交的签名
git commit --no-gpg-sign -m "Unsigned commit"
# 签名标签
git tag -s v1.0 -m "Signed tag" 验证签名
本地验证
# 查看最近提交的签名信息
git log --show-signature -1
# 查看多个提交的签名状态
git log --pretty="format:%h %G? %an %s" -5 签名状态标识:
G= 有效签名 (Good signature)B= 无效签名 (Bad signature)U= 签名有效但密钥不受信任 (Untrusted)X= 签名已过期 (eXpired)Y= 签名由过期密钥创建 (expired keY)R= 签名由吊销密钥创建 (Revoked)E= 签名验证错误 (Error)N= 无签名 (No signature)
GitHub 验证
在 GitHub 上,正确配置的签名提交会显示:
- ✅ Verified - 签名有效且公钥已添加
- ❌ Unverified - 签名无效或公钥未添加
- 无标记 - 提交未签名
SSH 签名:现代化的替代方案
从 Git 2.34 版本开始,Git 支持使用 SSH 密钥进行签名,这为已经熟悉 SSH 的开发者提供了更简单的选择。
SSH 签名的优势
- 简化配置:复用现有的 SSH 密钥
- 统一管理:一套密钥解决认证和签名
- 减少复杂性:避免 GPG 的环境配置问题
配置 SSH 签名
生成 SSH 密钥(如果还没有)
# 生成 ed25519 密钥(推荐)
ssh-keygen -t ed25519 -C "your_email@example.com"
# 或生成 RSA 密钥
ssh-keygen -t rsa -b 4096 -C "your_email@example.com" 配置 Git 使用 SSH 签名
# 设置签名格式为 SSH
git config --global gpg.format ssh
# 设置 SSH 签名密钥(使用公钥文件路径)
git config --global user.signingkey ~/.ssh/id_ed25519.pub
# 启用自动签名
git config --global commit.gpgsign true 在 GitHub 上添加 SSH 签名密钥
- 复制你的 SSH 公钥:
cat ~/.ssh/id_ed25519.pub - 在 GitHub 上添加:
- 进入 Settings → SSH and GPG keys
- 点击 "New SSH key"
- Key type 选择 "Signing Key"(注意不是 Authentication Key)
- 粘贴公钥内容
SSH vs GPG 签名对比
| 特性 | SSH 签名 | GPG 签名 |
|---|---|---|
| 配置复杂度 | 简单 | 复杂 |
| 密钥管理 | 复用现有 SSH 密钥 | 需要专门的 GPG 密钥 |
| 生态支持 | 较新,支持有限 | 成熟,广泛支持 |
| 密钥格式 | SSH 公钥文件路径 | GPG 密钥 ID |
| 适用场景 | 个人项目,简化配置 | 企业项目,严格安全要求 |
常见问题与解决方案
GPG 签名失败
问题:gpg: signing failed: Inappropriate ioctl for device
# 解决方案:设置 GPG TTY
export GPG_TTY=$(tty) 问题:gpg: signing failed: No secret key
# 检查密钥是否存在
gpg --list-secret-keys
# 检查 Git 配置的密钥 ID 是否正确
git config user.signingkey 问题:密码输入界面无法显示(macOS)
# 安装并配置 pinentry-mac
brew install pinentry-mac
echo "pinentry-program /opt/homebrew/bin/pinentry-mac" >> ~/.gnupg/gpg-agent.conf
gpg-connect-agent reloadagent /bye 签名验证问题
GitHub 上显示 "Unverified"
- 确认邮箱匹配:
git config user.email
gpg --list-keys - 确认公钥已添加到 GitHub
- 确认密钥未过期
签名状态显示 "U" (Untrusted)
# 信任自己的密钥
gpg --edit-key 你的密钥ID
# 在交互界面中输入 trust,选择信任级别 性能优化
缓存 GPG 密码
编辑 ~/.gnupg/gpg-agent.conf:
default-cache-ttl 3600
max-cache-ttl 86400 禁用特定仓库的签名
# 在特定项目中禁用签名
git config commit.gpgsign false 最佳实践
密钥管理
- 定期备份私钥:将私钥导出并安全存储
- 设置密钥过期时间:建议 2-4 年,到期前续期
- 使用强密码:保护私钥的密码应该足够复杂
- 撤销泄露密钥:如果私钥泄露,立即撤销并生成新密钥
团队协作
- 统一签名策略:团队应该统一使用 GPG 或 SSH 签名
- 密钥服务器:考虑使用企业密钥服务器管理团队密钥
- CI/CD 集成:配置自动化流程验证提交签名
安全考虑
- 密钥轮换:定期更新签名密钥
- 多设备同步:安全地在多个设备间同步密钥
- 审计日志:记录密钥使用和签名活动
完整配置示例
GPG 签名完整配置
# 1. 安装 GPG
brew install gnupg # macOS
# 2. 生成密钥
gpg --gen-key
# 3. 获取密钥 ID
KEY_ID=$(gpg --list-secret-keys --keyid-format LONG | grep '^sec' | awk '{print $2}' | cut -d'/' -f2)
# 4. 配置 Git
git config --global user.name "Your Name"
git config --global user.email "your_email@example.com"
git config --global user.signingkey $KEY_ID
git config --global commit.gpgsign true
# 5. 设置环境
echo 'export GPG_TTY=$(tty)' >> ~/.zshrc
# 6. 导出公钥
gpg --armor --export $KEY_ID SSH 签名完整配置
# 1. 生成 SSH 密钥(如果没有)
ssh-keygen -t ed25519 -C "your_email@example.com"
# 2. 配置 Git
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true
# 3. 显示公钥用于添加到 GitHub
cat ~/.ssh/id_ed25519.pub 结论
Git 提交签名是现代软件开发中的重要安全实践。GPG 签名提供了成熟、全面的解决方案,适合对安全有严格要求的项目;而 SSH 签名则为个人开发者和小团队提供了更简化的选择。
选择哪种签名方式主要取决于:
- 项目需求:企业项目通常偏好 GPG,个人项目可以选择 SSH
- 团队规模:大团队建议统一使用 GPG,小团队可以考虑 SSH
- 技术背景:熟悉 SSH 的团队可能更容易接受 SSH 签名
无论选择哪种方式,重要的是建立一致的签名策略,确保代码的完整性和可信


