Skip to main content

git-scrub

PyPI version Python versions License: MIT

CLI tool to scan GitHub organizations and user profiles for a committed email address, then rewrite it out of history across every affected repo.


Why this exists

git filter-repo handles the local rewriting step well, but provides no tooling to:

  • Discover which repos across a GitHub org or user profile contain a given email
  • Clone, rewrite, and force-push each one automatically
  • Verify the result via the GitHub API after each push
  • Report a clean summary across dozens or hundreds of repos

git-scrub automates the entire workflow. Point it at an org or a username, give it the old and new email, and it handles the rest.

Common use case: you've left a job or graduated, and you want to scrub your old institutional email (you@university.edu) from every repo you've ever touched — replacing it with your personal GitHub no-reply address.


How it works

1. Discover   →  list every repo in the target org(s) / user profile(s)
2. Scan       →  check each repo's commit history for the old email
                 (both author and committer fields)
3. Report     →  show a table of dirty repos and commit counts
4. Rewrite    →  for each dirty repo: clone → git filter-repo → force-push
5. Verify     →  confirm via the GitHub API that the email is gone
6. Clean up   →  temp clone is deleted after each repo

Steps 4–6 only run with --fix. Everything up to step 3 is always safe.


Prerequisites

  • Python 3.9+
  • git-filter-repo
    brew install git-filter-repo
    # or
    pip install git-filter-repo
    
  • GitHub CLI (gh) authenticated or a GITHUB_TOKEN env var with repo scope

Installation

pipx install git-scrub   # recommended
# or
pip install git-scrub

Usage

Scan (dry-run, always safe)

# Scan a whole org
git-scrub --old-email old@work.edu --org my-org

# Scan all repos under a GitHub username (public + private)
git-scrub --old-email old@work.edu --user myusername

# Multiple targets at once
git-scrub --old-email old@work.edu --org org1 --org org2 --user myusername

# Target a single specific repo
git-scrub --old-email old@work.edu --repo owner/repo-name

# Scan a non-default branch
git-scrub --old-email old@work.edu --org my-org --branch develop

Rewrite and push (--fix)

git-scrub \
  --old-email old@work.edu \
  --new-email 123456+myusername@users.noreply.github.com \
  --org my-org \
  --fix

# Skip per-repo confirmation prompts
git-scrub ... --fix --yes

JSON output (for scripting / CI)

git-scrub --old-email old@work.edu --org my-org --json
{
  "scanned": 42,
  "dirty": [
    { "repo": "my-org/some-repo", "commits": 7 }
  ]
}

Token

# Via env var (useful in CI)
GITHUB_TOKEN=ghp_... git-scrub ...

# Via flag
git-scrub --token ghp_... ...

If neither is provided, git-scrub calls gh auth token automatically.


Options

Flag Description
--old-email Email to find (required)
--new-email Replacement email (required with --fix)
--org GitHub org to scan. Repeatable.
--user GitHub username to scan all their repos. Repeatable.
--repo Specific owner/repo to target. Repeatable.
--branch Branch to scan (default: each repo's default branch)
--fix Rewrite history and force-push
--dry-run Explicit scan-only mode (already the default)
--yes / -y Skip per-repo confirmation prompts
--json Output results as JSON
--token GitHub token (or set GITHUB_TOKEN)
-V / --version Print version and exit

Notes

  • Dry-run is the default. Nothing is written without --fix.
  • Both author and committer email fields are checked and rewritten.
  • The scan checks each repo's default branch (or --branch). git filter-repo rewrites all branches and tags when fixing, so the full history is cleaned regardless.
  • Force-pushing rewrites history for all collaborators on a repo — coordinate with your team before running on shared repos.
  • GitHub's commit attribution UI may take a short time to update after a push.

License

MIT

Metadata

Release files for git-scrub 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for git-scrub 0.1.1
File Size Uploaded
git_scrub-0.1.1.tar.gz 9.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for git-scrub 0.1.1
File Interpreter ABI Platform
git_scrub-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 19.6 kB

Release files / git_scrub-0.1.1.tar.gz

Download URL git_scrub-0.1.1.tar.gz
Size 9.3 kB
Tags Source
SHA-256 checksum
How to use checksums
92645bd10a5ff99338689bb6fcbc0da0b4d3555ce80e5dbc51ca5274deabf99b
BLAKE2b-256 checksum
How to use checksums
791944ccafedc582ef6777ca14373a7a7b11b3e86c59ab57c9248f836b263b55
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 28, 2026.

Transparency log

Release files / git_scrub-0.1.1-py3-none-any.whl

Download URL git_scrub-0.1.1-py3-none-any.whl
Size 10.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e24a408f14e9e03a794394bacbf4a355671381a97dedbdd63d3babec003bec31
BLAKE2b-256 checksum
How to use checksums
0d965f5dbd99dc6eeaec5158802f881734cd07cf098de60fe8349de0165ae920
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 28, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page