Workflows
签名提交工作流
使用 GPG 或 SSH 签名提交,建立可验证的提交身份和可信协作链。
- 要把命令组合成稳定流程的团队成员
- 需要处理协作顺序和分支边界的人
- 知道 fetch / pull / push / branch 的基本作用
- 能理解一条分支为什么会分叉
- 照抄流程却没确认当前分支关系
- 在共享分支上用错整合方式
一句话理解
签名提交通过 GPG 或 SSH 密钥对每次提交进行加密签名,让协作者可以验证提交确实来自声称的作者,防止身份伪造和供应链攻击。
GPG 密钥对配置 git config公钥上传平台
提交带签名标记平台显示 Verified仓库完整性可检
签名不是可选项,而是信任基础设施。从第一天就配置好比中途补救容易。
为什么需要签名提交
在开源项目和大型团队中,任何人都可以设置任意的 user.name 和 user.email。恶意攻击者可以伪造身份提交恶意代码。签名提交让身份可验证、历史可信任。
未签名提交:
commit abc123
Author: Alice <alice@example.com>
← 无法证明真的是 Alice
签名提交:
commit def456
Author: Alice <alice@example.com>
gpgsig: -----BEGIN PGP SIGNATURE-----
← 可以用 Alice 的公钥验证
GPG 签名工作流
1. 生成 GPG 密钥
# 生成 GPG 密钥(推荐 RSA 4096 或 Ed25519)
gpg --full-generate-key
# 选择密钥类型和大小
# 输入姓名和邮箱(必须与 Git 配置一致)
2. 配置 Git 使用 GPG
# 列出密钥,获取 Key ID
gpg --list-secret-keys --keyid-format=long
# 配置 Git 使用该密钥
git config --global user.signingkey YOUR_KEY_ID
# 默认对所有提交签名
git config --global commit.gpgsign true
# 对标签签名
git config --global tag.gpgsign true
3. 提交并推送
# 如果 commit.gpgsign 未开启,手动签名提交
git commit -S -m "feat: add authentication"
# 创建签名标签
git tag -s v1.0.0 -m "Release version 1.0.0"
# 验证提交签名
git log --show-signature
# 验证标签签名
git tag -v v1.0.0
SSH 签名工作流(Git 2.34+)
相比 GPG,SSH 签名更轻量,可以直接复用你已有的 SSH 密钥。
# 生成 SSH 签名密钥(如果没有)
ssh-keygen -t ed25519 -C "signing@example.com" -f ~/.ssh/git_signing_key
# 配置 Git 使用 SSH 签名
git config --global user.signingkey ~/.ssh/git_signing_key.pub
git config --global gpg.format ssh
# 告诉 Git 哪些公钥是可信的
git config --global gpg.ssh.allowedSignersFile ~/.ssh/allowed_signers
# 添加可信签名者
echo "$(git config user.email) $(cat ~/.ssh/git_signing_key.pub)" >> ~/.ssh/allowed_signers
# 签名提交
git commit -S -m "feat: use ssh signing"
平台验证配置
GitHub
# 导出 GPG 公钥
gpg --armor --export YOUR_KEY_ID
# 或导出 SSH 公钥
cat ~/.ssh/git_signing_key.pub
# 复制到 GitHub Settings -> SSH and GPG keys -> New GPG key / Signing Key
GitLab
# 同样导出公钥后添加到 GitLab Profile -> GPG Keys / SSH Keys
# 签名提交后,GitLab 会显示 "Verified" 徽章
团队强制签名策略
通过 GitHub Branch Protection
Settings -> Branches -> Branch protection rules
-> Require signed commits
通过 Git Hook 校验
# .git/hooks/commit-msg
#!/bin/sh
# 要求所有提交必须签名
git verify-commit HEAD 2>/dev/null || {
echo "Error: Commit must be signed"
exit 1
}
混合场景处理
部分提交不签名
# 临时跳过签名
git commit --no-gpg-sign -m "chore: quick fix"
# 只对重要提交签名
git commit -S -m "feat: security-critical change"
多设备使用
# 在不同设备上使用相同的 GPG 密钥
# 导出密钥对
gpg --export-secret-keys --armor YOUR_KEY_ID > private.key
# 在另一台设备导入
gpg --import private.key
# 安全删除导出文件
shred -u private.key
验证失败排查
| 问题 | 原因 | 解决 |
|---|---|---|
| gpg failed to sign | GPG agent 未运行 | gpgconf --launch gpg-agent |
| key not found | Git 配置的 key ID 不对 | 检查 user.signingkey |
| bad signature | 公钥未上传到平台 | 导出公钥到 GitHub/GitLab |
| 无法验证 | 公钥不在 allowed_signers | 检查 SSH 签名的 allowedSignersFile |
最佳实践总结
- 默认开启签名:设置
commit.gpgsign true,让签名成为默认行为 - 保护好私钥:GPG/SSH 私钥是身份凭证,使用强密码保护
- 设置密钥过期:即使主密钥不过期,子密钥也应设置合理过期时间
- 备份密钥:导出并安全备份密钥对,避免丢失后无法验证历史提交
- 平台互认:确保公钥已上传到所有使用的 Git 托管平台
- 团队统一策略:建议核心分支强制要求签名提交
注意事项
- 签名提交会产生额外的元数据,略微增加仓库体积
- 初次配置时验证流程可能比较繁琐,但这是一次性投入
- 在历史项目中启用签名时,未签名的旧提交不会自动变成已验证
- 如果密钥泄露,需要立即撤销并生成新密钥
- CI/CD 自动提交通常不需要签名,但关键发布标签建议签名