I Used the Wrong Git Email for 2 Weeks — And No One Noticed
Every commit on my client's project showed sandeep@personal.com. Two weeks of commits. The wrong email. I didn't know it was happening. Here's the fix I set up that night — and haven't thought about since.
I accidentally committed 2 weeks of client work using my personal email.
No warnings. No errors. No clue it was happening.
I only noticed after pushing everything to GitHub.
Here's the thing nobody tells you when you start freelancing alongside a full-time job: Git has no idea you're two different people depending on which folder you're in.
I found this out the hard way.
I'd been heads-down on a client dashboard project — late nights, quick commits, shipping fast. Then one morning I opened GitHub to review a PR and noticed something. Every single commit. Every one. Author: sandeep@personal.com.
Not sandeep@work.com. Not the email the client hired. My personal one.
I had three client projects on that machine. Same story across all of them. Two weeks of commits. All from the wrong person, technically.
I didn't tell the client. I just fixed it and moved on. But it bothered me for days — not the mistake, the fact that I had no idea it was happening.
Why it happens (and why it's not obvious)
Git stores your identity in a config file at ~/.gitconfig. That's your global config. It applies everywhere on your machine unless something overrides it.
# this is probably set to whatever you used when you first installed Git
git config --global user.email
# → sandeep@personal.comWhen you create or clone a repo, that global config is what Git uses — silently, automatically, every commit — until you tell it otherwise for that specific repo.
Most developers never do. Why would you? You set it up once years ago and forgot about it. The problem only surfaces when you're juggling multiple contexts on one machine: personal projects, client work, a side job, a company laptop you also use for open source.
The first thing I tried (which doesn't really solve it)
cd ~/clients/acme-dashboard
git config --local user.email "sandeep@work.com"This works. It sets the email just for that repo by writing to .git/config inside it. Problem solved for this repo.
But I had eleven client repos. I went through all of them. Felt productive. Two days later I cloned a new one, started committing immediately, and forgot to run the command. Three commits in before I caught it.
--local is a fix for the symptom, not the cause. The cause is that you have to remember — and you won't, every time.
The fix I actually use now
Git has something called includeIf. It lets you load a different config file depending on which directory you're working in. Set it up once and it just runs — automatically, in the background, every time. You never think about it again.
First, organise your projects into folders by who you are when you work on them:
~/
├── clients/ ← freelance work
├── work/ ← day job
└── personal/ ← your own stuffThat folder structure is the trigger. Everything under ~/clients/ gets one identity. Everything under ~/personal/ gets another.
Then create a config file for each identity:
# ~/.gitconfig-clients
[user]
name = Sandeep
email = sandeep@work.com# ~/.gitconfig-personal
[user]
name = Sandeep
email = sandeep@personal.comThen add three lines to your global ~/.gitconfig:
[user]
name = Sandeep
email = sandeep@personal.com # the default fallback
[includeIf "gitdir:~/clients/"]
path = ~/.gitconfig-clients
[includeIf "gitdir:~/work/"]
path = ~/.gitconfig-workWhen Git runs inside any repo under ~/clients/, it loads ~/.gitconfig-clients. The work email overrides the global personal one. No command after cloning. No checklist. No forgetting.
cd ~/clients/acme-dashboard
git config user.email
# sandeep@work.com ✓
cd ~/personal/my-blog
git config user.email
# sandeep@personal.com ✓
# see exactly which file is responsible
git config --show-origin user.email
# file:/Users/sandeep/.gitconfig-clients sandeep@work.comWhat about two different GitHub accounts?
This is a separate problem that looks similar but isn't. user.email controls what shows up in the commit author line. That's metadata. It has nothing to do with which GitHub account you're authenticated as when you push.
If you have a work GitHub account and a personal one, you need separate SSH keys. Otherwise you'll be pushing as the same account no matter what email the commit shows.
# one key per account
ssh-keygen -t ed25519 -f ~/.ssh/id_work -C "work"
ssh-keygen -t ed25519 -f ~/.ssh/id_personal -C "personal"
# add each public key to the matching GitHub account
# GitHub → Settings → SSH and GPG keys → New SSH key# ~/.ssh/config
Host github-work
HostName github.com
User git
IdentityFile ~/.ssh/id_work
Host github-personal
HostName github.com
User git
IdentityFile ~/.ssh/id_personal
# clone using the alias
git clone git@github-work:client-org/project.git
git clone git@github-personal:sandeep007/blog.git
# test both
ssh -T git@github-work
# Hi work-sandeep! You've successfully authenticated.
ssh -T git@github-personal
# Hi sandeep! You've successfully authenticated.The things that will trip you up
- The trailing slash matters — gitdir:~/clients and gitdir:~/clients/ are different. The version without the slash may not match subdirectories reliably. Always include it
- Check config from inside the repo — running git config user.email outside a Git repo always returns the global. cd into the actual project first before verifying
- The folder is the contract — clone a client project into ~/personal/ by accident and it gets the personal identity. includeIf doesn't know what the project is, only where .git lives
- Windows needs full paths — the ~/ shorthand doesn't work reliably in gitdir: on Windows. Use the full path: gitdir:C:/Users/Sandeep/clients/
Honest takeaway
I wasted two weeks of commit history and some amount of professional credibility because I didn't know includeIf existed. The fix took me about ten minutes once I found it.
It's one of those Git features that feels almost too simple — you put it in one file and never think about it again. The folder structure becomes the rule. Git enforces it silently.
If you work on more than one type of project on the same machine, set this up today. It costs you nothing and saves you from the specific embarrassment of a client asking who is writing all their code.
If you’re working on multiple projects on the same machine, set this up today.
It takes 10 minutes — and can save your professional reputation.
Follow Stack Dev Life for more real-world dev mistakes & fixes.
Related Articles
You might also enjoy these
Array.fromAsync() and the End of Promise.all Map Patterns
Every JavaScript developer has written await Promise.all(items.map(async item =>...)). It works — until you hit a rate-limited API, a paginated async generator, or a ReadableStream. Array.fromAsync() is the purpose-built replacement you didn't know you needed.
Angular Signals Forms — Replace ReactiveFormsModule in New Projects
Reactive forms were the right solution for 2018. Angular 21 ships Signal-based Forms — no valueChanges, no async pipe, no subscription management. Here's how to replace ReactiveFormsModule in every new component you write.
Stay in the loop
Get articles on technology, health, and lifestyle delivered to your inbox.
No spam — unsubscribe anytime.