At the beginning I'd like to thank ElpieKay, who posted core functions of my solutions, which I've only automatized.
So, finally I have script I wanted to have. I divided it into pieces which depend on each other and can serve as independent scripts. It looks like this:
censorStringsInWholeGitHistory.sh:
#!/bin/bash
#arguments are strings to censore
for string in "$@"
do
echo ""
echo "================ Censoring string "$string": ================"
~/replaceStringInWholeGitHistory.sh "$string" "********"
done
usage:
~/censorStringsInWholeGitHistory.sh "my_password1" "my_password2" "some_f_word"
replaceStringInWholeGitHistory.sh:
#!/bin/bash
# $1 - string to find
# $2 - string to replace with
for branch in $(git branch | cut -c 3-); do
echo ""
echo ">>> Replacing strings in branch $branch:"
echo ""
~/replaceStringInBranch.sh "$branch" "$1" "$2"
done
usage:
~/replaceStringInWholeGitHistory.sh "my_password" "********"
replaceStringInBranch.sh:
#!/bin/bash
# $1 - branch
# $2 - string to find
# $3 - string to replace with
git checkout $1
for file in $(~/findFilesContainingStringInBranch.sh "$2"); do
echo " Filtering file $file:"
~/changeStringsInFileInCurrentBranch.sh "$file" "$2" "$3"
done
usage:
~/replaceStringInBranch.sh master "my_password" "********"
findFilesContainingStringInBranch.sh:
#!/bin/bash
# $1 - string to find
# $2 - branch name or nothing (current branch in that case)
git log -S "$1" $2 --name-only --pretty=format: -- | sort -u
usage:
~/findFilesContainingStringInBranch.sh "my_password" master
changeStringsInFileInCurrentBranch.sh:
#!/bin/bash
# $1 - file name
# $2 - string to find
# $3 - string to replace
git filter-branch -f --tree-filter "if [ -f $1 ];then sed -i s/$2/$3/g $1;fi"
usage:
~/changeStringsInFileInCurrentBranch.sh "abc.txt" "my_password" "********"
I have all those scripts located in my home folder, what is necessary for proper working in this version. I'm not sure that's the best option, but for now I cannot find better one. Of course every script has to be executable, what we can achieve with chmod +x ~/myscript.sh
.
Probably my script is not optimal, for big repos it will process very long, but it works :)
And, at the very end, we can push our censored repo to any remote with:
git push <remote> -f --all
Edit: important hint from ElpieKay:
Don't forget to delete and recreate tags that you have pushed. They
are still pointing to the old commits that may contain your password.
Maybe I'll improve my script in future to do this automatically.