A signing key needs the same care as a password: a passphrase, a backup of the private key kept offline, and a plan for the day it leaks. GnuPG 6,212 prepared for that day when it created the key, by storing a revocation certificate. Sam uses it on the scratch key of GPG Signing:
cd ../sign-lab
sed 's/^:-----/-----/' ~/.gnupg/openpgp-revocs.d/*.rev | gpg --import
git verify-commit HEAD; echo "exit status $?"
git log --format="%G? %s"
cd ../booknestgpg: key 70C29C786E24664C: "Sam Rivera <sam@example.com>" revocation certificate imported ... gpg: Good signature from "Sam Rivera <sam@example.com>" [ultimate] gpg: WARNING: This key has been revoked by its owner! gpg: This could mean that the signature is forged. gpg: reason for revocation: No reason specified exit status 1 R Sign a commit with GPG
The certificate starts with a colon so it cannot be imported by accident; sed removes it. After import, the signature is still mathematically good, but verify-commit fails and %G? shows R. Publish the revoked key to a keyserver and to your hosting account so everyone else sees the revocation too. Expiry is the gentler tool: gpg --quick-set-expire <fingerprint> 1y extends a key before it lapses, and since Git 2.54 1,932 commits signed while the key was valid no longer show as alarming after it expires.
SSH keys have no built-in expiry, so Git reads it from the allowed signers file. OpenSSH 8.8 23,707 and later accept valid-after and valid-before options, and Git checks them against the commit's date, so rotating to a new key keeps old signatures valid:
sam@example.com valid-before="20270101" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDzL... old
sam@example.com valid-after="20261201" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKq7... newFor a stolen key, gpg.ssh.revocationFile names a file of revoked public keys (or an OpenSSH KRL); any signature by a key in it is treated as invalid, whatever its date.