Git: BFG for removing secrets from entire git history

If you accidentally pushed a secret or password into a git repository, the BFG Repo-Clean utility is a convenient option for removing all traces of the secret from the entire git commit history.

It is also possible to use ‘git-filter-branch‘, but I find BFG more convenient and faster.

WARNING before performing administrative operations on a multi-user git repository, make sure you have a backup of all content and git history. [1,2,3]

Prerequisites

You must have a JVM on the machine where you will run the utility, and  download the jar from BFG page.

Removing secret from git commit history

Get a copy of the bare repository using a git command like below.  I’m using my test repository from github.

git clone --mirror https://github.com/fabianlee/bfgtest.git

This brings down the git records without any of the locally checkout files.  Then create a replacement file, which is just a text file containing the secrets to replace (one per line).  In our case, we are assuming a single phrase needs to be removed “mysecret”, from a file named “contains-secret.txt”.

# one directory 'up' from the repo directory, not inside it!
# text file specifying which words to hide
echo "mysecret" > secrets.txt

# use BFG to remove secrets, target a single file
java -jar ~/Downloads/bfg-1.14.0.jar --replace-text secrets.txt bfgtest.git

# use BFG to remove a single file
java -jar ~/Downloads/bfg-1.14.0.jar --delete-files mysecret.token bfgtest.git

The BFG output will direct you to run any commands it needs to finish the transformation.  Typically just this:

# go into repo directory
cd bfgtest.git

# run final command as directed by BFG output
git reflog expire --expire=now --all && git gc --prune=now --aggressive

# push changes to centralized remote repo
git push

Synchronize changes with other copies of repository

For other distributed copies of the repository, for example on other developer’s machines, you will need to request they do a pull with rebasing.

With a  decentralized source control system like git, if a user with their own local copy of the repository did a simple “git pull && git push”, this would result in the secret being reintroduced into the central repository.

Request other users run the following:

# if they have any local changes
git stash

# git pull with rebasing
git pull -r

# bring back any local changes
git stash pop

At this point, they are free to commit and push as normal.

 

 

REFERENCES

BFG documentation

BFG on github

git gc and aggressive

git-filter-repo is another utility option for rewriting history and deleting a secret

NOTES

OpenJDK11 used for this article

installing and using git-filter-repo to remove a secret [1]

# (if possible) first have everyone using do a commit and push
# this will make life much easier after history is rewritten

# install tool
sudo snap install --edge git-filter-repo

# get a fresh clone
mkdir cleaning && cd $_
git clone git@github.com:fabianlee/myrepo.git
git remote -v
cd myrepo/mypath
# do rewrite of history
git filter-repo --use-base-name --path mysecret --invert-paths

# set push origin back to original
git remote add origin git@github.com:fabianlee/myrepo.git
# push history back to github
git push --set-upstream origin main

# now for every client the best way is to get a fresh clone
# but you can also have them fetch and then rebase
git fetch
# do rebase, no interactive editor
GIT_SEQUENCE_EDITOR=: git rebase -i origin/main