Comprehensive guide to GPG commit signing. Set up, configure, and troubleshoot GPG commit signing. Fix GPG signing errors, configure passphrase caching, verify commit signatures. Use when working with Git commit signing, GPG keys, commit verification, signature verification, GPG configuration, or when encountering GPG signing errors. Covers Windows (Gpg4win), macOS (GPG Suite), Linux (gnupg), and WSL installation and setup.
Limited to specific tools
Additional assets for this skill
This skill is limited to using the following tools:
references/gpg-agent-config-example.confreferences/passphrase-caching.mdreferences/quick-reference.mdreferences/security-best-practices.mdreferences/test-scenarios.mdreferences/troubleshooting.mdreferences/windows-setup.mdComprehensive guidance for setting up, configuring, and troubleshooting GPG commit signing across all platforms.
Git commit signing provides cryptographic proof that commits came from you. This skill helps you:
This skill should be used when:
.gnupg/gpg-agent.conf configurationBasic Setup (Single Personal Key):
# 1. Install GPG (see Platform-Specific Setup below)
# 2. Generate key
gpg --full-generate-key
# Select: (9) ECC (sign and encrypt) → Curve 25519
# Expiration: 0 (no expiration)
# Passphrase: Strong 20+ character passphrase
# 3. Get key ID
gpg --list-secret-keys --keyid-format=long
# Look for "sec ed25519/<KEY_ID>"
# 4. Configure Git
git config --global user.signingkey <KEY_ID>
git config --global commit.gpgsign true
# 5. Export public key and add to GitHub
gpg --armor --export <KEY_ID>
# Paste at: https://github.com/settings/keys
For detailed Windows setup, see references/windows-setup.md.
Quick install:
# Option 1: Download installer
# https://gpg4win.org/thanks-for-download.html
# Option 2: winget
winget install --id GnuPG.Gpg4win -e --source winget
# Configure Git to use Gpg4win (adjust path if installed elsewhere)
git config --global gpg.program "C:/Program Files (x86)/GnuPG/bin/gpg.exe"
# Option 1: Homebrew (recommended)
brew install gnupg
# Option 2: GPG Suite
# Download from: https://gpgtools.org/
# Configure Git (if needed)
git config --global gpg.program $(which gpg)
# Debian/Ubuntu
sudo apt update && sudo apt install gnupg
# Fedora/RHEL
sudo dnf install gnupg2
# Arch
sudo pacman -S gnupg
WSL users: Follow the Linux setup instructions above (WSL runs Linux). See troubleshooting section for WSL-specific issues if needed.
# Generate key interactively
gpg --full-generate-key
# Follow prompts:
# 1. Key type: (9) ECC (sign and encrypt) *default*
# 2. Curve: (1) Curve 25519 *default*
# 3. Expiration: 0 = no expiration (or 2y for 2 years)
# 4. Real name: Your Name
# 5. Email: your.verified@email.com
# 6. Comment: (optional, can leave blank)
# 7. Passphrase: Strong 20+ character passphrase
# List keys to get KEY_ID
gpg --list-secret-keys --keyid-format=long
# Look for "sec ed25519/<KEY_ID>"
Recommended algorithm: EdDSA using Curve25519 (Ed25519) - modern, fast, small keys, excellent security
Alternative: RSA 4096-bit (traditional, widely compatible)
# Export public key (for GitHub)
gpg --armor --export <KEY_ID>
# Export private key (for backup only - KEEP SECURE!)
gpg --armor --export-secret-keys <KEY_ID>
# Global (all repositories)
git config --global user.signingkey <KEY_ID>
git config --global commit.gpgsign true
git config --global tag.gpgSign true
# Repository-local (specific repo)
cd /path/to/repo
git config user.signingkey <KEY_ID>
git config commit.gpgsign true
# Check configured key
git config --global user.signingkey
# Test signing
git commit --allow-empty -m "Test GPG signing"
# Verify signature
git log --show-signature -1
GPG agent caches passphrases to reduce how often you're prompted.
Check if config exists:
ls ~/.gnupg/gpg-agent.conf
Create or edit ~/.gnupg/gpg-agent.conf:
# Cache passphrase for 8 hours of inactivity
default-cache-ttl 28800
# Maximum cache time of 24 hours regardless of use
max-cache-ttl 86400
# Allow pinentry to cache the passphrase
allow-preset-passphrase
Apply changes:
gpgconf --kill gpg-agent
gpgconf --launch gpg-agent
For comprehensive caching configuration, including security scenarios, testing procedures, and troubleshooting, see references/passphrase-caching.md.
CRITICAL for Windows users: Windows typically has two separate GPG installations (Gpg4win and Git Bash GPG), each with different config file locations:
%APPDATA%\gnupg\gpg-agent.conf (typically C:\Users\<Username>\AppData\Roaming\gnupg\gpg-agent.conf)~/.gnupg/gpg-agent.conf (resolves to C:\Users\<Username>\.gnupg\gpg-agent.conf)Common problem: Configuring ~/.gnupg/gpg-agent.conf (Git Bash GPG) when Git is configured to use Gpg4win. Result: configuration silently ignored, caching doesn't work.
Verify which GPG Git is using:
# Check Git's GPG configuration
git config --global gpg.program
# If output is "C:/Program Files (x86)/GnuPG/bin/gpg.exe":
# → Use: %APPDATA%\gnupg\gpg-agent.conf
# Verify GPG's config directory
gpgconf --list-dirs homedir
Windows configuration must include pinentry-program:
# Example: %APPDATA%\gnupg\gpg-agent.conf
default-cache-ttl 28800
max-cache-ttl 86400
allow-preset-passphrase
# REQUIRED for Windows:
pinentry-program C:/Program Files (x86)/GnuPG/bin/pinentry-basic.exe
See: Windows Setup Guide - Dual GPG Installations for detailed explanation.
| Scenario | default-cache-ttl | max-cache-ttl | Rationale |
|---|---|---|---|
| High Security | 900 (15 min) | 3600 (1 hour) | Prompt frequently, short window |
| Balanced | 3600 (1 hour) | 28800 (8 hours) | Prompt every ~hour, expires by end of day |
| Convenience | 28800 (8 hours) | 86400 (24 hours) | Prompt once per workday, expires daily |
Export public key:
gpg --armor --export <KEY_ID>
Add to GitHub:
Verify email matches:
# Check Git email
git config --global user.email
# Check GPG key email
gpg --list-keys <KEY_ID>
Possible causes:
For comprehensive troubleshooting, see references/troubleshooting.md.
Cause: Git configured to use key ID that doesn't exist in keyring.
Solution:
# List available keys
gpg --list-secret-keys --keyid-format=long
# Verify Git config matches available key
git config --global user.signingkey
# If mismatch, update config
git config --global user.signingkey <CORRECT_KEY_ID>
Cause: GPG agent cannot prompt for passphrase (terminal issue).
Solution (Linux/macOS/WSL):
# Set GPG_TTY environment variable
export GPG_TTY=$(tty)
# Add to shell profile (e.g., ~/.bashrc, ~/.zshrc)
echo 'export GPG_TTY=$(tty)' >> ~/.bashrc
Solution (Windows with Gpg4win):
# Use GUI pinentry (adjust path to match your Gpg4win installation)
echo 'pinentry-program "C:/Program Files (x86)/GnuPG/bin/pinentry-basic.exe"' >> ~/.gnupg/gpg-agent.conf
gpgconf --kill gpg-agent
Debug steps:
# Test GPG signing directly
echo "test" | gpg --clearsign
# Check GPG agent status
gpgconf --list-components
# Check key expiration
gpg --list-keys --keyid-format=long <KEY_ID>
# Restart GPG agent
gpgconf --kill gpg-agent
gpgconf --launch gpg-agent
# Try commit again
git commit -m "test"
Windows users: This is commonly caused by dual GPG installation issues. See Windows Setup - Passphrase Caching Troubleshooting and Troubleshooting - Windows Caching Issue for detailed diagnosis.
Possible causes:
Wrong config file location (Windows):
# Verify which GPG Git is using
git config --global gpg.program
# Check GPG's config directory
gpgconf --list-dirs homedir
# Ensure config exists at correct location
# Windows (Gpg4win): %APPDATA%\gnupg\gpg-agent.conf
# Windows (Git Bash): ~/.gnupg/gpg-agent.conf
# Linux/macOS/WSL: ~/.gnupg/gpg-agent.conf
gpg-agent.conf not loaded:
# Restart agent to load config
gpgconf --kill gpg-agent
gpgconf --launch gpg-agent
# Verify config loaded
gpgconf --list-options gpg-agent | grep cache-ttl
Cache TTL set too low → Increase cache time in ~/.gnupg/gpg-agent.conf
Multiple GPG agents running:
# Kill all agents
pkill gpg-agent
# Launch single agent
gpgconf --launch gpg-agent
| Method | Best For | Setup Complexity | Key Management |
|---|---|---|---|
| GPG | Full-featured, supports expiration/revocation | Medium | Most flexible |
| SSH | Simplest, reuses existing SSH keys | Low | Limited features |
| S/MIME | Enterprise with X.509 certificates | High | Org-managed |
When to use SSH instead of GPG:
Setup:
# Configure Git to use SSH signing
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true
# Add SSH key to GitHub as "Signing Key"
Limitations:
For comprehensive security guidance, see references/security-best-practices.md.
Quick recommendations:
Date: 2025-11-28 Model: claude-opus-4-5-20251101