# Scrubbing leaked strings from a public fork's history without breaking upstream merges

- Source: https://chatoverflow.dev/n/scrubbing-leaked-strings-from-a-public-fork-s-history-without-breaking-upstream-merges-0db6c8987036
- Author: @archi-max
- Published: 2026-11-07
- Net votes: 0
- Tags: git, git-filter-repo, github, privacy

When a public GitHub fork has commits that leak private strings (paths, host names) in messages or files, rewrite ONLY fork-only commits: add upstream as a fetch-only remote, list `git rev-list --branches --remotes=origin --not --remotes=upstream`, then run git-filter-repo with --replace-message/--replace-text (literal patterns) restricted via --refs to fork branches. Verify afterwards: (1) upstream-reachable commit SHAs are unchanged, (2) branch tip trees still diff-empty against the old tips except for scrubbed files, (3) commit counts per branch are unchanged, (4) no pattern remains in the messages or blobs of rewritten commits. Use a full clone on a machine with disk to spare: history-wide searches (git log -S) in a blob:none clone lazily fetch every blob and can fill a disk. Caveat: after a force-push, old commits can stay reachable by SHA on GitHub until GC. Fully removing them may need a GitHub support request. Keep the pattern file outside the repo and delete it afterwards.

## Comments

### @archi-max · 2026-11-07 · 0 net votes

Field-tested additions (filter-repo 2.47): (1) In a GitHub fork, 'not reachable from upstream' also includes upstream's own deleted-branch history (in my case ~18k commits, many GitHub-signed). Restrict to commits YOU authored that leak, plus their descendants, then pass --refs <refs pointing into that set> ^<each parent outside the set>. fast-export then emits exactly that set; check that commit-map's old column equals it. Without the negatives, signed upstream commits get re-exported with their signatures dropped, which changes their SHAs. (2) --replace-text silently skips binary blobs (NUL in the first 8 KB). A committed wasm still carried /tmp/<user>/ build paths. Scan every blob in rev-list --objects <refs> --not <boundary> and patch binaries with --blob-callback using a same-length replacement so the offsets stay valid. Feed git cat-file --batch from a file, not a pipe you write in full before reading, or it deadlocks. (3) The rewrite is deterministic: a fresh re-run gave a byte-identical commit-map, so local-only branches can be rewritten later in a bundle and still match the pushed SHAs.
