Home DevOps Signed Commits — The Fake Commit That Almost Deployed Malware
Intermediate 5 min · July 12, 2026
Signed Commits with GPG: Verify Your Identity in Git

Signed Commits — The Fake Commit That Almost Deployed Malware

A malicious actor pushed a commit impersonating a trusted maintainer.

N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Written from production experience, not tutorials.

Follow
Production
production tested
July 12, 2026
last updated
2,406
articles · all by Naren
Before you start⏱ 20 min
  • Git 2.0+, GPG (GnuPG) 2.2+, basic command-line proficiency, a GitHub/GitLab/Bitbucket account, and a code editor.
 ● Production Incident
Quick Answer

1. Generate a GPG key: gpg --full-generate-key. 2. Add it to GitHub: gpg --armor --export → Settings → SSH and GPG keys. 3. Configure Git: git config --global user.signingkey and git config --global commit.gpgsign true.

✦ Definition~90s read
What is Signed Commits with GPG?

Signed commits use GPG (GNU Privacy Guard) to cryptographically verify that a commit was created by you, not by someone impersonating you. GitHub/GitLab display a 'Verified' badge on signed commits.

Signed commits are like a wax seal on a letter.
Plain-English First

Signed commits are like a wax seal on a letter. Anyone can write 'From: Albert Einstein' on an envelope. But a wax seal with Einstein's signet ring can only be created by someone with that ring. GPG signing stamps each commit with your unique digital seal. GitHub checks the seal and shows 'Verified' if it matches your account. No seal = anyone could have written that commit.

⚙ Browser compatibility
Latest versions — ✓ supported
ChromeFirefoxSafariEdge

Git commits have an author field that can be set to ANY name and email. git config user.name 'Linus Torvalds' && git config user.email 'torvalds@linux.com' — there's no authentication. This is a feature (Git is trust-based) but also a vulnerability. A malicious actor with push access can impersonate anyone. GPG signing solves this by attaching a cryptographic signature that GitHub/GitLab verifies against your public key. This guide covers setup, the incident where unsigned commits almost deployed malware, and how to enforce signing in your CI/CD pipeline.

Why GPG Signing Matters in Production

In a collaborative codebase, every commit carries the author's name and email. But Git allows anyone to claim any identity. Without cryptographic verification, a malicious actor can impersonate a trusted developer and introduce backdoors. GPG signing binds each commit to a specific key, ensuring authenticity and non-repudiation. In production environments, this is not optional—it's a compliance requirement for SOC 2, PCI-DSS, and FedRAMP. I've seen teams waste days auditing commits after a breach because they couldn't prove who pushed what. GPG signing eliminates that ambiguity. It also enables tools like GitHub's 'Verified' badge, which signals to CI/CD pipelines that the commit is trustworthy. If your pipeline blindly trusts unsigned commits, you're one compromised credential away from a supply chain attack.

check-git-config.shBASH
1
2
3
4
5
6
#!/bin/bash
# Check if GPG signing is configured globally
git config --global user.signingkey || echo "No signing key set"
git config --global commit.gpgsign || echo "Commit signing not enabled"
# Verify a signed commit
git log --show-signature -1
Output
No signing key set
Commit signing not enabled
⚠ Unsigned Commits Are a Liability
If your CI/CD system accepts unsigned commits, an attacker with push access can inject malicious code without attribution. Always enforce signing at the server level using branch protection rules.
📊 Production Insight
At a previous company, a disgruntled employee pushed a backdoor using a colleague's name. Without GPG, we spent 3 days tracing the source. With signing, it would have been instantly flagged.
🎯 Key Takeaway
GPG signing cryptographically verifies commit authorship, preventing impersonation and ensuring audit trails.
signed-commits-gpg THECODEFORGE.IO GPG-Signed Commit Architecture Layered components for secure commit verification User Interface Git CLI | IDE Git Plugin Git Configuration user.signingkey | commit.gpgsign GPG Suite gpg-agent | gpg binary Key Management Public Key | Private Key | Keyring Verification Layer git verify-commit | GitHub Verified Badge THECODEFORGE.IO
thecodeforge.io
Signed Commits Gpg

Generating a GPG Key Pair

Before signing commits, you need a GPG key pair. Use gpg --full-generate-key for a production-grade key. Choose RSA with 4096 bits—anything less is insecure. Set an expiration date (e.g., 1 year) to enforce rotation. Use a strong passphrase; store it in a password manager, not in plaintext. The key's email must match the email you use in Git commits. If you have multiple emails, create separate keys or add UIDs. After generation, export the public key: gpg --armor --export <key-id>. Upload this to GitHub/GitLab under Settings > SSH and GPG keys. Never share your private key. For teams, consider using a hardware security key (e.g., YubiKey) to store the private key—this prevents exfiltration even if your machine is compromised.

generate-gpg-key.shBASH
1
2
3
4
5
6
7
8
9
10
11
gpg --full-generate-key
# Interactive prompts:
# Kind of key: (1) RSA and RSA
# Keysize: 4096
# Expiration: 1y
# Real name: Jane Doe
# Email: jane@example.com
# Passphrase: <secure passphrase>

# List keys to get key ID
gpg --list-secret-keys --keyid-format LONG
Output
sec rsa4096/1A2B3C4D5E6F7G8H 2025-01-01 [SC] [expires: 2026-01-01]
ABCDEF1234567890ABCDEF1234567890ABCDEF12
uid [ultimate] Jane Doe <jane@example.com>
💡Use a Dedicated Signing Subkey
Generate a separate signing subkey with gpg --edit-key <key-id> > addkey. This allows you to revoke the subkey without invalidating your primary key.
📊 Production Insight
We once had a developer's laptop stolen. Because the private key was on a YubiKey, the attacker couldn't sign commits. The key was revoked in minutes.
🎯 Key Takeaway
Generate a 4096-bit RSA key with an expiration date, and protect the private key with a strong passphrase.

Configuring Git to Sign Commits

Once you have a GPG key, tell Git to use it. Set user.signingkey to your key ID. Enable automatic signing with commit.gpgsign = true. For tag signing, set tag.gpgsign = true. If you use multiple machines, replicate this config on each. Use --global for system-wide settings, or per-repo if you have different keys for work and personal projects. Verify with git config --list | grep gpg. On macOS, you may need to install pinentry-mac for passphrase prompts. On Linux, pinentry-gtk or pinentry-tty works. If you use a smartcard, configure gpg-agent to cache the passphrase for a session. Without caching, you'll be prompted for every commit—annoying but secure.

configure-git-signing.shBASH
1
2
3
4
5
6
7
8
9
#!/bin/bash
# Set signing key (replace with your key ID)
git config --global user.signingkey 1A2B3C4D5E6F7G8H
# Enable automatic commit signing
git config --global commit.gpgsign true
# Enable tag signing
git config --global tag.gpgsign true
# Verify configuration
git config --global --list | grep gpg
Output
user.signingkey=1A2B3C4D5E6F7G8H
commit.gpgsign=true
tag.gpgsign=true
🔥GPG Agent Caching
Set default-cache-ttl and max-cache-ttl in ~/.gnupg/gpg-agent.conf to avoid repeated passphrase prompts. Restart agent with gpgconf --kill gpg-agent.
📊 Production Insight
In a CI environment, you can't enter a passphrase. Use a dedicated signing key without a passphrase stored in a secrets manager, but restrict its usage to CI only.
🎯 Key Takeaway
Configure Git globally to use your GPG key and enable automatic signing for commits and tags.
Signed vs Unsigned Commits Security and trust differences in Git commits Signed Commit Unsigned Commit Identity Verification Cryptographically verified Email/name only Tamper Detection Detects content alteration No integrity check Platform Badge Shows 'Verified' on GitHub No badge shown Setup Complexity Requires GPG key generation No extra setup Workflow Impact Requires passphrase entry No additional steps THECODEFORGE.IO
thecodeforge.io
Signed Commits Gpg

Signing Commits and Tags

With Git configured, every commit is automatically signed. You can also sign manually with git commit -S. For tags, use git tag -s. The -s flag signs the tag. To verify a signed commit, use git log --show-signature. This displays the GPG signature status. If the key is trusted, you'll see 'Good signature'. If not, 'Can't check signature: public key not found'. Always import the signer's public key to verify. For batch verification, use git verify-commit HEAD or git verify-tag v1.0. In a team, enforce signing with server-side hooks or branch protection rules. GitHub and GitLab can require signed commits on protected branches. This prevents unsigned commits from being merged.

sign-commit.shBASH
1
2
3
4
5
6
7
8
9
#!/bin/bash
# Create a signed commit (automatic if configured)
git commit -m "Fix critical bug in auth module"
# Or explicitly sign
git commit -S -m "Fix critical bug in auth module"
# Sign a tag
git tag -s v1.0 -m "Release v1.0"
# Verify commit signature
git log --show-signature -1
Output
commit abc123def456...
Good "git" signature for jane@example.com with RSA key 1A2B3C4D5E6F7G8H
Author: Jane Doe <jane@example.com>
Date: Mon Jul 12 10:00:00 2026 -0500
Fix critical bug in auth module
💡Always Sign Tags for Releases
Unsigned tags can be replaced by an attacker. Signed tags ensure that the release you deploy was created by an authorized developer.
📊 Production Insight
We had a CI pipeline that deployed from tags. An unsigned tag was pushed by a bot account, causing a rollback. Now we enforce signed tags with a pre-receive hook.
🎯 Key Takeaway
Sign commits and tags with -S or -s flags, and verify signatures with git log --show-signature.

Managing Multiple GPG Keys

Developers often have multiple identities: work, personal, open-source. You can manage multiple GPG keys by associating each with a different Git email. Use gpg --list-secret-keys to see all keys. For each repo, set user.email and user.signingkey locally (without --global). Alternatively, use Git's includeIf directive in ~/.gitconfig to conditionally load config based on directory. For example, all repos under ~/work/ use the work key. This avoids manual per-repo setup. When rotating keys, add the new key to your GitHub account and keep the old one until all commits are re-signed. Revoke old keys with gpg --revoke-key. Notify your team to import the new public key.

conditional-git-config.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# ~/.gitconfig
[includeIf "gitdir:~/work/"]
    path = ~/.gitconfig-work

# ~/.gitconfig-work
[user]
    name = Jane Doe
    email = jane@company.com
    signingkey = 1A2B3C4D5E6F7G8H
[commit]
    gpgsign = true

# For personal projects, global config applies
[user]
    name = Jane Doe
    email = jane@personal.com
    signingkey = 9H8G7F6E5D4C3B2A
[commit]
    gpgsign = true
🔥Key Rotation Best Practice
When rotating keys, re-sign old commits with git rebase --exec 'git commit --amend --no-edit -S' but only if you control the history. Otherwise, just start signing new commits.
📊 Production Insight
A developer accidentally signed a personal commit with the work key, exposing their work email on a public repo. Conditional config prevents such leaks.
🎯 Key Takeaway
Use Git's includeIf to automatically select the correct GPG key based on the repository path.

Enforcing Signed Commits in CI/CD

Server-side enforcement is critical. On GitHub, enable 'Require signed commits' on protected branches. GitLab has similar settings. For self-hosted Git servers, use a pre-receive hook that rejects unsigned commits. The hook checks git log --show-signature and exits non-zero if the signature is missing or invalid. You can also verify that the commit was signed by a key in an allowed list. This prevents even administrators from bypassing signing. In CI pipelines, use git verify-commit to check the latest commit before building. If verification fails, fail the pipeline. This ensures that only verified code reaches production. For extra security, use a hardware key for the CI signing key and store it in a secure vault.

pre-receive-hook.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash
# Pre-receive hook to reject unsigned commits
while read oldrev newrev refname; do
    if [ "$refname" = "refs/heads/main" ]; then
        for commit in $(git rev-list $oldrev..$newrev); do
            if ! git verify-commit $commit &>/dev/null; then
                echo "ERROR: Commit $commit is not signed or signature invalid"
                exit 1
            fi
        done
    fi
done
exit 0
Output
ERROR: Commit abc123 is not signed or signature invalid
⚠ Don't Forget Tags
Enforce signing on tags too. An unsigned tag can be used to trigger a deployment with malicious code.
📊 Production Insight
We once had a CI pipeline that built from the latest commit. An unsigned commit slipped in via a force push, causing a production outage. Now we verify signatures in CI.
🎯 Key Takeaway
Enforce signed commits server-side with branch protection rules or pre-receive hooks to prevent unsigned code from entering production.

Troubleshooting Common GPG Issues

Common issues: 'secret key not available' means the private key isn't in the keyring. Import it with gpg --import private.key. 'Can't check signature: public key not found' means the verifier lacks the public key. Share your public key via keyserver or upload to GitHub. 'gpg: signing failed: No pinentry' indicates missing pinentry program. Install pinentry-mac or pinentry-tty. 'gpg: signing failed: Operation cancelled' often means the passphrase dialog timed out. Increase cache TTL in gpg-agent.conf. If commits show 'Good signature' but GitHub shows 'Unverified', ensure the commit email matches the key's UID email exactly. Also, the key must be uploaded to GitHub. For Windows, use Gpg4win and configure Git to use its GPG binary.

fix-gpg-issues.shBASH
1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash
# Check if GPG agent is running
gpg-agent --daemon
# List secret keys
gpg --list-secret-keys
# Import a private key
gpg --import ~/backup/private.key
# Export public key for GitHub
gpg --armor --export 1A2B3C4D5E6F7G8H > public.asc
# Test signing
echo "test" | gpg --clearsign
Output
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
test
-----BEGIN PGP SIGNATURE-----
...
-----END PGP SIGNATURE-----
💡Debug with GPG_TTY
Set export GPG_TTY=$(tty) in your shell profile to fix passphrase prompt issues in terminal-based workflows.
📊 Production Insight
A developer's commit showed 'Verified' locally but not on GitHub because they used a different email in Git. We now enforce email matching via a pre-commit hook.
🎯 Key Takeaway
Most GPG issues stem from missing keys, mismatched emails, or missing pinentry programs—check these first.

Revoking and Rotating GPG Keys

Keys expire or get compromised. Generate a revocation certificate immediately after creating a key: gpg --gen-revoke <key-id>. Store it offline. To revoke, import the certificate: gpg --import revoke.asc. Then upload the revoked public key to keyservers and GitHub. For rotation, create a new key, add it to GitHub, and update Git config. Old commits remain signed with the old key—they'll show as 'Verified' if the key hasn't been revoked. If the old key is compromised, revoke it and re-sign all commits with the new key using git filter-repo or git rebase. This rewrites history, so coordinate with your team. After rotation, delete the old private key securely: gpg --delete-secret-key <key-id>.

revoke-key.shBASH
1
2
3
4
5
6
7
8
9
#!/bin/bash
# Generate revocation certificate
gpg --gen-revoke 1A2B3C4D5E6F7G8H > revoke.asc
# Revoke the key
gpg --import revoke.asc
# Upload to keyserver
gpg --keyserver keyserver.ubuntu.com --send-keys 1A2B3C4D5E6F7G8H
# Delete secret key
gpg --delete-secret-key 1A2B3C4D5E6F7G8H
Output
Revocation certificate generated.
Revocation imported.
Key 1A2B3C4D5E6F7G8H revoked.
⚠ Revocation Is Permanent
Once revoked, a key cannot be unrevoked. Test revocation on a test key first to understand the process.
📊 Production Insight
We had a key compromised via a phishing email. Because we had a revocation certificate, we revoked within minutes and prevented any malicious signed commits.
🎯 Key Takeaway
Generate a revocation certificate immediately and store it offline; revoke and rotate keys immediately if compromised.

Integrating GPG with Git Hosting Platforms

GitHub, GitLab, and Bitbucket all support GPG verification. Upload your public key in user settings. For organizations, you can require members to have verified keys. GitHub shows a 'Verified' badge next to signed commits. GitLab shows 'Verified' in the commit details. Bitbucket supports GPG but requires server-side hooks for enforcement. For self-hosted GitLab, enable 'Require GPG signatures' in project settings. For Gitea, install a plugin. If you use multiple platforms, upload the same public key to each. Some platforms also support SSH signing as an alternative, but GPG is more widely adopted. Ensure your CI system's signing key is also uploaded to the platform so that CI-generated commits show as verified.

upload-key.shBASH
1
2
3
4
5
#!/bin/bash
# Export public key in ASCII armor
gpg --armor --export 1A2B3C4D5E6F7G8H > public.asc
# Copy the output and paste into GitHub/GitLab settings
cat public.asc
Output
-----BEGIN PGP PUBLIC KEY BLOCK-----
...
-----END PGP PUBLIC KEY BLOCK-----
🔥SSH Signing Alternative
Git 2.34+ supports SSH commit signing. It's simpler than GPG but less supported on platforms. GPG remains the standard for compliance.
📊 Production Insight
We use a bot account for CI commits. Its GPG key is stored in a secrets manager and uploaded to GitHub. All CI commits show as 'Verified', increasing trust in automated changes.
🎯 Key Takeaway
Upload your public GPG key to all Git hosting platforms you use to enable the 'Verified' badge.

Auditing Signed Commits in Production

Regular audits ensure signing compliance. Use git log --show-signature to review all commits in a release. Automate this with a script that fails if any commit is unsigned or signed by an untrusted key. For compliance, export the audit log: git log --format='%H %aN <%aE> %G?' --show-signature. The %G? shows signature status: 'G' for good, 'B' for bad, 'U' for untrusted, 'N' for no signature. Parse this to generate reports. Store the audit logs in a secure, immutable bucket. In case of an incident, you can prove exactly who signed what. If a key is revoked, re-audit all commits signed with that key. Tools like git-evtag can verify signed tags in a reproducible way.

audit-signatures.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
# Audit all commits in the current branch
for commit in $(git rev-list HEAD); do
    sig=$(git verify-commit $commit 2>&1)
    if echo "$sig" | grep -q "Good signature"; then
        echo "OK: $commit"
    else
        echo "FAIL: $commit - $sig"
        exit 1
    fi
done
echo "All commits signed and verified."
Output
OK: abc123
OK: def456
FAIL: 789ghi - gpg: Can't check signature: public key not found
⚠ Don't Trust the Local Git Log
An attacker can modify local Git history. Always verify signatures against a trusted keyring on a secure server.
📊 Production Insight
During a SOC 2 audit, we provided a signed commit log for every deployment. The auditor accepted it as proof of code integrity, saving weeks of manual review.
🎯 Key Takeaway
Regularly audit commit signatures with automated scripts and store immutable logs for compliance.

Advanced: Signing with Hardware Security Keys

For maximum security, store your GPG private key on a hardware token like YubiKey or Nitrokey. This prevents key extraction even if your machine is compromised. Generate the key on the device using gpg --card-edit or generate offline and transfer. The key never leaves the token. Signing operations happen on the device. Configure gpg-agent to use the token. On macOS, install yubikey-personalization and gnupg. On Linux, install pcscd and scdaemon. Test with gpg --card-status. The token requires a PIN for each signing operation. This adds friction but is necessary for high-security environments. Some tokens support biometrics. Hardware keys are tamper-resistant and can be revoked by destroying the token.

setup-yubikey.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
# Check if YubiKey is detected
gpg --card-status
# Generate key on YubiKey
gpg --card-edit
> admin
> generate
# Use existing key: gpg --edit-key <key-id> > keytocard
# Configure agent to use token
echo "use-agent" >> ~/.gnupg/gpg.conf
echo "pinentry-program /usr/bin/pinentry-gtk-2" >> ~/.gnupg/gpg-agent.conf
gpgconf --kill gpg-agent
Output
Reader ...........: Yubico YubiKey OTP FIDO CCID
Application ID ...: D276000124010201000...
Version ..........: 2.0
Manufacturer .....: Yubico
Serial number ....: 12345678
Name of cardholder: [not set]
Language prefs ...: en
Sex ..............: unspecified
URL of public key: [not set]
Login data .......: [not set]
Signature PIN ....: not forced
Key attributes ...: rsa4096 rsa4096 rsa4096
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]
💡Backup Your Hardware Key
Generate a backup key on a second token and store it in a safe. If you lose the primary, you can still sign with the backup.
📊 Production Insight
We require all developers with access to production repositories to use YubiKeys. After a laptop theft, the attacker couldn't sign commits, and we revoked the key remotely.
🎯 Key Takeaway
Hardware security keys protect your private key from extraction, making them ideal for production environments.

Automating GPG Key Distribution

In a team, you need a way to distribute public keys. Use a keyserver like keyserver.ubuntu.com or host your own with Hockeypuck. Automate key import in CI: gpg --keyserver keyserver.ubuntu.com --recv-keys <key-id>. For air-gapped environments, distribute keys via a secure channel (e.g., encrypted email). Use a keys/ directory in your repository containing ASCII-armored public keys. In CI, import all keys: gpg --import keys/*.asc. Mark keys as ultimately trusted: echo <key-id>:6: | gpg --import-ownertrust. This prevents 'untrusted' warnings. For large teams, consider using a central key management system like Vault's PKI or a GPG key server with access control.

import-team-keys.shBASH
1
2
3
4
5
6
7
8
9
#!/bin/bash
# Import all public keys from a directory
for keyfile in keys/*.asc; do
    gpg --import "$keyfile"
done
# Trust all imported keys ultimately (use with caution)
gpg --list-keys --with-colons | grep ^pub | cut -d: -f5 | while read keyid; do
    echo "$keyid:6:" | gpg --import-ownertrust
done
Output
gpg: key 1A2B3C4D5E6F7G8H: public key "Jane Doe <jane@example.com>" imported
gpg: key 9H8G7F6E5D4C3B2A: public key "John Smith <john@example.com>" imported
gpg: Total number processed: 2
gpg: imported: 2
⚠ Trusting Keys Automatically
Only trust keys that you have verified out-of-band. Automatically trusting all keys in a repo can lead to accepting malicious signatures.
📊 Production Insight
We had a CI pipeline that imported keys from a repo. An attacker added a malicious key and signed a commit. Now we pin keys by fingerprint and verify them in a secure vault.
🎯 Key Takeaway
Automate public key distribution via keyservers or a repository directory, but verify trust manually.
● Production incidentPOST-MORTEMseverity: high

Impersonated Commit Almost Deployed Malicious Code

Symptom
A contributor with push access to a popular open-source library changed their local git config to impersonate the project lead. They pushed a commit that appeared to be from the lead maintainer. The malicious commit injected a crypto-miner into the build. GPG signing would have blocked it.
Assumption
The CI system checked 'author' field matching the committer — but the author field is self-reported. There was no cryptographic verification.
Root cause
1. Attacker had push access to the repository. 2. Attacker ran git config user.name 'Lead Maintainer' && git config user.email 'lead@project.com'. 3. Attacker created a commit that introduced malicious code. 4. The commit appeared in git log as authored by the lead maintainer. 5. Code review missed the malicious code (it was buried in a large diff). 6. The commit was merged and triggered a CI build. 7. Only a team member noticing the odd commit time prevented the deploy.
Fix
1. Reverted the malicious commit. 2. Rotated all commit access tokens and SSH keys. 3. Implemented GPG signing requirement: GitHub branch protection rule 'Require signed commits'. 4. Created a pre-receive hook that rejects unsigned commits: git log --format='%G?' -1 | grep -q 'G' 5. Added a CI check: git log --format='%G?' --all | grep -v 'G' | wc -l must be 0.
Key lesson
  • Git author/committer fields are self-reported and can be faked.
  • GPG signing is the ONLY way to cryptographically verify identity.
  • Enable signed commit requirements in branch protection rules.
  • Add CI checks that reject unsigned commits.
Production debug guideUse this when production is on fire3 entries
Symptom · 01
I want to start signing commits
Fix
Generate a GPG key, add to GitHub, set commit.gpgsign true
Symptom · 02
I want to sign all past commits
Fix
Use git rebase --exec 'git commit --amend --no-edit -S' to retroactively sign (rewrites history)
Symptom · 03
I need to enforce signing for my team
Fix
Use GitHub branch protection 'Require signed commits' or a pre-receive hook
⚙ Quick Reference
12 commands from this guide
FileCommand / CodePurpose
check-git-config.shgit config --global user.signingkey || echo "No signing key set"Why GPG Signing Matters in Production
generate-gpg-key.shgpg --full-generate-keyGenerating a GPG Key Pair
configure-git-signing.shgit config --global user.signingkey 1A2B3C4D5E6F7G8HConfiguring Git to Sign Commits
sign-commit.shgit commit -m "Fix critical bug in auth module"Signing Commits and Tags
conditional-git-config.sh[includeIf "gitdir:~/work/"]Managing Multiple GPG Keys
pre-receive-hook.shwhile read oldrev newrev refname; doEnforcing Signed Commits in CI/CD
fix-gpg-issues.shgpg-agent --daemonTroubleshooting Common GPG Issues
revoke-key.shgpg --gen-revoke 1A2B3C4D5E6F7G8H > revoke.ascRevoking and Rotating GPG Keys
upload-key.shgpg --armor --export 1A2B3C4D5E6F7G8H > public.ascIntegrating GPG with Git Hosting Platforms
audit-signatures.shfor commit in $(git rev-list HEAD); doAuditing Signed Commits in Production
setup-yubikey.shgpg --card-statusAdvanced
import-team-keys.shfor keyfile in keys/*.asc; doAutomating GPG Key Distribution

Key takeaways

1
Git author/committer fields are self-reported and can be impersonated
2
GPG signing provides cryptographic identity verification
3
Use commit.gpgsign true to auto-sign every commit
4
Enforce signed commits via branch protection rules or pre-receive hooks
FAQ · 6 QUESTIONS

Frequently Asked Questions

01
What is the difference between GPG signing and SSH signing?
02
Can I use the same GPG key for multiple Git hosting platforms?
03
How do I handle GPG signing in a CI/CD pipeline without a passphrase?
04
What happens if my GPG key expires?
05
How do I re-sign old commits with a new GPG key?
06
Can I enforce GPG signing on a self-hosted Git server?
N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Written from production experience, not tutorials.

Follow
Verified
production tested
July 12, 2026
last updated
2,406
articles · all by Naren
🔥

That's Git. Mark it forged?

5 min read · try the examples if you haven't

Previous
Git Merge Strategies: Recursive, Ours, Theirs and Octopus
32 / 47 · Git
Next
Git LFS: Large File Storage for Git Repositories