Signing Git commits in NeoVim
While all commits to GitHub through the web interface are automatically signed, you have to do some configuration to make it work in the console.
Signing Git commits might be a requirement for your job, OpenSource maintainers might only accept signed contributions or you might just want to increase the security of your workflow.
I couldn’t find any existing article on how to set up signing commits in the NeoVim, so I’ll share my findings in this post.
Create a new GPG key and attach it to your Github account.
As the first step, you have to generate a new GPG key. This is greatly described in the Generating a GPG key article.
Make sure that you’re using the correct email and that you won’t forget the password.
Once this is done, Add a new GPG key as per the article.
Configure Git to sign commits
Next step is to amend your .gitconfig
so that every commit is signed:
[user]
; Make sure that email matches one in the GPG key
email = personal_email@gmail.com
name = Sergei Bulavintsev
; GPG key ID
signingkey = 7C43420F61CECAAA
[commit]
gpgsign = true
Now you will be prompted to enter the GPG password when you’ll try to commit anything in the terminal. To avoid typing the password every time, it is cashed via GPG agent.
Configure GPG to work with NeoVim
To make NeoVim ask for your GPG password, we need to set pinentry mode to
loopback
, as per documentation:
GPGME_PINENTRY_MODE_LOOPBACK
SINCE: 1.4.0
Redirect Pinentry queries to the caller. This enables the use of gpgme_set_passphrase_cb because pinentry queries are redirected to gpgme.
To do this, edit .gnupg/gpg-agent.conf
:
default-cache-ttl 28800
max-cache-ttl 28800
allow-loopback-pinentry
And .gnupg/gpg.conf
:
use-agent
pinentry-mode loopback
Now reload the agent:
gpgconf --reload gpg-agent
If you’ve configured everything correctly, you’ll see Enter passphrase
in the NeoVim:
This approach works with any Git plugin, such as Fugitive or LazyGit. By using cache with TTL 28800, the password has to be entered only once per day.
To check that your commit has been signed correctly:
git log --show-signature
You should see something like this:
Trust GitHub public keys
When you use GitHub web interface, it will automatically sign your
commits using user web-flow. In the web interface,
you’ll see all your commits as signed and verified. However, while
checking commits with --show-signature
flag, web commits will not be checked:
To fix this, import GPG key of the user web-flow
(kudos to Stack Overflow):
$ curl https://github.com/web-flow.gpg | gpg --import
$ gpg --edit-key noreply@github.com
gpg> trust
gpg> save
$ gpg --lsign-key noreply@github.com
After importing the key:
Signing commits for multiple emails
If you use the same GitHub account for both personal purposes(for example, OpenSource contributions) and for work, you might want to use different emails and GPG keys for this.
To do this:
- Generate another GPG key using your another email address
- Add new email to your GitHub Account
- Add new GPG key to your GitHub Account
Now comes the tricky part, automatically determine which GPG key to use for signing commits.
I’ve found the following solution(not considering using the local .gitconfig
for each repository:
- Git allows to do Conditional includes
in your
.gitconfig
based on the git path or origin. - Each included file can override your
user.email
anduser.signingkey
settings.
For example:
[user]
; Use this email by default
email = personal_email@gmail.com
name = Sergei Bulavintsev
signingkey = 7C43420F61CECAAA
[commit] gpgsign = true
; Override default settings if we are in the git_work folder
[includeIf "gitdir:~/git_work/"]
path = .gitconfig-work
; Override default settings if git origin contains my username
[includeIf "hasconfig:remote.*.url:*sbulav/*"]
path = .gitconfig-sbulav
And the included file .gitconfig_work
might look like:
[user]
email = work_email@organization.com
signingKey = A54F12F0D4D73FAA
For each GPG key you’ll have to enter corresponding password.
Comments