DEV Community

Josef Andersson
Josef Andersson

Posted on • Updated on

Git signoff and signing like a champ

Other Git related articles on DEV from me:
A clean Git history with Git Rebase and Conventional Commits
The "linear-git-commit-history-with-signing-in-github-ui"-workaround

Introduction

Signing and sign-off your Git commits for improved security, contributions assurance and contributor history? What's not to like? Well, Let's jump right in.

Why?: Summarized as short and simple as possible 

  • Git Sign-off is a de facto standard way in the Open Source communities about ensuring to the project you are contributing to that _you _have the right to submit your content. Often together with an note in the projects CONTRIBUTING.md, that you agree to the DCO-standard by doing a sign-off (see the F.A.Q for a short summary of the DCO). Also, Sign-off's helps improving the git history tracking of whom submitted what.
  • Git Signing adds an extra layer of trust regarding your commits.

So, in essence, they are solutions to different problems, to increase your project security, trust, and traceability. It is easy to mix up their names (and their short flags versions -s vs -S:) but they are different concepts. Both have fairly good support in modern versions of Git Services like for example GitLab and GitHub.

Are they cumbersome to configure?: No, as we will see. Configure once and mostly forget about it!

How do they work in practice?: Basically: Sign-off adds an extra comment to your commits - "you sign them off"!
 
Sign-off example :

$ git log


........

feat: add a test for the superservice

Signed-off-by: Heap Stacksson <heap.stacksson@example.com>
Enter fullscreen mode Exit fullscreen mode

Signing then. Well, as you might expect, it signs your commits cryptographically (by gpg- or ssh-key):

Signing example:

$ git log --show-signature 

<commit f3974852488dde8b4cd087d5b5a27817d3358777 (HEAD -> feature/show-sign-example, tag: 300.0.1)
Good "git" signature for heap.stacksson@example.com with ED25519 key SHA256:ABCToTLNtOKINCIuFYusrK+ohNbr5R4V9igTmCqciN4
Author: Heap Stacksson <heap.stacksson@example.com>
Date: Thu Feb 29 04:36:44 2024 +0100
feat: add a test for the superservice

Signed-off-by: Heap Stacksson <heap.stacksson@example.com>
Enter fullscreen mode Exit fullscreen mode

and as mentioned, the common Git services have pretty good support for these methods. Here is an example from GitHub for how signing is implemented visually:

Image description
"GitHub sign verification example", © by GitHub is licensed under CC-BY-SA

Set up Git Sign-off

Add the -s or the --signoff flag to your commits:

$ git commit --signoff -m 'chore: this commit will be signoff:ed'
Enter fullscreen mode Exit fullscreen mode

Set up Git Signing (before Git version 2.34.0, with GPG-key)

If your Git version is less than 2.34.0 (or if you just prefer GPG-signing anyway) you need to supply a gpg-key for signing.

$ git --version
Enter fullscreen mode Exit fullscreen mode

There are many articles on how to generate and add a gpg-key to your hosted Git service, so I will leave that part to you (See, for example GitLab's excellent guide):

Add the -S or the --gpg-sign flag to your commits:

$ git commit --gpg-sign -m 'chore: this will sign your commit'
Enter fullscreen mode Exit fullscreen mode

And for signing tags:

$ git tag -s thetag
Enter fullscreen mode Exit fullscreen mode

Set up Git Signing (Git version 2.34.0++, with ssh-key)

Git introduced signing with ssh-keys from 2.34.0 and upwards. This simplifies life, as you most likely already have a ssh-key for your Git chores, and don't need to keep track of an extra gpg-key.
The ssh feature also needs a fairly modern openssh version,8.8++, and finally, for visual candy, a fairly modern instance of GitLab etc, (cloud GitHub already supports this visually) so that your signatures are visually shown.
Note: Using gpg-keys after Git 2.34.0 is still perfectly fine.

Configure git to use ssh-key for signing instead of gpg:

$ git config --global gpg.format ssh
Enter fullscreen mode Exit fullscreen mode

Give it your public ssh-key, inline or filepath:

$ git config --global user.signingKey 'path/to/yourkey.pub'
Enter fullscreen mode Exit fullscreen mode

SSH has no web-of-trust as gpg has, so you will also need to add an allowedSigners file where you add public signatures you trust, including your own. Otherwise verifying signatures will fail.

$ touch ~/.config/git/allowed_signers
$ git config --global gpg.ssh.allowedSignersFile "$HOME/.config/git/allowed_signers"
Enter fullscreen mode Exit fullscreen mode

Make sure to add your own public ssh-key to this (and your collborators- creating a repo of team public keys for sharing might be a good idea).

Example

$ cat ~/.config/git/allowed_signers

..keys
heap.stacksson@example.com asdfas4949494949adfasfAAAAFASDFASDFSAD9939
Enter fullscreen mode Exit fullscreen mode

Add an Git alias for signoff and signing or configure a global "always sign"

And by using signoff and signing without an alias, you will forget to add them at times:). Therefore, I highly recommend that you add an git alias so that you can mostly forget about this:

$ git config --global alias.cs commit --signoff --gpg-sign
$ git cs -m 'chore: this commit will be signed off and signed even though I forgot to set the flags'
Enter fullscreen mode Exit fullscreen mode

Alternatively, You could also configure the global Git configuration to make it "always sign" instead of an alias for you. This is how you would do it, including "always sign tags".

$ git config --global commit.gpgsign true
$ git config --global tag.gpgsign true
$ git config --global user.signingkey <KEY ID> --see for example https://docs.gitlab.com/ee/user/project/repository/gpg_signed_commits/#create-a-gpg-key
Enter fullscreen mode Exit fullscreen mode

But, you will still need a alias for the signoff feature (a global Git configuration to always signoff is not supported by git).

$ git config --global alias.cs commit --signoff
$ git cs -m 'chore: this commit will be signed-off and signed even though I forgot to set the flags'
Enter fullscreen mode Exit fullscreen mode

F.A.Q

I get an error, "failed to sign commit in my shell"?

You might need to set the GPG_TTY env var

 export GPG_TTY=$TTY
Enter fullscreen mode Exit fullscreen mode

Should I use GPG or SSH-signing?

Both have pro's cons so it is up to you - for example, - ssh-key might be easier to configure (no need for extra gpg-key handling, you might already have an ssh-key setup for git needs), but then you need to share the public ssh keys in the mentioned allowed_signatures, to be able to verify. The sharing part is easily handled if using gpg, by uploading the public key to an public key server.
Also, with ssh, if using older GitLab versions, you are going to miss out on the visual support for this. And it won't work with older git/openssh-combos if you are stuck with old development environments/versions.

My nice verification signature disappeared when merging/squashing etc in GitLab/GitHub GUI?

Depending on your workflow, Git platform/PR-strategy and merge configuration there might be caveats. There are certainly room for improvements here from GitHub, GitLab and others.

Some Links about different takes:
GitHub Discussion about GitHubs Rebase Strategy (a bit broken, GitLabs works better here
General about signing with gpg
How to squash/merge via CLI

How can I rebase and with Sign/Signoff?

The git rebase command supports this usecase:

$ git rebase -i --signoff --gpg-sign <your sha that you are rebasing from>
Enter fullscreen mode Exit fullscreen mode

What is the DCO mentioned regarding signoffs?

_The meaning of a signoff depends on the project, but it typically certifies that the committer has the rights to submit this work under the same license (as the project) and agrees to a Developer Certificate of Origin (see https://developercertificate.org for more information).
_

So, make sure to add something about agreeing to the DCO by Sign-off in your CONTRIBUTING.md, if that applies for your project.

My nice green verified button disappered on GitHub when I choose Rebase on Pull Request with signed commits, with the WebUI

Rebase from the Web-UI on GitHub is broken. Instead of the expected behaviour (as in Git, GitLab, BitBucket and other providers), it always rewrites the hashes, and your nice verified signature is gone. That means you currently cant keep a linear Git history with signed commits and Rebase. However a CLI workaround is to do as described in the Stack Overflow Question here.
I left a bug report and got this answer "I'm afraid this is a known issue we are tracking internally and a pain point for a number of folks. ... While we don’t yet have a specific ETA for when this might be implemented..

Various interesting links
More about about SSH signing
Stack Overflow: What is the Signoff for?

All content in this article is licensed under the CC0 if not stated otherwise. Please add suggestions and corrections if I mixed up something, or that you feel something important is missing.

Top comments (0)