Keeping signatures valid through rebase and squash Jump to heading

A signature covers the exact bytes of a commit object: its tree, its parents, its author and committer lines and its message. Change any of those and you have a different commit, which the old signature does not cover. Every history-rewriting operation — rebasing onto a newer base, squashing fixups, amending a message, even a rebase that changes nothing but the parent — therefore produces commits that are either freshly signed or unsigned. Teams that enforce signing discover this the first time a perfectly signed branch fails the gate after a routine rebase. This page shows how to make re-signing automatic and how to choose merge methods that keep signatures meaningful, as part of the commit verification gates topic.

When to use this approach Jump to heading

  • Your gates verify signatures, and contributors rebase, squash or amend before merging.
  • Branches pass the signature check when first pushed but fail after being updated on top of a newer base.
  • You use the forge’s squash or rebase merge buttons and want to understand what happens to signatures.
  • You maintain long-running branches that are periodically rebased, as described in keeping a long-lived branch in sync with main.

Step 1 — Understand why a rebase strips signatures Jump to heading

A rebase replays each commit onto a new parent. The new commit has a different parent hash, so it is a different object, and Git has to decide whether to sign it. It signs only if signing is turned on for the person running the rebase.

Same change, new commit, new signature neededA branch of two signed commits is rebased onto a newer main. The replayed commits contain the same changes but have different parents, so they are new objects. Without automatic signing they arrive unsigned, and the gate rejects them.rebase replays commits as new objectsbeforeBS1S2main movedBNafter rebaseNS1'S2'S1' is not S1 — it needs its own signature or the gate sees an unsigned commit Same change, new commit, new signature neededA branch of two signed commits is rebased onto a newer main. The replayed commits contain the same changes but have different parents, so they are new objects. Without automatic signing they arrive unsigned, and the gate rejects them.rebase replays commits as new objectsbeforeBS1S2main movedBNafter rebaseNS1'S2'S1' is not S1 — it needs its own signature or the gate sees an unsigned commit
# Verification: compare signature status before and after a rebase
git log -2 --format='%h %G?' feature        # G G
git rebase main feature
git log -2 --format='%h %G?' feature        # N N if signing is not automatic

Step 2 — Turn on automatic signing for every commit Git creates Jump to heading

The commit.gpgSign setting tells Git to sign every commit it writes, including the ones produced by rebase, cherry-pick, amend and merge --squash. It is the single most important setting for keeping signatures through rewrites.

git config --global commit.gpgSign true
git config --global tag.gpgSign true         # annotated tags too
# For SSH signing, also make sure the format and key are set
git config --global gpg.format ssh
git config --global user.signingKey ~/.ssh/id_ed25519_signing.pub

With this on, a rebase re-signs each replayed commit as it writes it, so S1' and S2' above carry fresh signatures from the person who ran the rebase.

Every operation that writes a new commitRebase, cherry-pick, amend and a squash merge each create new commit objects. With commit.gpgSign enabled, all four sign what they write; without it, all four quietly produce unsigned commits.rebasereplays each commitcherry-pickcopies one commitcommit --amendreplaces the tipmerge --squashfolds a branchone setting, commit.gpgSign, covers all four — per-command -S flags are easy to forget Every operation that writes a new commitRebase, cherry-pick, amend and a squash merge each create new commit objects. With commit.gpgSign enabled, all four sign what they write; without it, all four quietly produce unsigned commits.rebasereplays each commitcherry-pickcopies one commitcommit --amendreplaces the tipmerge --squashfolds a branchone setting, commit.gpgSign, covers all four — per-command -S flags are easy to forget
# Verification: rebase again and every rewritten commit is signed
git rebase main feature && git log main..feature --format='%h %G?'

That last point has a consequence worth stating: after a rebase, the signature belongs to whoever ran it, not necessarily the original author. If Alice rebases Bob’s commits, they end up signed by Alice. The author field still says Bob, and the committer field says Alice. For most gates that is acceptable — the person who rewrote the commit vouches for it — but a gate that requires signer to equal author will reject it.

Step 3 — Re-sign a branch that was rewritten without signing Jump to heading

If someone already rebased without signing turned on, the fix is to rewrite each commit once more with a signature. The --exec option runs a command after each replayed commit.

# Re-sign every commit on the branch since it diverged from main
git rebase --exec 'git commit --amend --no-edit -S' "$(git merge-base main HEAD)"
git log main..HEAD --format='%h %G?'   # all G

⚠️ SAFETY WARNING: This rewrites every commit on the branch, so the branch must be force-pushed afterwards. Use git push --force-with-lease, which refuses if someone else pushed to the branch in the meantime. If anything goes wrong, the pre-rewrite tip is in the reflog: git reset --hard ORIG_HEAD restores it immediately after the rebase, or git reflog feature finds it later.

Step 4 — Choose a merge method that keeps signatures meaningful Jump to heading

The forge’s merge buttons are where most signature loss happens, because the forge — not the contributor — creates the final commits.

What survives each merge methodMerging locally or with a merge commit keeps every contributor signature on the branch. Squash and rebase merges made by the forge replace them with forge-signed commits. Squashing locally and pushing keeps a contributor signature but only on the single squashed commit.Contributor signaturesSigner of final commitsforge merge commitpreservedcontributors + forgeforge squashlostforge onlyforge rebaselostforge onlylocal squash, pushone, re-signedperson who squashedif contributor signatures must be on the branch, merge commits are the only forge option What survives each merge methodMerging locally or with a merge commit keeps every contributor signature on the branch. Squash and rebase merges made by the forge replace them with forge-signed commits. Squashing locally and pushing keeps a contributor signature but only on the single squashed commit.Contributor signaturesSigner of final commitsforge merge commitpreservedcontributors + forgeforge squashlostforge onlyforge rebaselostforge onlylocal squash, pushone, re-signedperson who squashedif contributor signatures must be on the branch, merge commits are the only forge option

Three workable policies follow from that table. Use merge commits, and contributor signatures stay in history. Use forge squash or rebase, and accept the forge’s signature as the attestation — pin and trust the forge key as described in verifying signatures on merge commits made by the forge. Or squash locally with signing on and fast-forward the result, which keeps one contributor signature per change at the cost of a manual step.

# Local squash that produces one signed commit, then fast-forward
git switch feature
git reset --soft "$(git merge-base main HEAD)"
git commit -S -m "Add rate limiting to the export API"
git switch main && git merge --ff-only feature

Step 5 — Re-sign fixups during autosquash Jump to heading

Fixup workflows rewrite history on purpose. With commit.gpgSign on, git rebase -i --autosquash signs the folded commits automatically. Without it, every autosquash produces an unsigned branch, which is the single most common cause of “it was signed yesterday” reports.

git commit --fixup=HEAD~2 -S
git rebase -i --autosquash main     # writes signed commits when commit.gpgSign is true
git log main..HEAD --format='%h %G? %s'

The full fixup workflow is in using fixup commits and autosquash during review.

Validation checklist Jump to heading

Frequently Asked Questions Jump to heading

Can Git keep the original author’s signature through a rebase? Jump to heading

No. The signature covers the parent hash, which changes, so the original signature no longer matches the new commit. Only the person who creates the new commit can sign it. If preserving the original signature matters, merge instead of rebasing.

Does git cherry-pick sign the new commit? Jump to heading

Yes, when commit.gpgSign is true or when you pass -S. A cherry-picked commit is a new object, so the same rule applies as for a rebase. Backports made by automation need the automation’s own key.

Why does the gate reject a commit I only amended to fix a typo? Jump to heading

Amending creates a new commit. If you amended without signing — for example with commit.gpgSign unset and no -S — the new commit is unsigned. Amend again with -S, or turn on automatic signing so it never happens.