Next.js starter your AI actually understands. Ship internal tools in days not weeks. Pre-order $199 $499 → [Get it now]

How to anonymize commits in Git

Anonymizing Git commits is useful when open-sourcing an internal project, when contributors want to remove personal information, or when team members need to be credited under pseudonyms. As the creator of CoreUI with 25 years of open-source development experience, I’ve helped contributors anonymize their history before submitting patches to public repositories. The most flexible approach is git filter-repo with an email or commit callback that replaces names and emails according to a mapping. This rewrites all matching commits permanently and requires force-pushing to update the remote.

Replace a specific author’s name and email across all history.

# Install git-filter-repo
pip install git-filter-repo
# or: brew install git-filter-repo

# Work on a fresh clone
git clone --no-local original-repo anonymized-repo
cd anonymized-repo

# Replace email with anonymized version
git filter-repo --email-callback '
  return b"[email protected]" if email == b"[email protected]" else email
'

# Replace name simultaneously
git filter-repo --name-callback '
  return b"Anonymous" if name == b"Real Name" else name
'

Run the --email-callback and --name-callback together using a single --commit-callback for efficiency:

git filter-repo --commit-callback '
  if commit.author_email == b"[email protected]":
    commit.author_name = b"Anonymous"
    commit.author_email = b"[email protected]"
  if commit.committer_email == b"[email protected]":
    commit.committer_name = b"Anonymous"
    commit.committer_email = b"[email protected]"
'

The --commit-callback runs for every commit and lets you modify any commit attribute. The callbacks use bytes (b"...") not strings.

Anonymize Multiple Contributors

Use a mapping file to replace many contributors at once.

# mailmap.py - run as a filter-repo commit callback
MAILMAP = {
    b'[email protected]': (b'Contributor A', b'[email protected]'),
    b'[email protected]':   (b'Contributor B', b'[email protected]'),
    b'[email protected]': (b'Contributor C', b'[email protected]'),
}

def replace_author(commit):
    if commit.author_email in MAILMAP:
        name, email = MAILMAP[commit.author_email]
        commit.author_name = name
        commit.author_email = email
    if commit.committer_email in MAILMAP:
        name, email = MAILMAP[commit.committer_email]
        commit.committer_name = name
        commit.committer_email = email
git filter-repo --commit-callback "$(cat mailmap.py)"

Embedding the Python mailmap directly in the shell command passes it as the callback body. For large mappings, save to a file and read it with open() inside the callback.

Anonymize a Single Commit with Amend

For just the most recent commit:

git commit --amend --author="Anonymous <[email protected]>" --no-edit

For older commits without rewriting the full history:

git rebase -i HEAD~5
# Mark target commit as "edit"
# When rebasing pauses at the commit:
git commit --amend --author="Anonymous <[email protected]>" --no-edit
git rebase --continue

This is simpler for changing just one or two commits without running a full history rewrite.

Push the Anonymized History

git remote add origin https://github.com/user/repo.git
git push origin --force --all
git push origin --force --tags

Best Practice Note

Using GitHub’s noreply address format ([email protected]) for anonymized emails is a good practice — it’s a recognized pattern that links to a user profile on GitHub without exposing the real email. Always coordinate with all contributors before anonymizing shared history — rewriting affects everyone’s local clones. For removing sensitive data from commits rather than author information, see how to remove sensitive data from Git history.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author