A client's email on my personal repo: why git-wrong-email exists

One day my personal projects started signing commits with the email of the client I work for instead of mine. A GUI git client had rewritten my global config, and nothing warned me.

On October 13, looking at a public commit history, I saw that my latest commits on a personal project didn’t carry my email. They carried the email of the client I work for.

That isn’t cosmetic. A commit stays public forever with the email it carries, and that wasn’t an email for my own projects.

What I had

I thought I had this solved. The client’s work lives in its own folder inside ~/Code, and in ~/.gitconfig an includeIf gives it its email:

[user]
	name = Sergio Infante
	email = [email protected]

[includeIf "gitdir:~/Code/client/"]
	path = ~/.config/git/identity-client

The identity-client file sets the client’s user.email. If the repo lives under ~/Code/client/, git uses that email. Otherwise it uses the global email, which is the personal one. It’s what almost every guide recommends, and it works.

How it happened

I hadn’t touched anything. What touched it was a GUI git client I use, with a setting along the lines of “keep my .gitconfig updated with my profile info”. That setting rewrote the global user.email with the email of the account I was signed into, which was the client’s.

The client’s repos never noticed, because their includeIf still won. But my personal repos had no includeIf of their own: they relied on the global email, which was exactly the value that had just changed. They all started signing with the client’s email, and git had no reason to complain.

Why what I had didn’t warn me

includeIf assigns, it doesn’t check. It tells git which email to use in a folder. It has no way to tell you that the email git is about to use isn’t the one you expected, because it doesn’t know what you expected. If the includeIf doesn’t apply, for whatever reason, git uses whatever is there and carries on.

user.useConfigOnly doesn’t cover this. I had it on. It makes git refuse to make up an identity like user@mac-name when none is configured. It’s worth turning on, but here the email was configured. It was configured wrong.

A pre-commit hook in each repo isn’t enough either. There are hooks that check the email, but you add them repo by repo, with a config file inside the repo. I can’t do that in the client’s repo, I’d forget it in the next repo I clone, and they only check at commit time.

And the GUI client wasn’t the only risk. I also commit from the terminal, from the editor and, more and more, from coding agents. Any of them can bring its own idea of who I am.

What I actually needed

I didn’t need another way to assign the email; I already had that. I needed something that checked the result:

  • Look at the email git is about to put on the commit, not at the configuration. That way it doesn’t matter how the wrong email got there: a rewritten .gitconfig, a mistyped includeIf, an environment variable or a repo cloned into the wrong folder.
  • One rule per folder, written once. “Only these emails are accepted in this folder.” And if a repo matches no rule, refuse it: a repo with no rule is one I haven’t thought about yet.
  • Cover the whole machine without touching any repo. The ones I have, the ones I’ll clone tomorrow and the client’s, where I can’t add anything.
  • Work with any tool: the terminal, the editor, the GUI client or an agent.
  • Check again before the push. A commit can skip the check with --no-verify or arrive through a rebase, but what matters is that it doesn’t leave the machine.

git-wrong-email

I wrote the first version that same day, as part of the config files I manage with macsetup. The next day I already had to fix it: it blocked a push because of a merge of commits that were already public under another email, and stopping a push over history nobody can fix only teaches you to use --no-verify. A few days later I split it into its own project, git-wrong-email.

It’s a single shell script with no dependencies. It installs as a global git hook, and the rules live in a file:

~/Code/client/     [email protected]
~/Code/personal/   [email protected]
*                  [email protected]

If I try to commit with the wrong email, git refuses:

$ git commit -m 'fix typo'
git-wrong-email: committer email is '[email protected]', which this repository does not accept.
  Repository: /Users/me/Code/personal/my-blog
  Allowed: [email protected]
  Check: git config --show-origin user.email

With this in place, October 13 would have been a commit refused in my terminal, not a public one.

In another post I’ll go into how it works inside: why the hook that matters most is pre-push, what it costs to install a global hook without breaking each repo’s own hooks, and which cases still slip past it. This one was about why it was needed. If you work with more than one identity on the same computer, it’s on GitHub under the MIT license, and it installs with Homebrew:

brew install neosergio/tap/git-wrong-email
git wrong-email install

Comments