A complete guide to generating a GPG key, configuring Git to sign commits, and setting up pinentry-mac so graphical apps like VS Code can sign commits and save your passphrase in the macOS Keychain.
Install GnuPG via Homebrew:
brew install gnupgVerify the installation:
gpg --versiongpg --full-generate-keyWhen prompted:
- Key type:
(1) RSA and RSA(default) - Key size:
4096 - Expiration:
0(never) or a duration like2y - Real name: Your name (should match your Git identity)
- Email: The email associated with your GitHub/GitLab account
- Comment: Optional — leave blank or add a label
- Passphrase: Choose a strong one — you'll save it to the Keychain later
List your keys to find the key ID:
gpg --list-secret-keys --keyid-format=longExample output:
sec rsa4096/3AA5C34371567BD2 2024-01-01 [SC]
ABCDEF1234567890ABCDEF1234567890ABCDEF12
uid [ultimate] Your Name <you@example.com>
ssb rsa2048/4BB6D45382678CE3 2024-01-01 [E]
Your key ID is the part after rsa4096/ on the sec line — in this example: 3AA5C34371567BD2.
Tell Git which key to use and enable signing globally:
git config --global user.signingkey 3AA5C34371567BD2
git config --global commit.gpgsign true
git config --global tag.gpgsign trueAlso make sure your Git identity matches the email on your GPG key:
git config --global user.email "you@example.com"
git config --global user.name "Your Name"If Git can't find gpg, tell it the path explicitly:
git config --global gpg.program $(which gpg)On Apple Silicon this is typically /opt/homebrew/bin/gpg.
Export your public key:
gpg --armor --export 3AA5C34371567BD2Copy the full output (from -----BEGIN PGP PUBLIC KEY BLOCK----- to -----END PGP PUBLIC KEY BLOCK-----), then add it to your account:
- GitHub: Settings → SSH and GPG keys → New GPG key
- GitLab: Preferences → GPG Keys → Add new key
Make a test commit and verify the signature:
git commit --allow-empty -m "test: verify GPG signing"
git log --show-signature -1You should see gpg: Good signature from "Your Name <you@example.com>" in the output.
By default, GPG tries to show a passphrase prompt in the terminal. Graphical apps don't have a terminal attached, so signing silently fails. pinentry-mac provides a native macOS dialog and can save your passphrase to the Keychain.
brew install pinentry-macFind your gpg-agent.conf file (create it if it doesn't exist):
mkdir -p ~/.gnupgOpen or create ~/.gnupg/gpg-agent.conf and add:
pinentry-program /opt/homebrew/bin/pinentry-mac
Note: On Intel Macs, Homebrew installs to
/usr/local/bin/pinentry-mac. Adjust the path accordingly. Confirm withwhich pinentry-mac.
GPG is strict about directory permissions and will refuse to run if they are too open:
chmod 700 ~/.gnupg
chmod 600 ~/.gnupg/*.conf 2>/dev/null; trueApply the new configuration:
gpgconf --kill gpg-agent
gpgconf --launch gpg-agentMake sure your shell exports the correct socket path. Add this to your ~/.zshrc (or ~/.bashrc):
export GPG_TTY=$(tty)Then reload:
source ~/.zshrcTrigger a signing operation from the terminal so the pinentry-mac dialog appears:
echo "test" | gpg --clearsignIn the passphrase dialog that appears:
- Enter your GPG key passphrase.
- Check "Save in Keychain".
- Click OK.
The passphrase is now stored in the macOS Keychain. The GPG agent will use it automatically for all future signing operations — including from VS Code and other GUI apps — without prompting again.
- Open VS Code and make a change in a Git repository.
- Stage the change and commit via the Source Control panel.
- The commit should complete without any passphrase prompt.
- Run
git log --show-signature -1in the terminal to confirm the commit is signed.
error: gpg failed to sign the data
Run export GPG_TTY=$(tty) in your terminal and try again. Make sure gpg-agent is running: gpgconf --launch gpg-agent.
Pinentry dialog never appears
Confirm pinentry-mac is on the path you specified in gpg-agent.conf: which pinentry-mac. Kill and relaunch the agent after any config change.
Passphrase is still being asked every time
The GPG agent caches credentials for a limited time. To extend the cache duration, add these lines to ~/.gnupg/gpg-agent.conf:
default-cache-ttl 86400
max-cache-ttl 604800
Then reload the agent. If you checked "Save in Keychain" and it's still prompting, the Keychain entry may not have been stored — repeat step 9.
Commits show as "Unverified" on GitHub
The email on your GPG key must exactly match the email in your GitHub account and in git config user.email. Re-export and re-upload the key if you updated the email.