A complete, tested walkthrough for creating a GPG key, adding it to GitHub, and
fixing the gpg: signing failed: No pinentry error that Homebrew users hit on
M-series Macs.
Tested on macOS with Homebrew at /opt/homebrew (Apple Silicon). On Intel Macs,
replace /opt/homebrew with /usr/local everywhere below.
pinentry-mac is the dialog that prompts for your key passphrase. GnuPG does
not install it for you, and without it every signing attempt fails with
No pinentry.
brew install gnupg pinentry-mac
gpg --version
ls -l /opt/homebrew/bin/pinentry-mac # must exist before continuinggpg --full-generate-keyAnswer the prompts:
| Prompt | Answer |
|---|---|
| Key type | 1 (RSA and RSA) |
| Key size | 4096 |
| Expiration | 1y or 2y — renewable later with gpg --edit-key |
| Real name | Your name |
| A verified email on your GitHub account | |
| Passphrase | Strong; store it in your password manager |
The email is the part people get wrong. If it isn't verified under GitHub →
Settings → Emails, GitHub will either reject the key or mark your commits
Unverified.
gpg --list-secret-keys --keyid-format=longsec rsa4096/3AA5C34371567BD2 2026-09-22 [SC]
6D1D059002F640C0E123DAEF4158EA7997AC2E29
uid [ultimate] Your Name <you@example.com>
The key ID is the part after the slash on the sec line —
3AA5C34371567BD2 here. Export it for convenience:
export KEYID=3AA5C34371567BD2gpg --armor --export "$KEYID" | pbcopyThen go to GitHub → Settings → SSH and GPG keys → New GPG key and paste.
The pasted block must include both the -----BEGIN PGP PUBLIC KEY BLOCK-----
and -----END PGP PUBLIC KEY BLOCK----- lines.
git config --global user.signingkey "$KEYID"
git config --global commit.gpgsign true
git config --global tag.gpgsign true
git config --global gpg.program "$(which gpg)"Make sure the commit email matches the key's email exactly:
git config --global user.email # must equal the UID email from step 3echo "pinentry-program /opt/homebrew/bin/pinentry-mac" > ~/.gnupg/gpg-agent.conf
gpgconf --kill gpg-agentgpg-agent only reads this file at startup, so the --kill is not optional —
it respawns on the next use with the new config.
GnuPG also refuses to run with loose permissions:
chmod 700 ~/.gnupg
chmod 600 ~/.gnupg/*echo 'export GPG_TTY=$(tty)' >> ~/.zshrc
source ~/.zshrcUse ~/.zshrc, not ~/.zprofile. .zprofile only runs for login shells, so
tmux panes, editor terminals, and plain zsh subshells would inherit a stale
or empty GPG_TTY. $(tty) has to be re-evaluated per shell.
echo test | gpg --clearsign # should pop the passphrase dialog
git commit --allow-empty -m "test: verify gpg signing"
git log --show-signature -1 # should print "Good signature"After pushing, GitHub shows a green Verified badge next to the commit.
[GNUPG:] KEY_CONSIDERED 6D1D059002F640C0E123DAEF4158EA7997AC2E29 2
[GNUPG:] BEGIN_SIGNING H8
gpg: signing failed: No pinentry
KEY_CONSIDERED means GPG found your key fine — the failure is purely that
gpg-agent could not launch the passphrase dialog. Work through these in order:
- The binary isn't installed. This is the usual cause, even when
gpg-agent.conflooks correct. Check withls -l /opt/homebrew/bin/pinentry-mac; if it's missing,brew install pinentry-mac. - Wrong Homebrew prefix. Guides written for Apple Silicon use
/opt/homebrew/bin; on Intel Macs it's/usr/local/bin. Confirm the real path withwhich pinentry-macand put that in the config. - Agent not restarted. Run
gpgconf --kill gpg-agentafter any edit to~/.gnupg/gpg-agent.conf. - Invisible characters in the config. Run
cat -A ~/.gnupg/gpg-agent.conf; you should see exactlypinentry-program /opt/homebrew/bin/pinentry-mac$with no^Mand no trailing spaces. - Still failing? Run
gpg-agent --daemon --verbosein a second terminal to see which binary it tries to execute and why the exec fails.
Usually a missing or stale GPG_TTY — see step 7, and note that adding the
export to a shell config does not affect terminals that are already open.
The committer email doesn't match a verified GitHub email that is also on the
key's UID. Check all three: git config user.email, the UID from
gpg --list-secret-keys, and GitHub → Settings → Emails.
Cache it for longer by adding to ~/.gnupg/gpg-agent.conf:
default-cache-ttl 28800
max-cache-ttl 86400
Then gpgconf --kill gpg-agent. Check "Save in Keychain" in the pinentry-mac
dialog if you want macOS to hold it.
If you lose it, you cannot re-sign anything with that identity, and revoking it is the only option.
gpg --export-secret-keys --armor "$KEYID" > gpg-private-backup.asc
gpg --gen-revoke "$KEYID" > gpg-revocation-cert.ascStore both in a password manager or encrypted volume, never in a repo.
If GPG is more ceremony than you want, Git 2.34+ can sign with the SSH key you already use for pushing:
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign trueThen add the same public key to GitHub a second time, under Settings → SSH and GPG keys → New SSH key, with key type set to Signing Key. No agent config, no pinentry, and it works identically across machines.