125

Git now has the ability to sign commits with git commit -S, which is great, but sometimes I forget the flag to commit, and sometimes I mail myself patches which I apply with am, and that command doesn't have a flag for signing.

Is there a way to add a signature to an already recorded commit?

  • 10
    For the record, you can tell git to always sign commits via configuration: git config commit.gpgsign true. – nicooga Oct 23 '18 at 12:47
  • @nicooga I wish your comment had more upvotes so I noticed this earlier. I've had to pull up this question at least half a dozen times, and setting that flag would've saved me a bunch of time. – Michael Ziluck Sep 16 '19 at 21:28
122
  1. Go into interactive rebase mode.
  2. Add the following line after each commit you want to sign

    exec git commit --amend --no-edit -S

This will run this command after picking each commit.

UPDATE:

Easier way to do this is:

git rebase --exec 'git commit --amend --no-edit -n -S' -i development

This rebases everything till development (or any hash) and you don't have to copy paste after every commit.

| improve this answer | |
  • 2
    Oh I wish I had found this sooner. I read so many things, even from GitHub themselves, saying that you can't resign old commits. This proves that completely false! I could have saved hundreds of commits, which I have now squashed. Oh well... thanks for sharing! I made an alias out of this. resign = "!re() { git rebase --exec 'git commit --amend --no-edit -n -S' -i $1; }; re" becomes git resign HASH – BarryMode Jul 6 '17 at 21:16
  • 2
    This should be common knowledge! You have done a great service for humanity (no sarc!)! – hopeseekr Feb 3 '18 at 20:25
  • 3
    There's no reason to rebase at all. Just run git commit --amend --no-edit -n -S. – Quolonel Questions Mar 6 '18 at 1:51
  • 16
    Doesn’t this change the history, requiring a git push --force? – Steve Apr 14 '18 at 17:21
  • 1
    @Steve Yes, requiring force push depends on what commits you change and whether or not they are pushed already. – Shubham Chaudhary Apr 19 '18 at 6:34
42

Signing a commit changes its contents, so more recent commits depending on it will change their hash.

If you just want to sign the most recent commit, git commit -S --amend will work.

| improve this answer | |
16

I use git rebase -i --root ( see Rewriting History ) and change pick to edit.

Then I use git commit -S --amend --no-edit && git rebase --continue (on Windows) for each commits.

This is manually sign for each commits. I hope we will found better solution.

| improve this answer | |
  • I have my home directory as a git repo (for dotfiles). Some programs interactively pick up changes as its rebasing, funny to see the history being replayed live. It's slow enough because signing is slow – Avindra Goolcharan Jan 22 '17 at 1:33
6

I also stumbled on the same problem and here is my solution:

git rebase -i --root --exec 'git commit --amend --no-edit --no-verify -S'

this will sign all of my commits from the first initial commit and also bypass commit hook that I set up using husky. No need to change pick to edit.

| improve this answer | |
6

If you need to GPG sign all commits SINCE a particular commit on the current branch, you can use the following instead:

git filter-branch --commit-filter 'git commit-tree -S "$@";' <COMMIT>..HEAD

Where <COMMIT> is the commit id (e.g. abc123e5).

This has the added benefit that it does not disturb the commit metadata (including commit date).

If you also would like to stop getting prompted for your GPG passphrase on every commit, also see this answer: https://askubuntu.com/a/805550

NOTE: Switching from gpg to gpg2 for GIT signing will require you to re-import your private key in GPG 2.

| improve this answer | |
5

If you want to filter only specific commits and sign only them you can use filter-branch:

git filter-branch --commit-filter 'if [ "$GIT_COMMITTER_EMAIL" = "user@domain.com" ];
  then git commit-tree -S "$@";
  else git commit-tree "$@";
  fi' HEAD

This is useful if, for some reason, you want to sign only your own commits.

| improve this answer | |
3

If no filtering on commit is needed, then it is preferred to use rebase than filter-branch:

git rebase -i master --exec 'git commit --amend --no-edit --no-verify -S --reset-author'

Else, you can leave untouched the commits you don't own.
Set the following alias in ~/.gitconfig (replace your@address.com with your email address):

resign = "!_() { : git checkout ; [ \"$#\" -eq 0 ] && echo 'Usage: resign <rev-list>' && exit 2; \
                   git filter-branch --commit-filter ' \
                   if [ \"$GIT_COMMITTER_EMAIL\" = \"your@address.com\" ]; then git commit-tree -S \"$@\"; else git commit-tree \"$@\"; fi' $1; }; _"

Then for instance, to resign all your commits in the current branch pulled from master, do:

git resign master..

Credits to previous answers by BarryMode and Roberto Leinardi

| improve this answer | |
0

here's the one I use for all commits, yes it will re-write history:

git rebase --exec 'git commit --amend --no-edit -n -S' -i --root
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.