# Setup GPG signing for git commits on Windows

**Date:** 2024-03-04  
**Author:** Kees C. Bakker  
**Categories:** Installation Notes, Windows  
**Tags:** Git  
**Original:** https://keestalkstech.com/setup-gpg-signing-on-windows/

![Setup GPG signing for git commits on Windows](https://keestalkstech.com/wp-content/uploads/2024/03/thisisengineering-raeng-fzaXcu7H4-unsplash.jpg)

---

Let's setup git commit verification using [GPG](https://www.wikiwand.com/en/GNU_Privacy_Guard) on Windows. This will prompt us to sign the commit. I will be using a [passphrase](https://www.wikiwand.com/en/Passphrase) instead of signing the commits with my SSH token. This gives an extra layer of security to the setup.

![A Visual Studio Code windows wit some code and a terminal triggering a git commit. A screen has popped up allowing the user to sign the commit using the passphrase.](https://keestalkstech.com/wp-content/uploads/2024/03/screenshot-gpg-signing-on-windows-1.png)
*Showing the GPG signing Windows when a commit is created.*

Signed commits will show the *green verified* label in GitHub:

![A list of commits on a repository on GitHub, showing the label of each commit, the user and the time on the left side. On the right side of each commit there is a green verified label, the commit hash and a copy and browse button.](https://keestalkstech.com/wp-content/uploads/2024/03/image-1.png)
*Showing the green verified label on commits that were signed.*

## What does GPG mean?

**G**NU **P**rivacy **G**uard, or GPG, helps with signing messages:

> GPG is a collection of tools that allow signing and encrypting of data using asymmetric cryptography (with public / private keys). Git uses GPG to sign and verify commits and tags. With such a signature, you can easily verify that a commit (or tag) was *really* made by a specific user.
>
> — *git-tower.com*

If you check one of the previous screenshots you'll notice the term OpenPGP, which stands for Open **P**retty **G**ood **P**rivacy. GPG is an implementation of OpenPGP:

> One of the original implementations of PGP, also called PGP, was fully owned by the PGP Corporation. The latter is now owned by Symantec, which in turn is a part of Broadcom.
> 
> However, OpenPGP is now an international standard as defined in the latest RFC 4880 – OpenPGP Message Format.
> 
> […]
> 
> On top of the standard and optional OpenPGP featureset, GPG provides several improvements: versatile key management system, frontend applications and libraries, and fully ported to Microsoft Windows as Gpg4win.
>
> — *Baeldung*

## Step 1: Gpg4win installation

We'll be using Gpg4win. You can install [Gpg4win by downloading it](https://www.gpg4win.org/), or do the install with Chocolatey from an **elevated** PowerShell:

```powershell
choco install gpg4win
```

## Step 2: generate GPG key

The following steps will guide you thought the UI to create a new GPG key:

1. Start *Kleopatra*
2. Click the *New Key Pair* button
3. Enter your *Name* and *Email address*. Tick the *Protect the generated key with a passphrase* box.
4. Optional: disable valid until by clicking the *Advanced Settings...* and untick the *Valid until* box. Click *OK*.
5. Click *OK* again.
6. Enter your passphrase.
7. Done.

## Step 3: add GPG key to GitHub

First, we'll export the key to the clipboard:

```powershell
# get the GPG key
$key=$(
  gpg --list-secret-keys --keyid-format LONG `
  | Select-String -Pattern "ed25519/([^ ]+)" `
  | ForEach-Object { $_.Matches.Groups[1].Value } `
)
 
# export key
gpg --armor --export "$key" | Set-Clipboard; `
echo "Key exported to clipboard"
```

Now we can add it to our GitHub profile:

1. Open your keys in your profile on GitHub: [https://github.com/settings/profile](http://github.com/settings/keys)
2. Click the *New GPG Key* button.
3. Enter a *Title* for the paste the clipboard into the Key field.
4. Click *Add GPG Key*.

GitHub will now understand your signed commits.

### Local git configuration

Now, let's configure the local git with the following PowerShell script:

```powershell
# get the GPG key
$key=$(
  gpg --list-secret-keys --keyid-format LONG `
  | Select-String -Pattern "ed25519/([^ ]+)" `
  | ForEach-Object { $_.Matches.Groups[1].Value }
)

# get the location of gpg
$program=$(Get-Command gpg).Source

# config git
git config --global commit.gpgsign true
git config --global user.signingkey "$key"
git config --global gpg.program "$program"
```

Your commits on your dev box should now be signed with the private key you just created.

## Step 4: start GPG agent at logon

I don't know why, but sometimes my GPG agent is not running. So I added a small startup script that triggers the loading of the agent.

```powershell
& {
    $TaskName = "Start GPG"
    $CurrentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name

    # Check if the task already exists
    if (Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue) {
        Write-Output "Task '$TaskName' already exists. Deleting it first..."
        Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false
    }

    # Define the action, trigger, and settings
    $Action = New-ScheduledTaskAction `
        -Execute 'PowerShell.exe' `
        -Argument "-NoProfile -WindowStyle Hidden -Command `"echo 'Ensure GPG...'; gpg-connect-agent reloadagent /bye; sleep 5;`""

    $Trigger = New-ScheduledTaskTrigger -AtLogOn -User $CurrentUser
    $Settings = New-ScheduledTaskSettingsSet `
        -AllowStartIfOnBatteries `
        -DontStopIfGoingOnBatteries `
        -StartWhenAvailable

    # Register the new task
    Register-ScheduledTask `
        -Action $Action `
        -Trigger $Trigger `
        -TaskName $TaskName `
        -Description "Ensures GPG agent is reloaded at user logon." `
        -Settings $Settings

    Write-Output ""
    Write-Output "Task '$TaskName' created successfully."
}
```

When the agent is not loaded, you'll be waiting for that popup for a long time before it times out.

## Bonus: Visual Studio Code GPG signing

To enable GPG signing in Visual Studio Code, you'll need to set `git.enableCommitSigning` to true:

1. Press *F1* to open up the all commands view.
2. Input *>Preferences: Open Settings (UI)*.
3. Search *git.enableCommitSigning*.
4. Enable the *Git: Enable Commit Signing* to enable the commit signing.

## Bonus: Dev Containers

The latest version of Gpg4win will not work with Dev Containers, because they've switched keyrings ([more info here](https://stackoverflow.com/a/77519131/201482)). The solution is to migrate back to the "old" keychain with the following command:

```
gpg-disable-keyboxd
```

When you get the error "error: cannot run C:\Program Files (x86)\Gpg4win..\GnuPG\bin\gpg.exe: No such file or directory", you can solve this by overwriting the GPG program in your container:

```sh
# config local GPG for signing
# fixes:
# - error: cannot run C:\Program Files (x86)\Gpg4win..\GnuPG\bin\gpg.exe: No such file or directory.
git config --global gpg.program gpg
```

More information on [the startup script and dev container can be found here](https://keestalkstech.com/2023/06/github-windows-ssh-gpg-devcontainer/#startup-script).

## Changelog

- 2024-12-29: Make the task start regardless if the laptop is on batteries or not.
- 2024-10-31: Added steps as headings.
- 2024-03-20: Added a fix for the new Gpg4win keyring causing Dev Containers not to work.
- 2024-03-04: Initial article.
