Sign Your Git Commits with GPG or SSH

Khimananda Oli 8 min read Virtualization
Sign Your Git Commits with GPG or SSH

By Khimananda Oli | Last reviewed: August 2026

If you cannot cryptographically prove who wrote a line of code, your repository is vulnerable to impersonation and supply chain attacks. Learning to sign your Git commits with GPG or SSH is the definitive way to bind identity to history, ensuring that every change in your audit trail is authentic. This practice is no longer optional for teams pursuing SOC 2 or ISO 27001 compliance; it is a fundamental control for shifting security left and establishing trust in your software delivery lifecycle.

Developer Localgit commit -SPrivate Key SignsCommit Hash + MetadataGit RemoteGitHub / GitLabStores SignatureDisplays "Verified"Auditor / CIFetches Public KeyVerifies SignatureRejects UnsignedCryptographic Chain of Trust: Private Key Signs → Public Key Verifies
End-to-end flow when you sign your Git commits with GPG or SSH keys

How do you generate and configure keys to sign your Git commits with GPG or SSH?

The first step in securing your commit history is generating a dedicated cryptographic key. While GPG has been the standard for decades, SSH signing (available since Git 2.34) offers a streamlined alternative that reuses existing authentication infrastructure. Both methods achieve the same goal: binding your identity to a specific commit object via a digital signature.

Generating an SSH Key for Signing

SSH signing is generally recommended for new setups in 2026 due to lower friction. You should use the Ed25519 algorithm for its superior performance and security profile compared to RSA.

ssh-keygen -t ed25519 -C "[email protected]" -f ~/.ssh/git_signing_key

After generation, copy the public key to your clipboard and add it to your Git provider's "Signing Keys" section (distinct from authentication keys on some platforms).

cat ~/.ssh/git_signing_key.pub | pbcopy # macOS
# or
cat ~/.ssh/git_signing_key.pub | xclip -selection clipboard # Linux

Generating a GPG Key for Signing

If your organization requires GPG for compliance evidence collection, generate a modern RSA-4096 or ECC key. Avoid SHA-1; ensure your digest algorithm is SHA-512.

gpg --full-generate-key
# Select: (1) RSA and RSA
# Key size: 4096
# Validity: 2y (rotate annually)
# Name/Email: Match your git config exactly

Export the ASCII-armored public key for upload:

gpg --armor --export [email protected] > my_gpg_public.asc

Configuring Git Globally

Once your key exists locally and remotely, tell Git to use it. Consistency between your user.email and the key's email is mandatory; mismatches result in unverified badges even if the signature is cryptographically valid.

  • For SSH: Set format to ssh, specify the signing key path, and enable auto-signing.
  • For GPG: Set format to openpgp, provide the key ID, and configure the gpg program path if non-standard.
# SSH Configuration
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/git_signing_key
git config --global commit.gpgsign true

# GPG Configuration
git config --global gpg.format openpgp
git config --global user.signingkey YOUR_GPG_KEY_ID
git config --global commit.gpgsign true

GPG vs SSH signing: which method should you choose for commit verification?

Choosing between GPG and SSH depends on your team's maturity, tooling ecosystem, and compliance obligations. There is no universal "best," only the right trade-off for your context. In my experience helping Nepal-based outsourcing firms align with global clients, SSH adoption has accelerated significantly since 2024 because it eliminates the separate key management overhead that often causes developer friction.

CriteriaSSH SigningGPG Signing
Setup ComplexityLow (reuses existing keys)High (separate keyring, agents)
Algorithm SupportEd25519, RSA, ECDSARSA, ECC, DSA (legacy)
Git Version Requirement≥ 2.34.0All versions
Platform SupportGitHub, GitLab, Bitbucket (2026)Universal
Key RotationSimple (add new, revoke old)Complex (web of trust, revocation certs)
Compliance AcceptanceGrowing (check auditor preference)Gold Standard
Tag SigningSupportedSupported

If you are starting fresh or migrating a team that already uses SSH for authentication, choose SSH. It reduces cognitive load and operational toil. Reserve GPG for environments where external auditors explicitly demand OpenPGP artifacts or where you need to integrate with legacy PKI systems. For most DevOps teams practicing supply chain security, SSH provides sufficient cryptographic assurance with significantly less maintenance burden.

Start: Need Signing?Legacy Systems or Strict Audit?YESNOChoose GPGMax CompatibilityOpenPGP StandardChoose SSHLow FrictionEd25519 RecommendedManage Keyring + AgentReuse Auth Infrastructure
Decision framework for selecting GPG or SSH to sign your Git commits

How do you troubleshoot unverified signatures and common signing failures?

A "Unverified" badge on a signed commit usually indicates a configuration mismatch rather than a cryptographic failure. The most frequent cause in my practice is an email address discrepancy. Git matches signatures against the committer email, not just the key owner. If your local user.email differs by capitalization or domain alias from what is registered on the platform, verification fails silently.

Diagnosing Signature Issues Locally

Before pushing, verify your signature locally using git log --show-signature. This outputs the raw GPG/SSH status. Look for "Good signature" and confirm the UID matches your expected identity.

git log --show-signature -1
# Expected output includes:
# gpg: Good signature from "Your Name <[email protected]>"
# or for SSH:
# Good "git" signature for [email protected] with ED25519 key SHA256:...

Fixing Email Mismatches

If signatures fail verification despite being cryptographically valid, audit your email configuration across all layers:

  1. Check git config user.email (local and global).
  2. Verify the email listed in your GPG UID (gpg --list-keys) or SSH key comment.
  3. Confirm the exact email string added to your Git provider's signing keys page.
  4. Ensure no noreply aliases are interfering if you've configured privacy emails.

For GPG specifically, ensure your key hasn't expired. Expired keys produce valid signatures that platforms reject. Extend validity with gpg --edit-key KEY_ID then expire. For SSH, verify you haven't accidentally added the key as an "Authentication Key" instead of a "Signing Key" on platforms that distinguish them.

Handling Passphrase Fatigue

Developers often disable signing because entering passphrases repeatedly breaks flow. Solve this with agent caching, never by removing passphrases. Configure gpg-agent to cache credentials for a reasonable duration (e.g., 4 hours) or use hardware tokens like YubiKey which require physical touch but no passphrase entry. For SSH, ssh-add --apple-use-keychain (macOS) or equivalent keychain integrations provide similar relief.

How do you enforce signed commits in CI pipelines and branch protection?

Signing commits individually is insufficient; you must enforce verification at the gate. Without enforcement, unsigned commits from compromised accounts or careless scripts can pollute your history. Branch protection rules and CI checks transform signing from a personal habit into an organizational control aligned with secure development practices.

Configuring Branch Protection Rules

On GitHub, navigate to Settings → Branches → Add Rule. Enable "Require signed commits." This prevents merging any commit lacking a verified signature. Apply this to main, release/*, and any protected deployment branches. GitLab and Bitbucket offer equivalent controls under repository settings.

Warning: Enable this only after confirming all active contributors have configured signing. Enabling prematurely blocks legitimate work and creates emergency override pressure. Communicate the change window clearly.

CI Pipeline Verification Gates

Branch protection stops merges, but CI should catch issues earlier. Add a pipeline job that validates signatures before running expensive tests. This provides fast feedback and generates audit artifacts.

# Example GitLab CI job for signature verification
verify-signatures:
  stage: validate
  script:
    - git log --format="%H %G?" origin/main..HEAD | grep -v "G$" && exit 1 || echo "All commits verified"
  allow_failure: false

For automated releases, ensure your CI bot also signs commits. Generate a dedicated machine identity (SSH key or GPG key) stored in your secrets manager. Never reuse human keys for automation. Document this machine identity in your compliance evidence to satisfy auditor inquiries about non-human actors.

Developer PushSigned CommitCI Validation GateCheck SignatureVerify IdentityFail Fast if InvalidBranch ProtectionRequire VerifiedBlock Unsigned MergeEnforce PolicyMergeTrustedREJECTEDInvalid / Missing Sig
Enforcement pipeline ensuring only verified signed commits reach production branches

Establishing Trust Through Verified Commit History

Cryptographic commit signing transforms your repository from a mutable ledger into a verifiable chain of custody. Whether you choose SSH for operational simplicity or GPG for compliance alignment, the critical factor is consistent enforcement. Start by configuring your local environment today, then progressively roll out branch protection as your team builds muscle memory. Remember that signing is one layer of defense; combine it with secrets scanning and dependency auditing for comprehensive supply chain security. If you need help designing a compliant Git workflow or auditing your existing signing infrastructure, reach out to discuss your specific requirements.

Frequently Asked Questions

SSH is generally preferred for new setups due to simpler key management and native support in Git 2.34+. GPG remains necessary for legacy systems or specific compliance requirements requiring X.509 certificates.

Set gpg.format to ssh and user.signingkey to your public key path using git config commands. Ensure your OpenSSH version is 8.0 or newer to support the required signing agent functionality properly.

The signing email must match a verified email in your GitHub account settings exactly. Additionally, ensure you uploaded the correct public key to your profile and that the commit author email matches the key identity.

Yes, but security best practices recommend generating a dedicated signing key. Separating authentication and signing limits exposure if one key is compromised and allows distinct expiration policies for each cryptographic purpose.

Git 2.34.0 introduced native SSH signing support. Upgrade via your package manager or compile from source if running older distributions to enable this feature without external wrapper scripts or plugins.

Run git config commit.gpgsign true to enable automatic signing globally or per repository. This appends signatures transparently during commit creation without requiring manual flags or remembering additional command syntax.

Negligibly. Signing adds milliseconds locally. Verification in pipelines depends on volume but typically completes in seconds using cached keys. Bottlenecks usually stem from network latency fetching public keys rather than cryptographic operations themselves.

You cannot retroactively change signatures without rewriting history. Configure SSH signing for future commits while retaining GPG keys for verifying historical commits. Document the transition date in your repository security policy for auditors.

You cannot recover lost private keys. Generate a new key pair, update your Git configuration, and upload the new public key to hosting platforms. Previous commits remain verifiable only if the old public key stays accessible.

No. Both GPG and SSH signing use free open-source tools. Costs only arise if purchasing hardware security tokens like YubiKeys for key storage or enterprise certificate authorities for specialized X.509 compliance requirements.

Use git log --show-signature to display verification status and signer details. Configure git log --format to include signature indicators permanently. Failed verifications indicate missing keys, expired signatures, or potential tampering requiring investigation.

Yes. GitHub, GitLab, and Bitbucket offer branch protection settings requiring verified signatures. Reject unsigned or unverified pushes automatically. Combine with pre-receive hooks for self-hosted instances to maintain consistent signing policies across repositories.

Yes. Each machine performing signed commits needs access to the private key. Use SSH agents with forwarding or hardware tokens to avoid copying private keys between systems while maintaining signing capability across environments.

Check GPG agent status and TTY environment variables. Restart the agent with gpgconf --kill gpg-agent. Verify pinentry program accessibility and ensure no concurrent processes lock the keyring preventing signature generation.

Major platforms including GitHub, GitLab, and Bitbucket support SSH signature verification as of 2026. Self-hosted solutions may require updates. Always verify platform documentation before migrating teams from GPG to ensure full compatibility.