I once pushed several commits with the wrong email address. The current Git config was easy to fix, but the old commits still showed the wrong identity on GitHub. This note records the cleanup process.
Before doing this, one warning is worth repeating: this rewrites Git history. If the repository is shared with other people, talk to them first. Everyone may need to rebase, reset, or clone again after the force push.
Fix the Current Config First
For new commits, update user.name and user.email normally:
$ git config user.name "Zhang San"
$ git config user.email "zhangsan@example.com"
If the same identity should be used for all repositories on the machine:
$ git config --global user.name "Zhang San"
$ git config --global user.email "zhangsan@example.com"
This only affects future commits. Existing commits need a history rewrite.
Use a Fresh Clone
git-filter-repo is the tool I prefer for this kind of job. It is faster and clearer than the old git filter-branch flow.
I usually start from a fresh clone instead of running it in my daily working directory:
$ git clone git@github.com:your-name/your-repo.git your-repo-rewrite
$ cd your-repo-rewrite
Install the tool if it is not available:
$ pip install git-filter-repo
On macOS, Homebrew is also fine:
$ brew install git-filter-repo
Prepare a Mailmap
Create a file named my-mailmap in the repository root:
Zhang San <zhangsan@example.com> <old-email@example.com>
This means: whenever a commit uses <old-email@example.com>, rewrite it to Zhang San <zhangsan@example.com>.
Multiple old addresses can point to the same final identity:
Zhang San <zhangsan@example.com> <old-email@example.com>
Zhang San <zhangsan@example.com> <work-old@example.com>
Zhang San <zhangsan@example.com> <noreply-old@example.com>
Then run:
$ git filter-repo --mailmap my-mailmap
If you are not using a fresh clone, git-filter-repo will refuse to run unless you add --force. That refusal is useful. It saved me from rewriting the wrong local checkout once.
Check the Result
After the rewrite, verify a few commits:
$ git log --format='%h %an <%ae> | %cn <%ce>' -n 10
The first identity is the author, and the second identity is the committer. With --mailmap, git-filter-repo rewrites both in the commit objects.
If you only want GitHub or git shortlog to display a corrected identity without changing commit hashes, use a committed .mailmap file instead. That is safer for shared repositories, but it does not change the actual historical commit metadata.
Push the Rewritten History
One detail that is easy to miss: after git-filter-repo runs, it removes the origin remote by default. Add it back before pushing:
$ git remote add origin git@github.com:your-name/your-repo.git
$ git push --force --all origin
$ git push --force --tags origin
After that, tell collaborators what happened. For a small private repository, recloning is usually the simplest recovery path. For a larger shared repository, people may prefer to reset their local branches carefully.
A Small Checklist
- Fix current
git configfirst, so the same mistake does not continue. - Rewrite from a fresh clone.
- Keep the
my-mailmapfile around for audit, even if it is not committed. - Verify with
git logbefore force pushing. - Coordinate before rewriting any branch that other people use.