我有一个密码已经提交到我的Git仓库中的几个文件中。是否有一种方法可以自动替换整个历史记录中的此密码为其他字符串,以便没有痕迹?理想情况下,如果我能编写一个简单的bash脚本来接收要查找和替换的字符串,并自行完成所有工作,类似于:
./replaceStringInWholeGitHistory.sh "my_password" "xxxxxxxx"
编辑:这个问题不是那个问题的重复,因为我询问的是如何替换字符串而不是删除整个文件。
我有一个密码已经提交到我的Git仓库中的几个文件中。是否有一种方法可以自动替换整个历史记录中的此密码为其他字符串,以便没有痕迹?理想情况下,如果我能编写一个简单的bash脚本来接收要查找和替换的字符串,并自行完成所有工作,类似于:
./replaceStringInWholeGitHistory.sh "my_password" "xxxxxxxx"
编辑:这个问题不是那个问题的重复,因为我询问的是如何替换字符串而不是删除整个文件。
git filter-repo --replace-text
Git 2.25的man git-filter-branch
已经明确建议使用git filter-repo
而不是git filter-tree
,所以我们就这么做吧。
安装https://superuser.com/questions/1563034/how-do-you-install-git-filter-repo/1589985#1589985
python3 -m pip install --user git-filter-repo
echo 'my_password==>xxxxxxxx' > replace.txt
git filter-repo --replace-text replace.txt
git filter-repo --replace-text <(echo 'my_password==>xxxxxxxx')
d1==>asdf
d2==>qwer
--refs HEAD
--refs refs/heads/master
仅对指定的提交范围进行操作,您可以使用 git filter-repo 来修改一系列提交,而不是整个分支历史记录。如何使用 git filter-repo 仅修改一系列提交,而不是整个分支历史记录?
--refs HEAD~2..master
--refs HEAD~2..HEAD
选项--replace-text
的文档位于:https://github.com/newren/git-filter-repo/blob/7b3e714b94a6e5b9f478cb981c7f560ef3f36506/Documentation/git-filter-repo.txt#L155
--replace-text <expressions_file>::
一个包含表达式的文件,如果找到,则将其替换。默认情况下,每个表达式都被视为文字文本,但支持
regex:
和glob:
前缀。您可以以==>
结尾并带有一些替换文本来选择除默认值***REMOVED***
之外的替换选项。
如何在单个文件中进行替换:git-filter-repo replace text by expression in a single file
当然,一旦你公开了一个密码,就已经太迟了,你将不得不更改密码,所以在这种情况下我甚至不会费心去替换它:从Git历史中删除敏感文件及其提交 相关链接:如何替换Git历史中的文本? 在git-filter-repo ac039ecc095d上进行了测试。首先,找到所有可能包含密码的文件。假设密码是abc123
,分支是master
。您可能需要排除那些仅将abc123
作为普通字符串的文件。
git log -S "abc123" master --name-only --pretty=format: | sort -u
然后将 "abc123" 替换为 "******"。假设其中一个文件是 foo/bar.txt
。
git filter-branch --tree-filter "if [ -f foo/bar.txt ];then sed -i s/abc123/******/g foo/bar.txt;fi"
如果远程仓库存在,最后强制推送master
分支到远程仓库。
git push origin -f master:master
我进行了一项简单的测试,它可以正常工作,但我不确定在你的情况下是否适用。您需要处理所有分支中的所有文件。至于标签,您可能需要删除所有旧标签并创建新标签。
git log -S "abc123" test --name-only --pretty=format: | sort -u
时,出现错误:fatal: ambiguous argument 'test': both revision and filename
。有没有什么办法可以避免这个错误? - Karol Selaktest
的引用和一个名为 test
的文件。这是一个命名冲突。如果你希望 Git 将 test
解释为引用,请使用 git log -S "abc123" test --name-only --pretty=format: -- | sort -u
。如果将其解释为文件,则使用 git log -S "abc123" --name-only --pretty=format: -- test | sort -u
。如果你需要两者都,请使用 git log -S "abc123" test --name-only --pretty=format: -- test | sort -u
。--
周围有空格。更多信息请参见 https://www.git-scm.com/docs/gitcli#_description。 - ElpieKay首先,我要感谢ElpieKay发布了我的解决方案的核心功能,我只是将其自动化了。
所以,最终我拥有了想要的脚本。我将它分成了相互依赖且可以作为独立脚本的片段。它看起来像这样:
#!/bin/bash
#arguments are strings to censore
for string in "$@"
do
echo ""
echo "================ Censoring string "$string": ================"
~/replaceStringInWholeGitHistory.sh "$string" "********"
done
使用方法:
~/censorStringsInWholeGitHistory.sh "my_password1" "my_password2" "some_f_word"
#!/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
使用方法:
~/replaceStringInWholeGitHistory.sh "my_password" "********"
#!/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
使用方法:
~/replaceStringInBranch.sh master "my_password" "********"
#!/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
用法:
~/findFilesContainingStringInBranch.sh "my_password" master
#!/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"
使用方法:
~/changeStringsInFileInCurrentBranch.sh "abc.txt" "my_password" "********"
chmod +x ~/myscript.sh
来实现。git push <remote> -f --all
编辑:来自ElpieKay的重要提示:
不要忘记删除并重新创建你已经推送过的标签。它们仍然指向可能包含密码的旧提交。
也许我将来会改进我的脚本,以自动执行此操作。