How to interactively use git rebase to fix unsigned GPG commits.
This is mainly a "post-it note to self" as I usually don't forget to sign my git commits, but occasionally I run into issues where I don't notice a commit has not been signed until 30 commits later. Here's the solution...
TL;DR
git rebase -i ID_OF_COMMIT_BEFORE_FIX
- change
pick
toedit
for the commit(s) needing a GPG signature and save. git commit --amend --no-edit -S
git rebase --continue
The Backstory
In my usual workflow, especially when working with software that utilizes Git Flow like branches, I use GitKraken for visualization of the git structure.It has a nice UI and does a great job at presenting git repositories. But it does lack some "advanced" features to be truly useful to me. Such as handling complex GPG / SSH key setup's. (More on that in a future post)
This morning I was working on geeshoe/atom, a PHP library to to generate fully compliant RFC4287 RSS/Atom feeds (Currently in initial development). I had mistakenly performed a cherry pick using GitKraken. I say mistakenly because as I mentioned previously, GitKraken doesn't recognize my GPG key setup, so while it did perform the cherry pick, GitKraken didn't actually sign the commit. I didn't notice this until after I had pushed a PR up to GitHub and seen one of my commits didn't have the green "verified" tag. Dang it!
Are my commits signed?
In the CLI, git log --show-signature
let's you know...
user@host:~/document$ git log --show-signature
commit 4ff30a5... (HEAD -> master)
gpg: Signature made Tue 28 Jan 2020 05:36:27 AM EST
gpg: using RSA key ...741096D2ADE04CA
gpg: Good signature from "Jesse Rushlow <jr@geeshoe.com>" [ultimate]
Author: Jesse Rushlow <jr@geeshoe.com>
Date: Tue Jan 28 05:36:01 2020 -0500
updated doc
commit 95f8587...
Author: Jesse Rushlow <jr@rushlow.dev>
Date: Tue Jan 28 05:21:15 2020 -0500
ignore ideas
commit c772d80d...
gpg: Signature made Tue 28 Jan 2020 05:19:33 AM EST
gpg: using RSA key ...741096D2ADE04CA
gpg: Good signature from "Jesse Rushlow <jr@geeshoe.com>" [ultimate]
Author: Jesse Rushlow <jr@geeshoe.com>
Date: Tue Jan 28 05:19:28 2020 -0500
Initial commit
I've modified the output above for readability but as you can see, the first (Initial commit) & the third (updated doc) commits were both signed using my GPG key. The second commit (ignore ideas) however was not signed.
The fix
As the above scenario doesn't happen often to me, I always seem to forget how to sign previous commits without getting into a git mess. After doing some googling, rebasing hit's me square in the forehead. Duh!
The key is that we want to begin the rebase at the commit just before the commit which needs to be modified. In this case it will be the initial commit c772d80
. We also want to rebase interactively.
git rebase -i c772d80
will open a text editor that will allow use to tell git which commit we want to modify.
user@host:~/document$ git rebase -i c772d80
Editor:
pick 95f8587 ignore ideas
pick 4ff30a5 updated doc
# Rebase c772d80..80753f3 onto c772d80 (3 commands)
#
# Commands:
..........
We are going to change pick
to edit
for pick 95f8587 ignore ideas
within the editor and save as shown below.
Editor:
edit 95f8587 ignore ideas
pick 4ff30a5 updated doc
# Rebase c772d80..80753f3 onto c772d80 (3 commands)
#
# Commands:
..........
Git will then bring you back to the command prompt and halt at the commit that needs editing:
user@host:~/document$ git rebase -i c772d80
Stopped at 95f8587... ignore ideas
You can amend the commit now, with
git commit --amend '-S'
Once you are satisfied with your changes, run
git rebase --continue
user@host:~/document$
Now we can sign the commit using git commit --amend --no-edit -S
--amend
Amend the previous commit.
--no-edit
Use the existing commit message. No need to edit it.
-S
GPG-sign the commit. If you need to specify the GPG key to use, -S[<keyid>]
is more appropriate.
After running the above command, git will output something similar to the following:
user@host:~/document$ git commit --amend --no-edit -S
[detached HEAD c11cc9e] ignore ideas
Author: Jesse Rushlow <jr@rushlow.dev>
Date: Tue Jan 28 05:21:15 2020 -0500
1 file changed, 1 insertion(+)
create mode 100644 .gitignore
user@host:~/document$
We can now go ahead and finish up the rebase with git rebase --continue
& if all goes well, git will tell you that the rebase was successful. To verify that we signed the commit, git log --show-signature
should now show the GPG signature:
user@host:~/document$ git rebase --continue
Successfully rebased and updated refs/heads/master.
user@host:~/document$ git log --show-signature
...
commit c11cc9e...
gpg: Signature made Tue 28 Jan 2020 05:58:38 AM EST
gpg: using RSA key ...741096D2ADE04CA
gpg: Good signature from "Jesse Rushlow <jr@geeshoe.com>" [ultimate]
Author: Jesse Rushlow <jr@rushlow.dev>
Date: Tue Jan 28 05:21:15 2020 -0500
ignore ideas
...
user@host:~/document$
You're all set! Happy coding...
Word to the wise...
If you have already pushed the unsigned commit upstream to github as I did, care should be taken before using the above described method. As there could be negative consequences.
First, after performing the rebase, you will more than likely have to force push the branch upstream to github. If this is a feature branch that hasn't been merged / modified by others, forcing the push shouldn't cause any headaches.
If there have been modifications to the branch / PR upstream, you may want to revert the commit, and just create a new signed commit rather than doing a rebase. If all else fails, you can always let the unsigned commit ride solo as a reminder not to make that mistake again...
As always comments, rants, suggestions, and constructive criticism are always welcome.
- Jesse Rushlow
jr@rushlow.dev
Top comments (0)