GnuPG Cheatsheet - GPG Encrypt, Sign & Key Management
Everyday GPG collapses into four actions: generate a keypair, hand your public key over, let the other side encrypt with it, and decrypt or sign with your private key. What actually breaks is rarely the commands and almost always the key material, since a lost private key is unrecoverable and an unverified imported key may have been swapped in transit. So the first habit after generation is to export a backup, and the first habit after import is to check the fingerprint against a channel you trust. This sheet walks the full chain through key generation and management, import and export, encryption and decryption, signing and verification, trust and key servers, and Git signing. Two more habits pay off repeatedly: pass --armor for text-safe output you can paste into an email, and rely on gpg-agent to cache the passphrase so you are not retyping it for every message. Pinning the fingerprint through trustedchannels is what upgrades an imported key from merely present to genuinely trusted.
Typical Use Case
For engineers who need verifiable identity rather than trust-by-fiat: signing Git commits and tags, encrypting files for a teammate, verifying a downloaded release. GnuPG is older than most people expect and its failure modes are specific: a missing gpg-agent, a key whose trust was never set, a key server that silently serves nothing. This sheet covers key lifecycle, import/export, encryption, both signature styles, and commit signing.
Key Generation 8
gpg --full-generate-keygpg --quick-generate-key "Name <email>"gpg --list-keysgpg --list-secret-keysgpg --list-keys KEYIDgpg --edit-key KEYIDgpg --delete-key KEYIDgpg --delete-secret-key KEYIDImport & Export 6
gpg --export -a KEYID > pubkey.ascgpg --export-secret-keys -a KEYID > private.ascgpg --import pubkey.ascgpg --import private.ascgpg --send-keys KEYID --keyserver keyserver.ubuntu.comgpg --recv-keys KEYIDEncrypt & Decrypt 6
gpg -e -r recipient@domain.com secret.txtgpg -e -r user@domain.com -o secret.txt.gpg secret.txtgpg -d secret.txt.gpg > secret.txtgpg -c secret.txtgpg -d secret.txt.gpgecho "message" | gpg -e -r user@domain.comSign & Verify 6
gpg -s document.txtgpg --clear-sign document.txtgpg -b document.txtgpg --verify document.txt.sig document.txtgpg --verify document.txt.ascgpg --detach-sign -a file.tar.gzTrust & Keyserver 5
gpg --edit-key KEYID
> trustgpg --sign-key KEYIDgpg --refresh-keysgpg --search-keys "user@domain.com"gpg --fingerprint KEYIDGit Signing 6
git config --global user.signingkey KEYIDgit config --global commit.gpgsign truegit commit -S -m "message"git tag -s v1.0 -m "release"git verify-commit HEADgpgconf --kill gpg-agentParameter matrix
| Parameter | Effect | Example |
|---|---|---|
--quick-generate-key | Non-interactive key creation in one command, the scripted alternative to --full-generate-key | gpg --quick-generate-key "Name <email>" |
--recv-keys | Fetch someone's public key from a keyserver; needs a key ID or email, and a typo fails silently | gpg --recv-keys KEYID |
--clear-sign | Produce a cleartext signature: readable text with the signature embedded | gpg --clear-sign document.txt |
commit.gpgsign | Make every git commit GPG-signed automatically so verifiers can trace the key fingerprint | git config --global commit.gpgsign true |
gpgconf --kill gpg-agent | Restart the agent to clear stale passphrase state after changing a password | gpgconf --kill gpg-agent |
Common pitfalls
SymptomAfter gpg --import, gpg --verify still refuses the signature or prints a WARNING.
CauseThe key is imported but untrusted; gpg has no basis for considering it legitimate.
FixCheck gpg --fingerprint KEYID first, then gpg --edit-key KEYID and set trust to ultimate, and verify again.
Symptomgpg --recv-keys finishes silently but the key never appears locally.
CauseThe email is mistyped or the keyserver simply has no such key, so the response is empty.
FixRun gpg --search-keys "user@domain.com" to find the exact key ID, then gpg --recv-keys.
SymptomAfter changing the passphrase, gpg still accepts the old one or hangs.
Causegpg-agent holds stale passphrase state.
FixRun gpgconf --kill gpg-agent to restart the agent, then retry.
Symptomgit commit -S hangs in a terminal and always fails in CI.
Causegpg wants an interactive passphrase, which cannot exist without a TTY.
FixIn CI use gpg --batch --pinentry-mode loopback with the agent cache, and confirm it with gpgconf --kill gpg-agent before committing.
SymptomAn exported secret key gets committed to a repo or pasted into a chat app.
Causegpg --export-secret-keys -a KEYID emits a directly usable private key; leaking it forfeits the whole identity.
FixRevoke and regenerate: gpg --delete-secret-key KEYID plus a revocation of the public key. Keep private keys in a password manager or offline backup.
Troubleshooting
1Signature verification failed: compare fingerprints, then trust
gpg --fingerprint KEYID && gpg --verify document.txt.sig document.txtThe fingerprint must match what the other party published. Matching fingerprints plus a warning means trust is unset, not that the key is wrong.
2Find a key by email
gpg --search-keys "user@domain.com"Then fetch precisely with gpg --recv-keys KEYID rather than passing the email directly.
3Confirm local key material is complete
gpg --list-keys && gpg --list-secret-keysPublic keys present but no secret keys means the private half is missing or deleted, and signing will fail.
4Reset the agent when it misbehaves
gpgconf --kill gpg-agentStale passphrase cache, password changes not taking effect and gpg hangs all start here.
Command Examples
Generate a new key pair without any prompts
gpg --quick-generate-key "Name <email>"The default algorithms and subkeys are fine for everyday signing and encryption; verify the private half landed with gpg --list-secret-keys.
Encrypt to a recipient key with an explicit output name
gpg -e -r user@domain.com -o secret.txt.gpg secret.txtOnly the recipient public key is needed here; they decrypt with their own private key, so exposure of this public key is not the risk.
Create a clear-text signature with a readable body
gpg --clear-sign document.txtThe result is readable content plus an embedded signature in a .asc file, verified with gpg --verify document.txt.asc alone.
Verify the signature on the latest Git commit
git verify-commit HEADCommits are only signed after you set user.signingkey and turn on commit.gpgsign with git config --global; otherwise there is nothing for this to verify.
Common Pitfalls
- Never let an exported private key file such as private.asc reach a Git repository or a chat app; a leak hands someone a complete clone of your identity.
- Verify the fingerprint out of band before raising trust to ultimate, because trust is the assertion that this key belongs to this person, not a button you click casually.
- If GPG still accepts the old passphrase or commands hang after a passphrase change, restart the agent with gpgconf --kill gpg-agent before chasing anything else.
- A valid signature is not the same as a trusted identity: read the WARNING lines and the trust level after gpg --verify, and confirm with gpg --fingerprint when it matters.
- Confirm the recipient public key is actually present before encrypting (gpg --recv-keys, then re-check with gpg --list-keys); a missing key fails quietly rather than loudly.
Tips
- Sign Git commits: git config --global commit.gpgsign true with a GPG key.
- gpg --armor (-a) produces ASCII keys/signatures for easy text transfer.
- Back up keys: gpg --export-secret-keys -a KEYID > private.asc, store safely.
- gpg-agent caches the passphrase so you don't retype it.
- gpgconf --kill gpg-agent restarts the agent to fix cache issues.
- A key fingerprint verifies authenticity - always check it after importing.
FAQ
gpg --verify says the signature is good, yet it still warns that the signature is not from this key. What is going on?
A good signature only proves the data matches the signature, not that you trust the signer. First compare gpg --fingerprint KEYID against the fingerprint the other party gave you through a channel you already trust, then raise the trust level with gpg --edit-key KEYID. If the fingerprints differ, stop: that is not the key generated by the person you think it is.
gpg --recv-keys finishes silently with no output and no error, yet the public key never arrives. Why?
Almost always the identifier is wrong. A single mistyped character in the address is not an error condition, the command simply finds nothing. Search the keyserver first with gpg --search-keys "user@domain.com" to confirm the spelling, then feed the KEYID it reports to --recv-keys. Afterwards confirm the key is really there with gpg --list-keys.
Should I use symmetric encryption or public-key encryption?
gpg -c uses only a passphrase and needs no public key, which suits encrypting something for yourself on the fly but leaves you responsible for transferring that passphrase securely. gpg -e -r user@domain.com is the right choice when a specific person is the reader: you hold nothing but their public key, and their own private key does the unlocking, which also means several recipients can each open the same file.
How does verification differ between a detached and a clear-text signature?
gpg -b leaves the original untouched and writes the signature to a separate .sig file, so verification needs both: gpg --verify document.txt.sig document.txt. gpg --clear-sign embeds the signature inside the file, so verification takes just that one file: gpg --verify document.txt.asc. Pick based on whether your recipient cares more about readable content or about the original bytes being unchanged.
After changing my private key passphrase, GPG still accepts only the old one, or commands just hang. Why?
The gpg-agent has a stale cached passphrase from before the change and keeps using it. Run gpgconf --kill gpg-agent to restart the agent, after which every private-key operation goes through a fresh passphrase prompt. A git commit -S that sits there without returning has the same root cause, so restart the agent before signing.
Official References
Each command links to its official documentation below, so you can verify the latest usage and read deeper.
Maintained by LaoHand
Publicly updated on Jul 21, 2026, continuously proofread against official docs.
Contact Us
Wrong command or description? Send us corrections, business inquiries or product feedback by email.
Contact Us