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
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