Skip to main content

What Happens If a Commit Is Unsigned? (Forgejo Enforcement Across Machines)

· 3 min read
Mark Burton
Software Engineer & Technical Writer

In my previous post, I covered migrating from GPG to SSH commit signing.

If you have not read that first, start here:

This follow-up answers a practical question that appears as soon as you use multiple machines:

"If I commit from another machine and forget to sign, does push get rejected, or does it push and show untrusted?"

Short answer: it depends on enforcement.

Trust Labels vs Enforcement​

These are separate controls and should not be confused:

  • Trust model controls how Forgejo labels signed commits in the UI.
  • Enforcement policy controls whether unsigned commits are allowed onto protected branches.

If you set:

FORGEJO__REPOSITORY_SIGNING__DEFAULT_TRUST_MODEL=committer

that affects trust evaluation and labels. It does not, by itself, block unsigned pushes.

What Happens When You Push an Unsigned Commit​

Case 1: No signed-commit enforcement on the target branch​

  • Push succeeds.
  • Commit is visible.
  • Signature state is shown as unverified/untrusted (or not verified).

Case 2: Signed-commit enforcement enabled on the target branch​

  • Push is rejected.
  • Your commit remains local.
  • You re-sign locally, then push again.

Typical Multi-Machine Failure Mode​

This usually happens because one machine is missing one of these:

  • gpg.format=ssh
  • commit.gpgsign=true
  • user.signingkey=<path-to-public-key>

It is rarely a Forgejo bug. It is usually configuration drift between environments.

Fast Recovery​

Last commit only​

git commit --amend --no-edit -S
git push --force-with-lease

Several recent commits​

git rebase -i --exec "git commit --amend --no-edit -S" <base>
git push --force-with-lease

Use force-with-lease carefully and only on branches where rewrite is acceptable.

Practical Policy​

For personal and small-team self-hosted workflows:

  1. Keep signing enabled globally on every machine.
  2. Use passphrase-protected private keys.
  3. Use ssh-agent so passphrases are not a daily pain.
  4. Enable signed-commit enforcement on protected branches where you want hard guarantees.

Forgejo Protected Branch Checklist​

Use this as a quick hardening list for repositories where unsigned commits should never land on key branches.

  1. Protect your primary branch (for example main).
  2. Enable the signed-commit requirement in branch protection.
  3. Keep your trust model set to committer at server level unless you have a specific reason not to.
  4. Test from a machine with signing configured and confirm push succeeds.
  5. Test from a machine without signing configured and confirm push is rejected.
  6. Document the recovery command for contributors:
git commit --amend --no-edit -S
git push --force-with-lease

This gives you both visibility (trust labels) and enforcement (blocked unsigned pushes).

Appendix: Windows and WSL Parity Checklist​

If you commit from both Windows and WSL, run this in each environment and compare outputs.

git --version
git config --show-origin --get gpg.format
git config --show-origin --get user.signingkey
git config --show-origin --get commit.gpgsign
git log --show-signature -1

Expected minimum parity:

  • gpg.format=ssh
  • commit.gpgsign=true
  • A valid user.signingkey path for that environment

On Windows, also check which Git binaries are available:

where.exe git

If parity checks fail, treat it as configuration drift and fix before relying on enforcement.

Final Thought​

Trust labels are a visibility tool. Enforcement is a control.

Use both deliberately: labels to understand provenance, enforcement to protect critical branches.