Renewing an Expired GPG Key for Git Commit Signing
Table of Contents
- Table of Contents
- The Problem
- Step 1: Identify Your Expired Key
- Step 2: Extend the Expiration Date
- Step 3: Update Remote Git Hosts (GitLab, GitHub)
- Step 4: Exporting the GPG Key to Other Devices
- Quick Tip: Bypass Signing in an Emergency
The Problem
If you sign your Git commits using GPG, you might eventually encounter an error like this when attempting to commit changes:
$ git commit -m "My latest commit"
error: gpg failed to sign the data:
[GNUPG:] KEYEXPIRED 1794083815
[GNUPG:] KEY_CONSIDERED 111122223333444455556666AAAABBBBCCCCDDDD 3
gpg: skipped "111122223333444455556666AAAABBBBCCCCDDDD": Unusable secret key
[GNUPG:] INV_SGNR 9 111122223333444455556666AAAABBBBCCCCDDDD
[GNUPG:] FAILURE sign 54
gpg: signing failed: Unusable secret key
fatal: failed to write commit object
Best security practices recommend setting an expiration date (typically 1 or 2 years) when generating GPG keys. When that expiration date passes, GPG will refuse to use the secret key to sign data, returning Unusable secret key.
Fortunately, an expired key does not mean you need to create a new keypair. You can extend the validity of your existing primary key and subkeys without losing your signature history or breaking previous commit verifications.
Step 1: Identify Your Expired Key
First, find your key ID. You can check the key configured for Git:
git config user.signingkey
Or list all secret keys in your GPG keyring with long key IDs:
gpg --list-secret-keys --keyid-format LONG
You will see output similar to:
sec rsa4096/3AA5C34371567BD2 2024-11-08 [SC] [expired: 2026-11-07]
111122223333444455556666AAAABBBBCCCCDDDD
uid [ expired] User <user@example.com>
ssb rsa4096/42B317FD4BA89230 2024-11-08 [E] [expired: 2026-11-07]
Note your key ID (the 16-character string 3AA5C34371567BD2 or the full fingerprint 111122223333444455556666AAAABBBBCCCCDDDD). Notice that both the primary key (sec) and the subkeys (ssb) may be marked as [expired].
Step 2: Extend the Expiration Date
Open the interactive GPG key editor:
gpg --edit-key <YOUR_KEY_ID>
1. Update the Primary Key
At the gpg> prompt, run expire:
gpg> expire
GPG will ask for the validity period:
Changing expiration time for the primary key.
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0)
Type your preferred extension (e.g., 1y for one year or 2y for two years) and hit Enter. Confirm the date when prompted:
Is this correct? (y/N) y
If prompted, enter your GPG passphrase to authorize the modification.
2. Update the Subkeys
Most GPG keys use separate subkeys for signing ([S]), encryption ([E]), or authentication ([A]). If your signing subkey is expired, you also need to update its expiration date.
In the key listing within gpg>, identify the index of each subkey (e.g., 1, 2).
Select the first subkey:
gpg> key 1
(An asterisk * will appear next to ssb indicating it is selected.)
Now run expire again:
gpg> expire
Choose the same expiration period (e.g., 1y or 2y) and confirm with y.
Deselect the subkey by entering key 1 once more:
gpg> key 1
If you have additional subkeys (e.g., key 2), repeat the process for each one.
3. Save the Changes
Save and quit the GPG prompt:
gpg> save
Your local key is now valid again!
Step 3: Update Remote Git Hosts (GitLab, GitHub)
Even though your local GPG tool can now sign commits, remote platforms like GitLab and GitHub will continue to mark new commits as Unverified until they have your updated public key containing the new expiration date.
1. Export the Updated Public Key
Export your public key in ASCII-armored format:
gpg --armor --export <YOUR_KEY_ID>
Copy the entire output, including the -----BEGIN PGP PUBLIC KEY BLOCK----- and -----END PGP PUBLIC KEY BLOCK----- lines.
2. Update GitLab
- Navigate to User Settings -> GPG Keys (
https://gitlab.com/-/user_settings/gpg_keys). - Delete the expired key entry.
- Paste the newly exported key block into the Key field and click Add key.
3. Update GitHub (if applicable)
- Navigate to Settings -> SSH and GPG keys (
https://github.com/settings/keys). - If GitHub does not automatically refresh the expiration, delete the expired key and paste the newly exported public key.
4. (Optional) Sync with Public Keyservers
If you originally published your key to a public keyserver:
gpg --send-keys <YOUR_KEY_ID>
Step 4: Exporting the GPG Key to Other Devices
If you develop across multiple machines (such as a laptop, desktop, or remote server) and want to use the same GPG key for signing commits, you can transfer the keypair to your other devices.
1. Export from the Source Device
Export both the public key and the private (secret) key to ASCII-armored files:
# Export public key
gpg --armor --export <YOUR_KEY_ID> > public.key
# Export secret key (prompts for passphrase)
gpg --armor --export-secret-keys <YOUR_KEY_ID> > private.key
Security Note:
private.keycontains your private key material. Transfer it securely (e.g., usingscpover SSH or an encrypted USB drive). Never transmit it over unencrypted channels or commit it to a repository.
2. Import on the Target Device
On the target machine, import both files into the local keyring:
gpg --import public.key
gpg --import private.key
Once imported, delete the exported private.key file to prevent leaving sensitive keys on disk:
shred -u private.key
(On macOS or systems without shred, use rm private.key.)
3. Set Key Trust
Imported keys initially have an “unknown” trust level on a new keyring. To prevent warnings when signing commits, mark the key as ultimately trusted:
gpg --edit-key <YOUR_KEY_ID>
At the gpg> prompt:
gpg> trust
Select 5 (I trust ultimately), confirm with y, and save:
gpg> save
4. Configure Git on the Target Device
Configure Git to use the key for commit signing:
# Set your signing key
git config --global user.signingkey <YOUR_KEY_ID>
# Enable commit signing by default
git config --global commit.gpgsign true
If you encounter issues with GPG prompting for your passphrase in the terminal, ensure GPG_TTY is set in your shell configuration (~/.bashrc or ~/.zshrc):
export GPG_TTY=$(tty)
Quick Tip: Bypass Signing in an Emergency
If you are in a rush and need to commit immediately before you have a chance to update your key, you can instruct Git to bypass signing for a single commit:
git commit --no-gpg-sign -m "Urgent commit without signature"