How to replace a string in a whole Git history?

git filter-repo --replace-text

Git 2.25 man git-filter-branch already clearly recommends using git filter-repo instead of git filter-tree, so here we go.

Install https://superuser.com/questions/1563034/how-do-you-install-git-filter-repo/1589985#1589985

python3 -m pip install --user git-filter-repo

and then use:

echo 'my_password==>xxxxxxxx' > replace.txt
git filter-repo --replace-text replace.txt

or equivalent with Bash magic:

git filter-repo --replace-text <(echo 'my_password==>xxxxxxxx')

Tested with this simple test repository: https://github.com/cirosantilli/test-git-filter-repository and replacement strings:

d1==>asdf
d2==>qwer

The above acts on all branches by default (so invasive!!!), to act only on selected branches use: git filter-repo: can it be used on a specific branch? e.g.:

--refs HEAD
--refs refs/heads/master

The option --replace-text option is documented at: https://github.com/newren/git-filter-repo/blob/7b3e714b94a6e5b9f478cb981c7f560ef3f36506/Documentation/git-filter-repo.txt#L155

--replace-text <expressions_file>::

A file with expressions that, if found, will be replaced. By default, each expression is treated as literal text, but regex: and glob: prefixes are supported. You can end the line with ==> and some replacement text to choose a replacement choice other than the default of ***REMOVED***.

Of course, once you've pushed a password publicly, it is always too late, and you will have to change the password, so I wouldn't even bother with the replace in this case: Remove sensitive files and their commits from Git history

Related: How to substitute text from files in git history?

Tested on git-filter-repo ac039ecc095d.


First, find all the files that could contain the password. Suppose the password is abc123 and the branch is master. You may need to exclude those files which have abc123 only as a normal string.

git log -S "abc123" master --name-only --pretty=format: | sort -u

Then replace "abc123" with "******". Suppose one of the files is foo/bar.txt.

git filter-branch --tree-filter "if [ -f foo/bar.txt ];then sed -i s/abc123/******/g foo/bar.txt;fi"

Finally, force push master to the remote repository if it exists.

git push origin -f master:master

I made a simple test and it worked but I'm not sure if it's okay with your case. You need to deal with all the files from all branches. As to the tags, you may have to delete all the old ones, and create new ones.

Tags:

Git

Bash

Replace