Skip to content
safegit scrub
Edit
On this page

surgically rewrite git history to remove or replace sensitive content: file and match rewrite the commits, trees and blobs of a range the caller selects (--from or --entire-history), run applies a recipe of such operations in one coordinated pass, and verify only reads -- it confirms that the patterns named on its command line are absent from the whole object store

#safegit scrub

surgically rewrite git history to remove or replace sensitive content: file and match rewrite the commits, trees and blobs of a range the caller selects (--from or --entire-history), run applies a recipe of such operations in one coordinated pass, and verify only reads -- it confirms that the patterns named on its command line are absent from the whole object store

#scrub file

replace or remove a specific file across every commit in a SELECTED RANGE of history -- --from or --entire-history, one of which is required -- rewriting each affected commit tree to either substitute the file's contents with those of a sanitized file or delete it entirely from every snapshot in that range. A --delete also removes the move records naming that path, whole, since the path they refer to is being erased; a --replace-with edits no message, because the path still exists and a record naming it is still true

Effect: mutating · consequential (prompts before running; --approve-consequential skips)

#Flags

Flags
NameShortTypePresenceEnvDescription
--reasonstrrequiredmandatory audit trail message explaining why this scrub operation is needed
--remap-shas-inlist[str] (unique)optionalglob selecting files whose full 40-character commit hashes are remapped to the rewritten SHAs during the walk, keeping hash-referencing files like JSONL changelogs self-consistent at every commit (repeatable; same matching semantics as --scope; not applied inside submodule histories)
modechoicerequiredSelection (not typed as a flag). Elect exactly one of --delete, --replace-with. what happens to the file at every commit in range
    --deleterequiredElects mode = delete. delete the file from every commit in range
    --replace-withstrrequiredElects mode = replace-with. replace the file's contents with those of a sanitized file Its value: path to the file whose contents replace the target in every commit; resolved against YOUR current directory, unlike the target argument, which is repository-relative
rangechoicerequiredSelection (not typed as a flag). Elect exactly one of --from, --entire-history. how much of the history is rewritten
    --fromstrrequiredElects range = from. rewrite the commits from a given commit forward Its value: first commit hash to include when rewriting history
    --entire-historyrequiredElects range = entire-history. rewrite every commit from the root of the repository to HEAD

#Arguments

Arguments
NameTypePresenceDescription
filestrrequiredrepository-relative path to the file that should be scrubbed from history

#scrub match

replace every occurrence of a regex pattern in the blobs, commit messages and tag annotations of a SELECTED RANGE of history -- --from or --entire-history, one of which is required -- rewriting commit trees so that sensitive values like secrets and credentials are removed from every snapshot in that range. A move record is rewritten as a record rather than as text: the substitution applies to the decoded paths and the pair is re-encoded, so the output always parses, a pattern written against the escaped spelling matches nothing, and a substitution whose result would no longer be a move is refused before any ref moves

Effect: mutating · consequential (prompts before running; --approve-consequential skips)

#Flags

Flags
NameShortTypePresenceEnvDescription
--patternstrrequiredregular expression pattern to search for across all blobs in history
--reasonstrrequiredmandatory audit trail message explaining why this scrub operation is needed
--scopestroptionalglob pattern limiting which file paths are searched (e.g. '.env', 'config/*')
--remap-shas-inlist[str] (unique)optionalglob selecting files whose full 40-character commit hashes are remapped to the rewritten SHAs during the walk, keeping hash-referencing files like JSONL changelogs self-consistent at every commit (repeatable; same matching semantics as --scope; not applied inside submodule histories)
substitutionchoicerequiredSelection (not typed as a flag). Elect exactly one of --replace, --mangle. what replaces each match
    --replacestrrequiredElects substitution = replace. substitute a literal string for every match Its value: literal string to substitute for each regex match found in history
    --manglerequiredElects substitution = mangle. substitute random printable ASCII of the same length for every match
rangechoicerequiredSelection (not typed as a flag). Elect exactly one of --from, --entire-history. how much of the history is rewritten
    --fromstrrequiredElects range = from. rewrite the commits from a given commit forward Its value: first commit hash to include when rewriting history
    --entire-historyrequiredElects range = entire-history. rewrite every commit from the root of the repository to HEAD

#scrub run

execute a multi-operation scrub recipe from a TOML file, applying all pattern replacements and file removals across history in a single coordinated pass with topological commit ordering, overlap detection between operations, and automatic verification that no matched content survives in the rewritten object store — use --diff to preview all changes as unified diffs before committing to the rewrite

Effect: mutating · consequential (prompts before running; --approve-consequential skips)

#Flags

Flags
NameShortTypePresenceEnvDescription
--reasonstrrequiredmandatory audit trail message explaining why this scrub operation is needed
--diff, --no-diffbooloptionalpreview what would change without modifying any objects, showing unified diffs; omitted means the rewrite is performed
--limitintoptionalmaximum number of blob diffs to show in --diff mode; omitted means 50
--remap-shas-inlist[str] (unique)optionalglob selecting files whose full 40-character commit hashes are remapped to the rewritten SHAs during the walk, keeping hash-referencing files like JSONL changelogs self-consistent at every commit (repeatable; same matching semantics as --scope; not applied inside submodule histories)
rangechoicerequiredSelection (not typed as a flag). Elect exactly one of --from, --entire-history. how much of the history is rewritten
    --fromstrrequiredElects range = from. rewrite the commits from a given commit forward Its value: first commit hash to include when rewriting history
    --entire-historyrequiredElects range = entire-history. rewrite every commit from the root of the repository to HEAD

#Arguments

Arguments
NameTypePresenceDescription
recipestrrequiredpath to the TOML recipe file containing scrub operations

#scrub verify

confirm that the patterns named on the command line -- repeatable --pattern regexes, the operations of a scrub recipe file, or both -- are absent from every object in the git object store, scanning blobs, commit messages, and tag annotations and reporting detailed per-pattern pass or fail results with match locations for any violations found

Effect: read_only

#Flags

Flags
NameShortTypePresenceEnvDescription
--patternlist[str] (unique)optionalregular expression that must be absent from every object in the repository (repeatable)
--scopestroptionalglob pattern limiting which blob file paths a --pattern match counts against (e.g. '.env', 'config/*'); recipe operations carry their own scope in the recipe file

#Arguments

Arguments
NameTypePresenceDescription
recipestroptionalpath to a scrub recipe TOML file whose operations' patterns are verified; the format is the one 'scrub run' takes, and its replace/mangle/depends_on fields are ignored here because verification substitutes nothing

#Constraints

The framework enforces these before the command runs.

Constraints
RuleWhat it requires
verify-inputAt least one of --pattern (when supplied), recipe (when supplied).
verify-scope--scope requires --pattern.

More tools from this site

  • claudestream Drive Claude Code from Python: run it as a subprocess and read its output as typed events, with async and sync sessions, sandbox policies, and tools you define in Python
  • claudewheel A TUI Claude Code Launcher that lets you have more than one profile, manage sessions lifecycle, pick the exact CC version, model to use (even older unlisted ones), pick which GitHub account to use, etc.
  • dirstat Fast, single-binary directory statistics CLI: every file under a tree grouped by format, with counts, sizes, and lines of code, as a colored terminal table or as JSON
  • fastware A batteries-included ASGI framework: msgspec JSON, a managed Granian server, dependency injection, SSE, WebSockets, auth, and a test client
  • go-toml-edit Zero-dep TOML editing library for Go with comment preservation
  • howmuchleft The fastest Claude Code statusline: context window, 5-hour, and weekly limit usage as three customizable gradient bars, rendering in about 6 ms
  • orxtra
  • pgdesign
  • predraw Declarative rendering pipeline: describe a scene in JSON and get SVG, PNG and WebP out, with light and dark style tokens, reusable components and text converted to path outlines
  • reposummary Turn a git repository's history into a Markdown journal: pick a time window or revision range and get a readable digest of what changed, optionally narrated by an LLM
  • rlsbl Release orchestration and project scaffolding CLI that bumps versions, validates a structured JSONL changelog, tags only the commit CI verified, and publishes to npm, PyPI, Go and more
  • saferm Command-line replacement for rm that archives every deletion with a mandatory reason and the context it ran in, so deleted files can be listed, inspected and restored
  • selfdoc Static Site Generator that builds a project's documentation site directly from its source code, so the docs can never drift from the code they describe, with SEO/AEO, first-class blog, search, and cross-project linking built in
  • strictcli
  • stricttest An always-on test-isolation floor: a pytest plugin and a Go env-hygiene module that make a test suite structurally unable to reach real credentials, the real HOME, the network, or the development repository.
  • wesktop A Python framework that turns an ASGI web app into a desktop application, serving it from a local Granian server and displaying it in a native OS window via pywebview
Search