Overview
The Git error "gpg failed to sign the data" occurs when Git calls GnuPG (gpg) to sign a commit or tag but GPG cannot complete the signature. Typical causes:
- No secret key configured or wrong key selected
- gpg.program misconfigured (gpg vs gpg2, wrong path)
- Pinentry cannot prompt for passphrase (TTY issues, headless CI)
- gpg-agent not running or needs reset
- OS-specific issues (macOS pinentry, WSL TTY, Windows path)
This guide provides practical fixes for DevOps teams using Git.
Quickstart (most common fixes)
- Verify GPG is installed and v2+:
gpg --version - Export TTY (Linux/macOS):
export GPG_TTY=$(tty) - Ensure you have a secret key:
gpg --list-secret-keys --keyid-format=long - Configure Git to use gpg and your key:
git config --global gpg.program gpggit config --global user.signingkey <LONG_KEY_ID>- Optional:
git config --global commit.gpgsign true
- Make sure pinentry is installed and accessible (pinentry-mac, pinentry-tty/curses)
- Restart agent if needed:
gpgconf --kill gpg-agent - Test:
git commit -S -m "test"orgit tag -s v0.1 -m "sig"
Minimal Working Example
The following creates a test repo, generates a key if missing, and signs a commit.
# 1) Ensure GPG v2 and set TTY (Linux/macOS)
gpg --version
export GPG_TTY=$(tty)
# 2) Generate a key if you don't have one (interactive alternative below)
# Uses ed25519 signing key that never expires
NAME="Dev Ops"; EMAIL="[email protected]"
gpg --quick-generate-key "$NAME <$EMAIL>" ed25519 sign 0
# Find your key and capture the long key ID
KEY=$(gpg --list-secret-keys --keyid-format=long | awk '/sec/ {print $2}' | sed 's|.*\/||' | head -n1)
# 3) Configure Git to sign with GPG
git config --global gpg.program gpg
git config --global user.signingkey "$KEY"
git config --global commit.gpgsign true
# 4) Create a repo and make a signed commit
mkdir -p /tmp/gpg-sign-demo && cd /tmp/gpg-sign-demo
git init
echo ok > README.md
git add README.md
git commit -S -m "Signed commit"
Interactive key generation alternative:
gpg --full-generate-key # choose RSA 4096 or ed25519; enable signing capability
Step-by-step fixes
- Confirm GPG v2 is available
- Run
gpg --version. Look for “gpg (GnuPG) 2.x”. If only v1 exists, install GnuPG v2.
- Select the correct binary in Git
- Linux/macOS:
git config --global gpg.program gpg - If your system uses gpg2:
git config --global gpg.program gpg2 - Windows (Gpg4win):
# Use the actual installed path
git config --global gpg.program "C:/Program Files/GnuPG/bin/gpg.exe"
# or
git config --global gpg.program "C:/Program Files (x86)/GnuPG/bin/gpg.exe"
- Ensure a secret key exists and is usable
- List keys:
gpg --list-secret-keys --keyid-format=long - If empty, generate a key (see MWE above). Ensure the key has signing capability.
- Set your Git identity and default signing key:
git config --global user.name "Your Name"
git config --global user.email "[email protected]"
git config --global user.signingkey <LONG_KEY_ID>
- Fix pinentry and TTY issues
- Linux/macOS shells:
export GPG_TTY=$(tty)(add to your shell profile) - Install a pinentry tool:
- macOS:
brew install pinentry-macthen ensure it is used by GPG - Linux: install
pinentry-ttyorpinentry-cursesfrom your distro
- macOS:
- Force a specific pinentry via gpg-agent:
echo "pinentry-program $(command -v pinentry-mac || command -v pinentry-tty || command -v pinentry-curses)" >> ~/.gnupg/gpg-agent.conf
gpgconf --kill gpg-agent
- Reset the GPG agent cache
gpgconf --kill gpg-agentthen retry signing.
- WSL-specific
- Use Linux GPG inside WSL, not Windows GPG.
- Always set
export GPG_TTY=$(tty)in your WSL shell. - If using a smartcard/YubiKey, ensure scdaemon access inside WSL.
- macOS-specific
- Prefer
pinentry-mac. After install, restart agent as above. - If prompts do not appear, check privacy settings for pinentry.
- Windows-specific
- Install Gpg4win. Configure
gpg.programto its gpg.exe path. - If terminal prompts fail, try committing from Git Bash instead of CMD.
- Headless CI
- Pinentry cannot prompt; options:
- Use a key without passphrase restricted to CI and store securely.
- Or enable loopback mode:
echo allow-loopback-pinentry >> ~/.gnupg/gpg-agent.conf
gpgconf --kill gpg-agent
git config --global gpg.program "gpg --pinentry-mode=loopback"
- Provide passphrase via GPG tooling if absolutely required. Prefer rotating CI-only keys.
- Verify signing end-to-end
- Commit:
git commit -S -m "test" - Tag:
git tag -s v1.0 -m "release" - Inspect:
git log --show-signature -1
Common errors and targeted fixes
| Error snippet | Likely cause | Quick fix |
|---|---|---|
| gpg: signing failed: No secret key | Wrong/no key | Generate/import key; set user.signingkey |
| gpg: signing failed: Inappropriate ioctl for device | No TTY/pinentry | export GPG_TTY=$(tty); install pinentry; restart agent |
| error: gpg failed to sign the data | Wrong gpg.program | git config --global gpg.program gpg (or path to gpg.exe) |
| gpg: decryption failed: No secret key | Wrong key selected | Pick the correct LONG_KEY_ID |
| gpg: signing failed: No pinentry | Headless/GUI issues | Configure pinentry or loopback mode |
Pitfalls
- Mixing gpg v1 and v2 binaries. Always use v2.
- Key without “sign” capability (e.g., encryption-only). Create a signing-capable key.
- Enabling commit.gpgsign globally can stall rebases in noninteractive shells. Temporarily disable:
git -c commit.gpgsign=false rebase .... - Multiple GPG homes. If scripts set GNUPGHOME, ensure it matches where keys live.
- Smartcards require scdaemon; device access or permissions may block signing.
Performance notes
- Signing each commit adds a gpg-agent round-trip. Mitigate by:
- Ensuring gpg-agent is running and passphrase caching is enabled (default).
- Signing only tags and release merge commits if full-time signing is too slow.
- Avoiding remote filesystems for the GPG home to reduce latency.
Tiny FAQ
Q: Do I need to use gpg2 specifically? A: Use whichever command maps to GnuPG v2. Set git’s gpg.program accordingly.
Q: How do I pick the right key ID? A: Use the long key ID from
gpg --list-secret-keys --keyid-format=longand set it with user.signingkey.Q: Can I disable signing temporarily? A: Yes.
git -c commit.gpgsign=false commitorgit config commit.gpgsign false.Q: Alternative to GPG for signing? A: Git also supports SSH signing. If GPG is operationally hard, consider SSH signing policies.
Q: My GUI never shows a pinentry prompt. A: Ensure a GUI pinentry is installed and selected, or use a terminal with GPG_TTY set.