Skip to main content
RunBook Academy

Git, CI/CD & GitOpsXXXVI · Git History RewritingTools

BFG Repo-Cleaner — the fast credential scrubber

Advanced⏱ ~22 mingitbfgjava

What you'll learn

  • Install BFG Repo-Cleaner as a single Java JAR
  • Run bfg --replace-text <file> to substitute strings across every blob
  • Run bfg --delete-files <glob> to remove a file pattern from every commit
  • Run bfg --strip-blobs-bigger-than <size> to remove blobs over a threshold
  • Recognise when BFG is the right tool versus filter-repo

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

BFG Repo-Cleaner is a Java tool focused on the credential-scrub use case. It is faster than filter-repo because it walks the object store directly and lets the commit graph follow; it cannot run callbacks or mailmap.

Why BFG exists

For very large repositories the general-purpose parsing in filter-repo is the slow part. The credential scrub itself is just a string match against blob contents. BFG drops the commit-graph parsing and optimises for the string-match path:

flowchart LR
    A["rewrite needed"] --> B{"general or blob-only?"}
    B -->|"general (callbacks, mailmap)"| C["filter-repo"]
    B -->|"blob-only, large repo"| D["BFG"]
    C --> E["reflog expire + gc"]
    D --> E
    E --> F["force-push --force-with-lease"]

Install

BFG is a single Java JAR (JRE 8+):

curl -O https://repo1.maven.org/maven2/com/madgp/bfg/1.14.0/bfg-1.14.0.jar
mv bfg-1.14.0.jar /usr/local/bin/bfg.jar
alias bfg='java -jar /usr/local/bin/bfg.jar'

—replace-text

The primary BFG use case. The file is a list of strings to replace with ***REMOVED***:

bfg --replace-text passwords.txt

Every blob is scanned; every match becomes ***REMOVED***; the commit graph follows automatically. Right when the credential is scattered across many files. BFG does not support the literal->replacement syntax that filter-repo does; every match becomes the same token.

—delete-files

Remove every blob whose path matches a glob:

bfg --delete-files '*.{env,key,pem}'

Right when the sensitive file has a recognisable extension or naming pattern.

—strip-blobs-bigger-than

Remove every blob over a size threshold (the accidentally- committed large file: a database dump, node_modules, a test fixture):

bfg --strip-blobs-bigger-than 100M

The threshold is a number with a unit suffix (K, M, G). Right for hygiene (repository size, clone time) rather than credentials. For credential-bearing large files, use --replace-text or --delete-files so the audit log names the specific object removed.

—no-blob-protection

BFG by default leaves the most recent commit’s blobs alone (“blob protection”). --no-blob-protection rewrites every blob including those in the latest commit. Right when the credential is in the latest commit and the team is certain the rewrite should reach it; wrong when the latest commit might be the one the engineer forgot to scrub.

When to use BFG versus filter-repo

  • BFG: large repo, blob-only rewrite, common credential patterns, large files. Fastest path for bulk text and bulk blobs.
  • filter-repo: callback logic, mailmap, conditional substitution, identity correction.

Both produce the same shape of rewritten history; both require the same reflog-and-gc cleanup; both require the same --force-with-lease push.

Production discipline

  1. BFG runs on a bare clone; filter-repo on a regular clone. The difference is the working tree.
  2. Same safety contract as filter-repo: fresh clone, reflog expire, gc, --force-with-lease.
  3. Verify before pushing. git log -S'<literal>' should print nothing; git log --diff-filter=D --name-only | grep <pattern> should list only the removed paths.

Cross-course references

  • Linux for Production Sysadmins - Part XXXIV (ConfigMgmt) covers the file-system hygiene that --strip-blobs-bigger-than mirrors.
  • Ansible for Production Sysadmins - Part XXXVII (RepoArch) covers the repository layout that benefits from the bulk-blob rewrite.
  • Terraform for Production Sysadmins - Parts IX-XII (State) cover the state-file size that --strip-blobs-bigger-than is sometimes used against.

Quiz

Knowledge check · 4 questions

  1. Q1. Which mode is the primary BFG Repo-Cleaner use case for credential scrubbing?

  2. Q2. BFG Repo-Cleaner runs on a regular (non-bare) working clone like git filter-repo does.

  3. Q3. Name the three primary BFG modes used in infrastructure work and what each one is for.

  4. Q4. A team runs bfg --replace-text passwords.txt and reports the rewrite completed but a secret scanner still fires. Diagnose the failure.

    Time T0: team runs bfg --replace-text passwords.txt on a bare clone. Time T0+10m: team force-pushes with --force-with-lease after reflog expire and gc. Time T0+30m: secret scanner fires on commit a3f9d2. The commit message contains the credential verbatim - passwords.txt did not list the literal that appeared in the commit message.

Passing score: 75%. Answers are checked in this browser.