Signing commits on Windows and WSL Jump to heading
On a Windows workstation there are often three Gits: Git for Windows, the Git inside each WSL distribution, and whichever one the editor decided to call. Each has its own configuration, its own idea of where ssh-keygen or gpg lives, and its own agent. Signing works perfectly in one terminal and fails in the editorโs commit box, or prompts for a passphrase on every commit in WSL while Windows never asks. The fix is not more configuration on each side; it is choosing one agent that holds the key and making every Git talk to it. This page does that for SSH and GPG signing, within the GPG vs SSH commit signing topic.
When to use this approach Jump to heading
- You commit from both Windows and a WSL distribution on the same machine.
- Signing works in one place but fails, or prompts constantly, in another.
- Your editor runs on Windows but opens repositories that live inside WSL, or the reverse.
- You want the private key in one place โ ideally the Windows side, where the OpenSSH agent or a password manager agent already runs.
- On a Linux or macOS machine the plain setup in setting up SSH commit signing from scratch is enough.
Step 1 โ Find out which Git each tool is using Jump to heading
Before changing anything, list the Gits involved and where each reads its configuration. Most โsigning works here but not thereโ reports are two different configuration files.
# In WSL
which git && git --version && git config --show-origin --get user.signingKey # In PowerShell
Get-Command git | Select-Object Source
git config --show-origin --get user.signingKey Step 2 โ Hold the SSH key in the Windows OpenSSH agent Jump to heading
Windows ships an OpenSSH agent service. Enable it, load the signing key into it once, and the key is available to every Windows process without a prompt.
# Run once in an elevated PowerShell
Get-Service ssh-agent | Set-Service -StartupType Automatic
Start-Service ssh-agent
ssh-add $env:USERPROFILE\.ssh\id_ed25519_signing
ssh-add -l Configure Git for Windows to sign with SSH using the Windows ssh-keygen, so it reaches the same agent.
git config --global gpg.format ssh
git config --global user.signingKey "$env:USERPROFILE\.ssh\id_ed25519_signing.pub"
git config --global gpg.ssh.program "C:/Windows/System32/OpenSSH/ssh-keygen.exe"
git config --global commit.gpgSign true # Verification: a commit from PowerShell is signed without a prompt
git commit --allow-empty -m "windows signing test"
git log -1 --format='%G? %GS' Step 3 โ Let WSL sign through the Windows agent Jump to heading
WSL processes cannot reach the Windows agentโs named pipe directly. The simplest bridge is to have WSL Git call the Windows ssh-keygen.exe for signing โ WSL can run Windows executables, and that binary talks to the Windows agent.
# In WSL
git config --global gpg.format ssh
git config --global gpg.ssh.program /mnt/c/Windows/System32/OpenSSH/ssh-keygen.exe
# The key path must be readable by the Windows binary, so use the Windows-side file
git config --global user.signingKey "$(wslpath -w "/mnt/c/Users/$WINUSER/.ssh/id_ed25519_signing.pub")"
git config --global commit.gpgSign true Replace $WINUSER with your Windows user name. The wslpath -w call converts the path to the form the Windows binary expects.
# Verification: commit inside WSL, no passphrase prompt, good signature
git commit --allow-empty -m "wsl signing test"
git log -1 --format='%G? %GS' Local verification inside WSL still needs an allowed signers file on the Linux side, because verification runs ssh-keygen too. Point gpg.ssh.allowedSignersFile at a Linux path or at the Windows file through /mnt/c.
Step 4 โ If you use GPG, share one gpg-agent Jump to heading
GPG works the same way in principle: run the agent on one side and forward to it. Gpg4win on Windows provides the agent; WSL Git calls the Windows gpg.exe directly.
# In WSL, use the Windows gpg so the Windows agent and pinentry handle the key
git config --global gpg.format openpgp
git config --global gpg.program "/mnt/c/Program Files (x86)/GnuPG/bin/gpg.exe"
git config --global user.signingKey 0x1122334455667788! # Verification: the Windows gpg sees the secret subkey
"/mnt/c/Program Files (x86)/GnuPG/bin/gpg.exe" --list-secret-keys --keyid-format long Mixing a Linux gpg in WSL with a Windows keyring does not work: the two have separate home directories and separate agents, and keeping two keyrings in sync is exactly the problem this page avoids.
Step 5 โ Make the editor use a Git that is configured Jump to heading
Editors running on Windows use Git for Windows for repositories on the Windows filesystem. Editors connected to WSL through a remote extension run WSL Git inside the distribution. Both are now configured, but check that the editor is not pointing at a third, bundled Git.
# A git wrapper that logs which binary ran โ temporarily put it first on PATH to find out
printf '#!/bin/sh\necho "$0 $*" >> /tmp/git-calls.log\nexec /usr/bin/git "$@"\n' > ~/bin/git
chmod +x ~/bin/git Remove the wrapper once you know the answer. If the editor turns out to use a bundled Git, point its Git path setting at the system Git rather than configuring a third copy.
Validation checklist Jump to heading
Frequently Asked Questions Jump to heading
Is it slower to call a Windows binary from WSL? Jump to heading
Slightly โ starting a Windows process from WSL adds a few tens of milliseconds. For signing, which happens once per commit, that is not noticeable. It would matter for a hot loop, which signing is not.
Can I keep the key inside WSL instead? Jump to heading
Yes: run ssh-agent inside WSL and configure Git for Windows to call WSLโs binary instead. It works, but Windows tools then depend on WSL being running. Keeping the key on the Windows side is usually more robust because the Windows agent is a service that starts with the machine.
Why does signing fail only when committing from the editor? Jump to heading
The editor is probably launching Git without the environment your shell sets up โ no GPG_TTY, no agent socket, or a different PATH. Configuring signing through gpg.ssh.program or gpg.program with absolute paths removes the dependency on environment variables.
Related Jump to heading
- GPG vs SSH Commit Signing โ the parent topic.
- Troubleshooting โgpg failed to sign the dataโ โ the error you are most likely to see along the way.
- Keeping SSH Signing Keys in an OS Keychain Agent โ agents beyond the built-in Windows one.
- Bootstrapping a Developer Machine for Git โ scripting this setup for new starters.