Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Automatic Git commit signing with GPG on OSX
# In order for gpg to find gpg-agent, gpg-agent must be running, and there must be an env
# variable pointing GPG to the gpg-agent socket. This little script, which must be sourced
# in your shell's init script (ie, .bash_profile, .zshrc, whatever), will either start
# gpg-agent or set up the GPG_AGENT_INFO variable if it's already running.
# Add the following to your shell init to set up gpg-agent automatically for every shell
if [ -f ~/.gnupg/.gpg-agent-info ] && [ -n "$(pgrep gpg-agent)" ]; then
source ~/.gnupg/.gpg-agent-info
export GPG_AGENT_INFO
else
eval $(gpg-agent --daemon --write-env-file ~/.gnupg/.gpg-agent-info)
fi
# Enables GPG to find gpg-agent
use-standard-socket
# Connects gpg-agent to the OSX keychain via the brew-installed
# pinentry program from GPGtools. This is the OSX 'magic sauce',
# allowing the gpg key's passphrase to be stored in the login
# keychain, enabling automatic key signing.
pinentry-program /usr/local/bin/pinentry-mac
# Uncomment within config (or add this line)
use-agent
# This silences the "you need a passphrase" message once the passphrase handling is all set.
# Use at your own discretion - may prevent the successful interactive use of some operations.
# It is working fine for my use cases though.
batch
# A quick outline of what must be done to get everything working.
# 1) Install the dependencies.
brew install gnupg gpg-agent pinentry-mac
# 2) Configure git to automatically gpgsign commits. This consists of
# pointing git to your signing key ID, and then enabling commit
# automatic signing.
git config --global user.signingkey <YOUR-SIGNING-KEY-PUB-ID>
git config --global commit.gpgsign true
# 3) Configure the GPG components (see above for relevant examples):
# ~/.gnupg/gpg.conf
# ~/.gnupg/gpg-agent.conf
# 4) Start the daemon and configure your shell (see above for example in .profile).
# ~/.bash_profile | ~/.zshrc
# Don't forget to upload your public key to Github!
# https://github.com/blog/2144-gpg-signature-verification
# Note: There needs to be a three-way match on your email for Github to show
# the commit as 'verified': The commit email, github email, & the email associated with the public key
# Learn about creating a GPG key and the knowledge behind these commands here:
# https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work
@bmhatfield

This comment has been minimized.

Copy link
Owner Author

commented Apr 6, 2016

The high level "connection diagram" for each part:

git -> gpg -> shell/env variable -> gpg-agent -> pinentry -> keychain
@jdowning

This comment has been minimized.

Copy link

commented Apr 6, 2016

Thanks for posting this! Two small suggestions/changes:

  1. I use Boxen, so Homebrew is installed in a different location. For ~/.gnupg/gpg-agent.conf I was able to use pinentry-program $HOMEBREW_ROOT/bin/pinentry-mac making the config more portable.
  2. I had to amend the gpg-agent command on startup: eval $(gpg-agent --daemon --options ~/.gnupg/gpg-agent.conf --write-env-file ~/.gnupg/.gpg-agent-info)
@bcomnes

This comment has been minimized.

Copy link

commented Apr 6, 2016

Why do you use gpg instead of gpg2 or gnupg21? It comes with gpg-agent, pinentry as deps.

EDIT: My bad, pinentry-mac is does not come with the pinentry package.

@bcomnes

This comment has been minimized.

Copy link

commented Apr 6, 2016

I came up with a slightly different recipe, using the latest version of gpg (2.1) and slightly less bash glue around the agent. https://gist.github.com/bcomnes/647477a3a143774069755d672cb395ca Thanks for the writeup! It was helpful :)

@bmhatfield

This comment has been minimized.

Copy link
Owner Author

commented Apr 7, 2016

@bcomnes - no particular reason on the gnupg choice. Just what I was used to. Thanks for sharing your workflow! Really the goal here is to highlight the pieces folks might need, so they can adapt them to their relevant approach.

@rpereira

This comment has been minimized.

Copy link

commented Apr 8, 2016

@bmhatfield I've used this and it keeps me asking for the passphrase on every commit.

@bmhatfield

This comment has been minimized.

Copy link
Owner Author

commented Apr 16, 2016

@ruiafonsopereira - sorry to hear that. The goal of this was more to try to give you all the pieces you needed to make this work, since it took me a little while to find them - you may have to adapt to your local environment. I wrote comments in each file with the intent of highlighting areas where you might do that. Some ideas I had to help troubleshoot: the .profile might not be sourced, or perhaps you didn't check "save in keychain" in the pinentry program, or perhaps gpg is installed in a way that it's looking for a different path, etc. Good luck!

@davisonio

This comment has been minimized.

Copy link

commented Jun 18, 2016

Thank you!

@danieleggert

This comment has been minimized.

Copy link

commented Jul 14, 2016

You can do all of this without any of this glue: https://gist.github.com/danieleggert/b029d44d4a54b328c0bac65d46ba4c65

@lenage

This comment has been minimized.

Copy link

commented Aug 1, 2016

Thanks @danieleggert , it works like charm! 😄

@ankurk91

This comment has been minimized.

@takutaku947

This comment has been minimized.

Copy link

commented Oct 8, 2016

I countered this error on your config:
"Inappropriate ioctl for device"
Solution:
Write "export GPG_TTY=$(tty)" in ~/.profile and restart.

@pustovalov

This comment has been minimized.

Copy link

commented Oct 23, 2016

Thx

@PurpleBooth

This comment has been minimized.

Copy link

commented Dec 6, 2016

Thanks! This is fantastic.

@aforty

This comment has been minimized.

Copy link

commented Dec 11, 2016

This is fantastic, thank you!

@loustler

This comment has been minimized.

Copy link

commented Jan 26, 2017

Thanks guys.

I spent so many time to find solution for solve my problem.

Your solution is very fantastic.

@Necmttn

This comment has been minimized.

Copy link

commented Mar 11, 2017

THANK YOU !

@lumeng

This comment has been minimized.

Copy link

commented Mar 27, 2017

I was wondering that given that the gpg installed by Homebrew on macOS has switched to gpg2 which has some potentially important differences from gpg1, any of the above configuration can be updated and/or simplified?

@abrkn

This comment has been minimized.

Copy link

commented Apr 26, 2017

Worked like a charm!

@loustler

This comment has been minimized.

Copy link

commented Apr 28, 2017

If you use gpg 2.1 or above, then cannot use --write-env-file.

See here

@swernerx

This comment has been minimized.

Copy link

commented May 7, 2017

I think we don't even need to start gpg-agent anymore - at least not together with pinentry-mac ... works flawlessly without in my setup with gpg v2 (includes gpg-agent) + pinentry-mac (installed via homebrew).

@jakeNiemiec

This comment has been minimized.

Copy link

commented Jul 26, 2017

@swernerx perhaps you could elaborate?

@ewanmellor

This comment has been minimized.

Copy link

commented Aug 2, 2017

@jakeNiemiec Echoing the comment from @swernerx:

I have pinentry-mac 0.9.4 and gnupg / gpg-agent 2.1.22 from Homebrew, and I don't need to start gpg-agent manually; pinentry-mac does it for me the first time I try to sign something. This means that I do not need use-standard-socket in .gpg-agent.conf or the .profile changes above. Also, use-agent doesn't do anything any more (GPG Configuration Options).

All I needed was:

  • brew install gnupg gpg-agent pinentry-mac (same as above)
  • pinentry-program /usr/local/bin/pinentry-mac in ~/.gnupg/gpg-agent.conf
  • The git config commands above.
@jannik-mohemian

This comment has been minimized.

Copy link

commented Nov 16, 2017

Amazing gist! ❤️

Quick tip for oh-my-zshell users:

Simply add gpg-agent to your plugins and skip the whole .profile part.

@sarkis

This comment has been minimized.

Copy link

commented May 1, 2018

@ewanmellor thanks for the more concise directions.. I'll add that you only need brew install gnupg pinentry-mac - gnupg 2.x+ comes with gpg-agent and actually if you just install gpg-agent from homebrew it defaults to keg only (not linking in /usr/local). Hope that helps someone else!

@ghost

This comment has been minimized.

Copy link

commented Jul 4, 2018

For those who hit the error gpg: Sorry, no terminal at all requested - can't get input I've left a solution for you on Stack.

@nhooyr

This comment has been minimized.

Copy link

commented Aug 14, 2018

From https://gist.github.com/danieleggert/b029d44d4a54b328c0bac65d46ba4c65

If you want annotated tags to be GPG signed:

git config --global tag.forceSignAnnotated true
@dade80vr

This comment has been minimized.

Copy link

commented Sep 16, 2018

Thanks. But, how can use it with Fish shell?
Fish setup is located in .config/fish/config.fish but does not support .profile (bash) syntax.

@AlterwebStudio

This comment has been minimized.

Copy link

commented Sep 20, 2018

brew install gnupg pinentry-mac

Thanks, is it necessery to do anything este after install of pinetry? Config git or set GPG sign? I still have errors with commiting:
error: gpg failed to sign the data
fatal: failed to write commit object

@jhenahan

This comment has been minimized.

Copy link

commented Oct 2, 2018

For anyone else running into issues (especially if you use fish), make sure that the env variable GNUPGHOME is set to your GPG config directory and that this environment variable is visible to Emacs. For instance, I use exec-path-from-shell to copy that variable so that Emacs knows about it.

@brunophilipe

This comment has been minimized.

Copy link

commented Dec 26, 2018

If you are having issues after trying a bunch of different things, make sure to restart the gpg-agent daemon. It only reads new configurations on startup. Just run killall gpg-agent. No need to start it up manually. Once you try to sign something it will start-up the agent automatically.

@shusson

This comment has been minimized.

Copy link

commented Jan 29, 2019

If you are having issues after trying a bunch of different things, make sure to restart the gpg-agent daemon. It only reads new configurations on startup. Just run killall gpg-agent. No need to start it up manually. Once you try to sign something it will start-up the agent automatically.

👍 this solved it for me

@atejeda

This comment has been minimized.

Copy link

commented Feb 28, 2019

For those who are debugging why gpg failed to sign the data:
echo "test" | gpg --clearsign

@t89

This comment has been minimized.

Copy link

commented Mar 20, 2019

Thank you for the guidance. For the changes to take effect I had to also restart the gpg-agent by typing gpgconf --kill gpg-agent into the shell.

@alvivi

This comment has been minimized.

Copy link

commented Oct 8, 2019

The gpg-agent formula is not needed anymore: https://stackoverflow.com/a/52456873/560382

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.