Skip to content

Instantly share code, notes, and snippets.

@jcefoli
Last active January 31, 2026 08:45
Show Gist options
  • Select an option

  • Save jcefoli/bdaeb48e2eba8cf724bc72de15d020a0 to your computer and use it in GitHub Desktop.

Select an option

Save jcefoli/bdaeb48e2eba8cf724bc72de15d020a0 to your computer and use it in GitHub Desktop.
GPG Git Commit Signing Key Cheatsheet

GPG Signing Cheatsheet

This guide walks through best practices of creating a gpg key and signing subkey for the purposes of signing git commits and some brief GitHub instructions.

Creating the Primary Key

First, create the primary key with the following config parameters: Ed25519, certify-only, 5-year expiry This primary key is only used to certify/renew subkeys; this key will be moved off the workstation and secured)

$keyUid="Your Name <[email protected]>"
gpg --quick-generate-key $keyUid ed25519 cert 5y

Get the primary key fingerprint (40 hex chars) and copy to variable [string]$primaryFingerprint)

gpg --list-keys --keyid-format=long
$primaryFingerprint = 'put fingerprint here'

Creating the Signing Subkey

This next step will create an Ed25519 signing subkey with a 2-year expiry

gpg --quick-add-key $primaryFingerprint ed25519 sign 2y

💾 Full Backup

❗🔑 Important Security Note - Store these backup files on another device / in a password manager, secrets store, etc)

Export the Primary Secrets and Owner Trust

gpg -a --export-options backup --export-secret-keys $primaryFingerprint > primary-secrets-backup.asc
gpg --export-ownertrust > ownertrust.txt

Export subkeys-only (for daily use)

gpg -a --export-secret-subkeys $primaryFingerprint > subkeys-only.asc

🧹 Remove the PRIMARY private key (keep subkeys only) ---

Delete the primary secret key

gpg --delete-secret-keys $primaryFingerprint

Ensure subkeys-only are present (re-import if needed)

gpg --import subkeys-only.asc

Validate that the primary eret key offline; daily machine keeps only signing/encryption subkeys)

Add the new key to GitHub + configure Git to use signing subkey

Export PRIMARY public key (which includes subkeys) and paste into GitHub

gpg --armor --export $primaryFingerprint

In GitHub, navigate to → Settings → SSH and GPG keys → New GPG key → paste / name it → Save

Find your signing subkey ID (16 characters; the one git will use)

gpg --list-secret-keys --keyid-format=long

Configure Local Git

git config --global user.name  "Your Name"
git config --global user.email "[email protected]"

Pin Git to the signing subkey (add '!' to force that exact subkey ID)

git config --global user.signingkey <SUBKEYID>!
git config --global commit.gpgsign true

On Windows (Gpg4win), ensure Git uses the right gpg.exe

git config --global gpg.program "C:\Program Files (x86)\GnuPG\bin\gpg.exe"

Test Local Commit

git commit -S -m "Test signed commit"
git log --show-signature -1

🛡️Commits signed this way should now be marked verified on GitHub

Key Rotation

This section explains how to renew keys when they expire.

Rotate Signing Subkey (every ~2 years)

Your primary key shouldn’t live on your everyday device. You need to restore it into the keyring before you can renew the subkey.

Copy your primary-secrets-backup.asc onto your device securely, then import the primary + subkeys locally again:

gpg --import primary-secrets-backup.asc

Add a new signing subkey (Ed25519; extend 2 years)

gpg --quick-add-key <PRIMARY-FPR> ed25519 sign 2y

Export updated public key (now includes the new signing subkey) ---

gpg --armor --export <PRIMARY-FPR>

Paste into GitHub → Settings → SSH and GPG keys → New GPG key

Next, Update Local Git to use the New signing subkey Get the new subkey ID:

gpg --list-secret-keys --keyid-format=long   # get NEW_SUBKEY_ID
git config --global user.signingkey <NEW_SUBKEY_ID>!

🔑 SECURITY! Export New Subkey to

Recreate a fresh subkeys-only bundle (optional housekeeping)

gpg -a --export-secret-subkeys <PRIMARY-FPR> > subkeys-only.asc

Delete the primary secret key from this workstation again

gpg --delete-secret-keys <PRIMARY-FPR>

Ensure subkeys-only are imported

gpg --import subkeys-only.asc

Securely delete local backup file once it's secured

Notes:

  • Old commits remain verified because their public key stays on GitHub.
  • New commits sign with the new subkey and verify as usual.

TO DO: FIX FORMATTING FROM HERE DOWN.

Rotate PRIMARY key (every ~5 years)

You do not create a new primary key in normal rotation. You simply extend its expiration, re‑export the public key, and keep operating. Old commits remain verified regardless, as long as the key stays uploaded to GitHub


# --- Bring the primary private key online temporarily (from offline backup) ---
gpg --import primary-secrets-backup.asc

# --- Extend the PRIMARY key expiration (e.g., add another 5 years) ---
gpg --edit-key <PRIMARY-FPR>
# gpg> expire
# (Choose new expiration, e.g., 5y)
# gpg> save
#  (This is the standard way to extend key expiry in GnuPG)

# --- Re-export and update public key on GitHub ---
gpg --armor --export <PRIMARY-FPR>
# Paste into GitHub → Settings → SSH and GPG keys → New GPG key
# (Multiple keys are fine; keeping old/expired keys preserves verification)

# --- Re-offline the primary key again (recommended) ---
gpg -a --export-secret-subkeys <PRIMARY-FPR> > subkeys-only.asc
gpg --delete-secret-keys <PRIMARY-FPR>
gpg --import subkeys-only.asc
# Securely remove any temporary copies of your offline backup.

# Notes:
# - No need to change your Git config unless you also rotated the signing subkey.
# - GitHub will continue verifying all old commits (expired keys are fine).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment