错误信息
error: gpg failed to sign the data
也可能输出为
- fatal: failed to write commit object
- gpg: skipped "ABCDEF0123456789": No secret key
- gpg: signing failed: No secret key
Git 会在第一行之后打印 gpg 的 stderr,例如“gpg: skipped "<key>": No secret key”或“gpg: signing failed: Inappropriate ioctl for device”。如果 `gpg.program` 无法启动,Git 会打印“(no gpg output)”。
含义
Git 请求 GnuPG 对提交或标签对象签名,gpg 以错误退出,于是 Git 中止了操作(“fatal: failed to write commit object”)。Git 自己输出的这一行没有说明原因;与它一起打印的 gpg 输出行(或 `[GNUPG:]` 状态行)才会说明。最常见的是“No secret key”:配置的 `user.signingkey` 在当前密钥环中不存在。
原因
签名密钥不在当前密钥环中
常见`user.signingkey` 是从另一台机器、dotfiles 仓库或 CI 配置中复制过来的;对应的私钥从未导入这台机器(`gpg --list-secret-keys` 中看不到它)。
gpg 无法询问密码短语
常见没有设置 `GPG_TTY`、在 IDE 中、通过 SSH 或在 CI 中运行时,pinentry 既没有终端也没有图形界面可用。gpg 会报告“Inappropriate ioctl for device”或超时。
密钥或签名子密钥已过期
偶见gpg 拒绝用已过期的密钥签名;stderr 中的输出行会提到过期,或者该密钥会因不可用而被跳过。
Git 启动了错误的 gpg
偶见`gpg.program` 指向了不存在的可执行文件,或者指向 `gpg` 1.x,而密钥位于 GnuPG 2 的密钥环中(在装了多个版本的 macOS 上很常见)。
修复方法
- 1.
用配置的密钥手动运行 gpg
如果用同一把密钥执行 `gpg --clearsign` 也失败,问题就出在 GnuPG 而不是 Git——它给出的消息才是真正的错误信息。
bash git config --get user.signingkey gpg --list-secret-keys --keyid-format=long # is that key listed, with a "sec" line? echo test | gpg --clearsign --local-user "$(git config --get user.signingkey)" > /dev/null && echo "gpg can sign" - 2.
让 Git 指向已有的密钥,并让 pinentry 正常工作
使用本地已有私钥的长密钥 ID 或指纹,显式设置 `gpg.program`,并在 shell 中导出 `GPG_TTY`。
bash KEY=$(gpg --list-secret-keys --with-colons alice@example.com | awk -F: '/^sec/ {print $5; exit}') git config --global user.signingkey "$KEY" git config --global gpg.program "$(command -v gpg)" export GPG_TTY=$(tty) # in ~/.bashrc / ~/.zshrc, so pinentry can ask for the passphrase
相关错误
gpg: signing failed: Inappropriate ioctl for deviceGit commit signing with GnuPG 2error: gpg.ssh.allowedSignersFile needs to be configured and exist for ssh sign…Git (verify-commit, log --show-signature, merge --verify-signatures) with gpg.format=sshgpg: Can't check signature: No public keyGnuPG (gpg --verify, git verify-commit / verify-tag / log --show-signature)