Your Git history should be a record of progress, not a graveyard of abandoned email addresses and typos that make it look like five different people wrote your project. If you've ever seen your GitHub contribution graph go dark because you committed from a new laptop with a default user.email, you’ve felt the frustration of a fragmented digital identity.
The Problem: Git is a Pedant
Git is incredibly literal. To Git, [email protected] and [email protected] are two entirely different human beings, even if the commit messages both sound like they were written by the same caffeinated developer at 3:00 AM.
When you run git shortlog -sn to see who has been doing the heavy lifting, you might see something depressing like this:
42 John Doe <[email protected]>
15 johnny <[email protected]>
3 j-doe <[email protected]>That’s 60 commits from one person split across three different identities. It messes up your stats, it breaks "blame" workflows, and it looks unprofessional when you're handing off a codebase.
The Fix: .mailmap
Instead of performing dangerous surgery on your history with git filter-repo or a messy rebase—which forces everyone else on the team to delete their local clones—you can just use a .mailmap file.
Think of it as a mapping layer. It doesn’t change the underlying commit data; it just tells Git, "Whenever you see this messy identity, show this clean one instead."
To get started, create a file named .mailmap in the root of your repository.
Mapping the Chaos
The syntax is straightforward but picky. The general rule is: Proper Name <[email protected]> Commit Name <[email protected]>.
Here is how I usually structure mine to handle various identity crises:
# Proper Name <[email protected]> <[email protected]>
John Doe <[email protected]> <[email protected]>
John Doe <[email protected]> <[email protected]>
# Proper Name <[email protected]> Old Name <[email protected]>
John Doe <[email protected]> Johnny D <[email protected]>
# Or fix everything at once if the email is the same but names vary
John Doe <[email protected]>Let's break that down:
1. The Email Swap: The first two lines tell Git that any commit made with those work or school emails should be credited to John Doe <[email protected]>.
2. The Name Correction: The third line fixes those instances where you used the right email but a weird nickname.
3. The Catch-All: The last line is the simplest—it tells Git that for the email [email protected], always display the name as John Doe.
Why this is better than rewriting history
I've seen developers spend hours trying to filter-branch their way out of a typo. Don't do that. Rewriting history changes the commit hashes. If you're working on a shared team repo, you’ve just made yourself the most unpopular person in the office because everyone else's local branches are now out of sync.
The .mailmap file is a plain text file. You commit it to the repo like any other file. It’s version-controlled, safe, and works instantly for everyone who pulls the code. When someone runs git log or git shortlog, Git looks for that file and applies the "mask" automatically.
Global vs. Local
Most of the time, you want the .mailmap inside the project so the whole team benefits. But if you have a personal habit of using different aliases across a dozen different repos, you can set a global mailmap:
git config --global mailmap.file ~/.mailmapThis is great for your own sanity on your local machine, though it won't fix the display for your colleagues on their machines. For open-source projects, always stick the file in the repo root.
The "Gotcha" with GitHub and GitLab
While Git handles .mailmap natively in the CLI, web interfaces like GitHub and GitLab have their own ways of calculating contribution graphs.
GitHub, for example, largely relies on the email address being linked to your GitHub account. However, they *do* support .mailmap for things like the "Contributors" list in some views. If you find your GitHub graph is still broken, the best fix is usually adding all your old email addresses to your GitHub account settings. You don't have to make them public; just verify them, and GitHub will retroactively link those commits to your profile.
Final Thoughts
A clean history isn't just about vanity. It’s about making the git log readable. When I’m trying to figure out why a line of code exists, I don’t want to spend five minutes wondering if j-smith and Smith, James (Contractor) are the same person.
Spend the three minutes it takes to create a .mailmap. Your future self—and your teammates—will thank you.