Never commit as the wrong you again.
A git identity guard that blocks the commit when your author identity doesn't match the repo. includeIf can set an identity — gitsignet is what stops a wrong one.
$ git commit -m "fix auth bug" ✗ gitsignet: wrong identity for this remote — commit blocked remote : github.com/acme-corp/widgets rule : github.com/acme-* expected: Work Me <me@acme.com> current : Personal Me <me@personal.dev> fix : run `gitsignet fix` to apply the expected identity $ gitsignet fix ✓ applied the expected identity (local git config): user.email → me@acme.com
Why git already has includeIf
git config includeIf can set your identity automatically — by directory, and since git 2.36 by remote URL too (hasconfig:remote.*.url:...). What it can't do is stop a commit under the wrong identity.
It only sets, never blocks
Typo a glob, or set user.email by hand in a fresh clone, and includeIf will not stop you from committing. gitsignet's pre-commit hook fails the commit when the identity is wrong.
It's silent
You only learn the identity was wrong after the commit is pushed with your personal email on a work repo. gitsignet is loud: doctor tells you up front, and the guard fails the commit.
user.useConfigOnly isn't enough
Git's own user.useConfigOnly refuses to commit with no identity configured at all — but it says nothing about an identity that IS configured and just wrong for this remote. gitsignet checks against a rule, not just presence.
Zero-config doctor
gitsignet doctor works before any config exists — it shows the identity you're about to commit as and the parsed remote. Once a rule exists, it also names the matching rule and whether you match it, and gitsignet fix applies the identity that rule expects.
Install
# install globally npm install -g gitsignet # …or run without installing npx gitsignet doctor
Quick start
# 1. See who you're about to commit as, and why gitsignet doctor # 2. Write a global config with your identities + rules gitsignet init --global # 3. Turn on the pre-commit guard in a repo gitsignet install
Keep one global config with all your identities and you never think about it again — every repo where you've run gitsignet install gets checked against its own remote.
Configuration
A .gitsignet.json in the repo overrides a global config at ~/.config/gitsignet/config.json. Rules match top-to-bottom; first match wins.
{
"strict": false,
"profiles": {
"work": { "name": "Work Me", "email": "me@acme.com" },
"personal": { "name": "Personal Me", "email": "me@personal.dev" }
},
"rules": [
{ "remote": "github.com/acme-*", "profile": "work" },
{ "remote": "github.com/my-username", "profile": "personal" },
{ "remote": "gitlab.com/**", "name": "Personal Me", "email": "me@personal.dev" }
]
}
remote is a glob matched against host/owner/repo, host/owner, and host. * matches within one path segment; ** crosses /. Use the literal "(none)" to match a local-only repo that has no origin remote. Without one, a repo with no origin at all still blocks a placeholder identity — an email at a reserved example or test domain such as ci@example.com, which no person commits as. With strict: true, a commit to any remote that matches no rule is blocked.
Commands
| Command | What it does |
|---|---|
gitsignet doctor | Explain the identity you're about to commit as, the parsed remote, the matching rule, and whether it's OK. Warns when a later rule is shadowed by an earlier broad one. Never fails a commit. |
gitsignet check | The guard. Exits non-zero on a mismatch or strict violation. --hook stays quiet on success. |
gitsignet fix | Apply the identity the matching rule expects (sets user.name/user.email). --global writes global config. Refuses when no rule matches. |
gitsignet install | Add the guard to this repo's pre-commit hook (honours core.hooksPath). Idempotent; preserves an existing hook. |
gitsignet uninstall | Remove the guard from the pre-commit hook. |
gitsignet init | Write a sample config. --global writes it to your XDG config dir. |
The installed hook calls gitsignet if it's on PATH, else falls back to npx --no-install gitsignet — so it works whether the tool is installed globally or as a dev dependency. Running only npx gitsignet is not enough to arm the hook: neither probe can see the transient npx cache, so the guard falls open. Install a resolvable binary (npm i -g gitsignet or npm i -D gitsignet); gitsignet install warns loudly when it can't find one.