# Fix Git Filter-Branch Rewrite Breaking GPG Commit Signatures
You use git filter-branch to rewrite history (remove large files, change author email, split a repository), but after the rewrite, all GPG-signed commits lose their signatures:
git log --show-signatureShows:
``` commit abc1234 (HEAD -> main) gpg: Signature made Thu 08 Apr 2026 10:00:00 AM UTC gpg: using RSA key ABC123 gpg: Good signature from "Author <email@example.com>"
commit def5678 gpg: WARNING: The signature is invalid! gpg: BAD signature from "Author <email@example.com>" ```
The signatures on rewritten commits are broken because the commit hash changed during the rewrite, invalidating the GPG signature.
Why Signatures Break During Rewrite
A GPG signature is a cryptographic signature of the commit content (tree, parent, author, committer, message). When git filter-branch rewrites a commit, even a single character change produces a different commit hash. The original GPG signature no longer matches the new commit content.
This is by design -- if signatures survived rewrites, an attacker could modify a signed commit and claim it was still the original.
Step 1: Re-Sign Rewritten Commits
After the rewrite, re-sign all affected commits:
```bash git filter-branch -f --commit-filter ' GIT_COMMITTER_NAME="$GIT_COMMITTER_NAME" \ GIT_COMMITTER_EMAIL="$GIT_COMMITTER_EMAIL" \ git commit-tree "$@" ' HEAD
# Then re-sign all commits git rebase --exec 'git commit --amend --no-edit -S' --root ```
The --exec flag runs the command after each commit during the rebase. The -S flag signs each commit with your GPG key.
Step 2: Sign Only Recent Commits
If you do not want to re-sign the entire history:
# Sign the last N commits
git rebase -i HEAD~10 --exec 'git commit --amend --no-edit -S'This opens the interactive rebase editor but immediately amends and signs each commit.
Step 3: Use filter-repo Instead (Recommended)
git filter-branch is deprecated. The recommended replacement is git-filter-repo, which handles rewrites more efficiently:
```bash # Install pip install git-filter-repo
# Run the rewrite git filter-repo --force
# Re-sign all commits after rewrite git rebase --exec 'git commit --amend --no-edit -S' --root ```
git-filter-repo is faster, safer, and does not leave backup refs that clutter the repository.
Step 4: Remove Signature Information Before Rewrite
If you are rewriting commits that include signature data in the commit message (GitHub-style):
Signed-off-by: Author <email@example.com>
gpgsig -----BEGIN PGP SIGNATURE-----
...
-----END PGP SIGNATURE-----The signature block in the commit message is just text and does not affect the cryptographic signature. However, if you want to clean it up:
git filter-branch --msg-filter '
sed "/^gpgsig /d" | sed "/^ -----BEGIN PGP SIGNATURE-----$/,/^ -----END PGP SIGNATURE-----$/d"
' HEADStep 5: Force Push After Rewrite
After rewriting and re-signing, you must force push:
git push --force-with-lease origin mainWarning: This rewrites the public history. Anyone who has cloned the repository will need to re-clone or reset their local branches.
Step 6: Verify Signatures After Rewrite
After the rewrite and re-signing:
git log --show-signature --oneline -10All commits should now show "Good signature" with your current GPG key.
Step 7: Configure GPG Signing
Ensure Git is configured to sign commits:
```bash # Set your GPG key git config --global user.signingkey ABC123DEF456
# Sign all commits by default git config --global commit.gpgSign true
# Or sign tags git config --global tag.gpgSign true ```
List your GPG keys:
gpg --list-secret-keys --keyid-format=longUse the key ID from the sec line (e.g., rsa4096/ABC123DEF456 -- the key ID is ABC123DEF456).
Step 8: Alternative: Use git-rebase for Signature Preservation
If you only need to modify commit messages or squash commits (not remove files), use interactive rebase instead of filter-branch:
git rebase -i HEAD~5During interactive rebase, you can:
- reword -- Change commit message (preserves signature if re-signed)
- edit -- Modify commit content
- squash -- Combine commits
- drop -- Remove commit
After the rebase, sign the modified commits:
git commit --amend --no-edit -S
git rebase --continueImportant Warning About Rewriting History
Rewriting published history is disruptive:
- 1.Notify your team before rewriting shared branches
- 2.Ensure everyone has pushed their work before the rewrite
- 3.Have team members re-clone after the rewrite (do not use
git pull) - 4.Re-sign all commits after the rewrite to maintain trust
- 5.Test the rewritten history thoroughly before force pushing
For large teams, consider using git replace instead of git filter-branch to create alternative history views without rewriting the actual commits.