Rewrite your Git commit history to replace exposed email addresses with your GitHub noreply address β across one or multiple repositories, interactively.
git-mailmask is an interactive CLI tool available for Linux/macOS (Bash) and Windows (PowerShell). It uses git-filter-repo under the hood to rewrite commit history and replace one or more old email addresses with a new identity β typically a GitHub privacy-safe noreply address (<id>+<username>@users.noreply.github.com).
This is useful when you have accidentally committed with a personal or work email and want to retroactively anonymize your public commit history.
- π Rewrites full Git history across all branches
- π Supports multiple old emails in a single run
- π Optional GitHub CLI integration to auto-fill your identity and browse your repositories
- β Interactive menus β arrow keys, space to select, enter to confirm
- π Paginated multi-select for large repository lists
- π₯οΈ Cross-platform: Bash (Linux/macOS) and PowerShell (Windows)
- π Supports local repositories β work on an already-cloned repo or the current directory
- π
--auto-pushflag to skip the push confirmation prompt
pip install git-filter-repoWindows users: Python and pip may not be installed by default. See the official Python installation guide to get started.
- GitHub CLI (
gh) β enables auto-detection of your GitHub username/email and lets you browse and select repositories directly from your account.
# macOS
brew install gh
# Windows (winget)
winget install --id GitHub.cli
# Linux
sudo apt install gh # Debian/Ubuntucurl -sSL https://raw.githubusercontent.com/Cold-FR/git-mailmask/main/git_mailmask.sh -o git_mailmask.sh && chmod +x git_mailmask.shInvoke-WebRequest -Uri "https://raw.githubusercontent.com/Cold-FR/git-mailmask/main/git_mailmask.ps1" -OutFile "git_mailmask.ps1"Clone or download the scripts, then make the Bash script executable:
git clone https://github.com/your-username/git-mailmask.git
cd git-mailmask
chmod +x git_mailmask.sh./git_mailmask.shTo skip the push confirmation at the end:
./git_mailmask.sh --auto-push.\git_mailmask.ps1To skip the push confirmation at the end:
.\git_mailmask.ps1 --auto-pushNote for Windows users: If the script is blocked after download, unblock it first:
Unblock-File .\git_mailmask.ps1
You will be prompted for the replacement name and email to apply to all rewritten commits.
If the GitHub CLI is installed and authenticated, your GitHub username and noreply email are fetched automatically and offered as defaults:
NEW IDENTITY :
- GitHub Username [Enter for: your-username] :
- GitHub Email [Enter for: 12345678+your-username@users.noreply.github.com] :
Press Enter to accept the defaults, or type a custom value.
Enter all email addresses that should be replaced, one per line. Press Enter on an empty line to finish.
OLD EMAILS TO REPLACE :
(Leave empty and press Enter to finish)
> old.work@company.com
> personal@gmail.com
>
Choose how to provide the target repositories:
(X) Enter a remote repository URL manually
( ) Connect to GitHub and select from my repositories
( ) Process the current directory (/your/current/path)
( ) Enter the path to a local repository manually
- Remote URL β paste a single HTTPS or SSH repository URL. The script clones it, rewrites history, and force-pushes back.
- GitHub repositories β requires the GitHub CLI. Fetches all your repos and displays a paginated multi-select menu. Use arrow keys to navigate, Space to toggle selection, and Enter to confirm.
- Current directory β runs directly on the repo in your working directory, no clone needed.
- Local path β enter or drag-and-drop a path to any local git repository. Quotes are stripped automatically.
The tool will:
- Clone the repository into a temporary folder (remote mode) or work in place (local mode)
- Track all remote branches locally
- Apply the mailmap rewrite via
git filter-repo - Restore the remote origin (removed by
git filter-repo) - Ask whether to force-push β or push automatically if
--auto-pushwas passed - Delete the temporary working directory
History successfully rewritten locally!
Do you want to force push to the remote? [Y/n]
=================================================
OPERATION COMPLETED SUCCESSFULLY !
=================================================
The script generates a Git mailmap file mapping each old email to the new identity:
Your Name <new@email.com> <old@email.com>
This file is passed to git filter-repo --mailmap, which rewrites every matching commit in the full history β including all branches.
- This rewrites Git history. All commit SHAs will change. This is a destructive, irreversible operation on the remote.
- Collaborators will need to re-clone or rebase their local copies after a force-push.
- You must have push access (with force-push allowed) to the target repository.
- For organization repositories, confirm that force-push is not blocked by branch protection rules.
Once git-mailmask has force-pushed rewritten history, any existing local clone will be out of sync. To realign it without re-cloning from scratch:
git fetch origin
git reset --hard origin/main # replace 'main' with your branch nameIf you have multiple branches to reset:
git fetch --all
git reset --hard origin/$(git rev-parse --abbrev-ref HEAD)Warning:
git reset --harddiscards all local uncommitted changes. If you have work in progress, you can stash it first:git stash # then after the reset: git stash pop
./git_mailmask.sh
# New identity:
# Username: johndoe
# Email: 12345+johndoe@users.noreply.github.com
# Old emails to replace:
# john.doe@oldcompany.com
# johndoe@personal.io
# Repository: https://github.com/johndoe/my-projectAll commits previously authored or committed with the old emails will be rewritten to johndoe <12345+johndoe@users.noreply.github.com>.
MIT Β© Cold-FR
