# 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:

bash
git log --show-signature

Shows:

``` 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:

bash
# 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.

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):

bash
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:

bash
git filter-branch --msg-filter '
    sed "/^gpgsig /d" | sed "/^ -----BEGIN PGP SIGNATURE-----$/,/^ -----END PGP SIGNATURE-----$/d"
' HEAD

Step 5: Force Push After Rewrite

After rewriting and re-signing, you must force push:

bash
git push --force-with-lease origin main

Warning: 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:

bash
git log --show-signature --oneline -10

All 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:

bash
gpg --list-secret-keys --keyid-format=long

Use 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:

bash
git rebase -i HEAD~5

During 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:

bash
git commit --amend --no-edit -S
git rebase --continue

Important Warning About Rewriting History

Rewriting published history is disruptive:

  1. 1.Notify your team before rewriting shared branches
  2. 2.Ensure everyone has pushed their work before the rewrite
  3. 3.Have team members re-clone after the rewrite (do not use git pull)
  4. 4.Re-sign all commits after the rewrite to maintain trust
  5. 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.