Signing Git Commits
I’ve come across the idea of signing Git commits before, but I never bothered to use them until I happened upon Horst Gutmann’s guide today and thought, well, I should probably do that.
I use the official distribution of Git on Windows, which includes
GPG. Instead of ~/.gnupg, I wanted to save my keys in a
directory of my choosing, so I set the GNUPGHOME
environment
variable. Since
the tools bundled with Git on Windows run under Cygwin, they can’t parse
C:\Path\To\Directory, which meant I had to use the /c/Path/To/Directory format.
Because I have several identities across multiple repository hosting services, I couldn’t create a
single GPG key to sign everything with. I instead created one per identity and registered
them with their respective hosting services. I always use a PowerShell alias I wrote to set up a
freshly-cloned repository with the required information, so I extended it to set the signing key
accordingly and enable
commit.gpgsign
for the repository, to automatically sign all new commits.
Existing commits are another matter, as signing the commit changes its identity and all its descendants are affected. There are therefore three categories:
- Commits that only exist locally or in pull requests (or equivalent). Modifying these won’t affect published history.
- Commits published to repositories which only I use. Modifying the history of the repository is acceptable.
- Commits published to repositories where I’m not the only user. These must not change.
To add a signature to existing commits, you need to rebase and amend every single
one, which is slow,
error-prone, and tedious. Instead, after some searching, I combined suggestions from multiple
sources to arrive at the incantation of git rebase --root --exec 'git commit --amend --no-edit -n
-S' -i master (automatically sign every single commit reachable from the master
branch in
sequence, going all the way back to the first commit). You must force-push the new history
afterwards.
I gave it a try on this site’s repository. Git merrily rewrote history one revision at a time without complaint, but 20 minutes later, when I gave the command to force-push over 1,000 signed commits, a dialog popped up asking me to authenticate with a Netlify site, presumably because I use Netlify Large Media. I abandoned the idea.[1] Of course, the reflog meticulously recorded every alteration, allowing me to undo all my signing and even restore the three unpublished commits I had only remembered midway through the rebase with a simple git checkout HEAD@{1049}.
- I’ll just have to trust that it was I who made all the previous commits.↩