Overview
Git shows “error: cannot spawn gpg: No such file or directory” when it cannot find the GnuPG binary while signing commits or tags. Fix it by installing GnuPG, ensuring it’s on PATH, and pointing Git to the absolute gpg path.
Common triggers:
- git commit -S, git tag -s, or commit.gpgsign=true
- Fresh machines, shells with restricted PATH, WSL/containers, or GUI clients
Quickstart (TL;DR)
- Install GnuPG.
- Confirm it’s on PATH: which gpg (Linux/macOS) or where gpg (Windows).
- Tell Git where to find it:
# Linux/macOS
GPG=$(command -v gpg || command -v gpg2)
[ -x "$GPG" ] || { echo "Install GnuPG first"; exit 1; }
git config --global gpg.program "$GPG"
# Windows PowerShell
$gpg = (Get-Command gpg.exe -ErrorAction SilentlyContinue).Source
if (-not $gpg) { Write-Error "Install GnuPG (e.g., Gpg4win or Chocolatey gnupg)"; exit 1 }
git config --global gpg.program "$gpg"
If you don’t have a key yet, generate one and set it as the signing key, then try a signed commit.
Minimal working example (creates a throwaway repo)
#!/usr/bin/env bash
set -euo pipefail
# 1) Locate GnuPG
GPG=$(command -v gpg || command -v gpg2)
if [ -z "${GPG:-}" ]; then
echo "GnuPG not installed. On macOS: brew install gnupg; Ubuntu: sudo apt-get install -y gnupg" >&2
exit 1
fi
echo "Using gpg at: $GPG"
git config --global gpg.program "$GPG"
# 2) Ensure a key exists (non-interactive demo key if missing)
if ! $GPG --list-secret-keys --with-colons | grep -q '^sec:'; then
$GPG --quick-generate-key "DevOps Demo <[email protected]>" default default never
fi
KEY=$($GPG --list-secret-keys --with-colons | awk -F: '/^sec:/ {print $5; exit}')
git config --global user.signingkey "$KEY"
echo "Signing key: $KEY"
# 3) Create a test repo and make a signed commit
rm -rf /tmp/gpgtest && mkdir -p /tmp/gpgtest && cd /tmp/gpgtest
git init -q
echo ok > README.md
git add README.md
git commit -S -m "Signed test commit" -q
echo "Success. Verify with: git log --show-signature -1"
Installation quick reference
- Linux (Debian/Ubuntu): sudo apt-get update && sudo apt-get install -y gnupg
- Linux (RHEL/CentOS/Fedora): sudo dnf install -y gnupg
- macOS (Homebrew): brew install gnupg
- Windows (Chocolatey): choco install gnupg
- Windows (winget): winget install GnuPG.GnuPG
After installing, re-open your terminal and re-run which gpg or where gpg.
Step-by-step fix
Reproduce the error
- Run: git commit -S -m "test" in any repo. If it fails with “cannot spawn gpg,” proceed.
Verify GnuPG availability
- Linux/macOS: which gpg || which gpg2
- Windows: where gpg
- If not found, install using the commands above.
Put gpg on PATH or point Git directly
- Recommended: set gpg.program to the absolute path to gpg.
# Use the exact path so GUI tools and non-login shells work too
GPG=$(command -v gpg || command -v gpg2)
git config --global gpg.program "$GPG"
$gpg = (Get-Command gpg.exe).Source
git config --global gpg.program "$gpg"
Create or import a key
- Create (non-interactive): gpg --quick-generate-key "Your Name [email protected]" default default 2y
- Or import: gpg --import yourkey.asc
Tell Git which key to use
KEY=$(gpg --list-secret-keys --keyid-format=long | awk '/^sec/ {print $2}' | sed 's|.*\/||' | head -n1)
git config --global user.signingkey "$KEY"
- Test signing
git commit -S -m "Signed" # or: git tag -s v1.0 -m "Signed tag"
- Make pinentry work (for passphrases)
- Linux/macOS: export GPG_TTY=$(tty) in your shell init (e.g., ~/.bashrc)
- Ensure a pinentry is installed (pinentry-tty, pinentry-curses, or pinentry-mac)
- CI/containers
- Install gnupg in the image, import the key, set gpg.program to the binary in the container, and run non-interactive signing.
OS-specific notes
- macOS (Homebrew): gpg usually installs to /opt/homebrew/bin/gpg (Apple Silicon) or /usr/local/bin/gpg. Use that full path in gpg.program.
- Windows: typical path is C:\Program Files\GnuPG\bin\gpg.exe. Confirm with where gpg. Configure Git to that absolute path.
- WSL: use Linux gpg inside WSL. Do not point WSL Git to Windows gpg.exe.
Common pitfalls
- gpg vs gpg2: Some systems name the binary gpg2. Use command -v gpg || command -v gpg2 and set gpg.program accordingly.
- Sudo resets PATH: git under sudo may not see your PATH. Avoid sudo for Git, or preserve PATH via sudo -E (with care).
- Headless shells: “Inappropriate ioctl for device” indicates pinentry cannot prompt. Set GPG_TTY and install a terminal pinentry.
- GUI clients/IDE: they may use a non-login shell. Set gpg.program to an absolute path so the client can find it.
- Corporate images: PATH is locked down by policy. Use per-user Git config gpg.program with a full path.
Performance notes
- Signing adds a small CPU cost per commit/tag; usually negligible on modern CPUs.
- Passphrase prompts can slow you down. Use gpg-agent caching. Example (Linux/macOS):
- Edit ~/.gnupg/gpg-agent.conf and set default-cache-ttl 3600
- Then reload: gpgconf --kill gpg-agent
- Hardware tokens (e.g., smartcards) introduce I/O latency; keep them connected and avoid USB power saving.
Frequently asked questions
How do I temporarily bypass signing?
- One commit: git -c commit.gpgsign=false commit -m "msg"
- Globally: git config --global commit.gpgsign false
How do I verify signatures?
- git log --show-signature -1
- git tag -v v1.0
Do I need gpg2 specifically?
- Any GnuPG 2.1+ works. Use the binary you have and set gpg.program to its path.
Why does it work in one terminal but not another?
- Different shells/launchers set different PATHs. Using an absolute gpg.program path avoids PATH variability.
Example Git config
# ~/.gitconfig
[commit]
gpgsign = true
[gpg]
program = /absolute/path/to/gpg
[user]
signingkey = ABCDEF1234567890
Summary
Install GnuPG, ensure the gpg binary is on PATH, and configure Git’s gpg.program to the absolute path. Then set a signing key and test a signed commit or tag. This resolves “error: cannot spawn gpg” reliably across Linux, macOS, Windows, WSL, and CI.