如何在整个Git历史中替换字符串?

Kar*_*lak 6 git bash replace

我的一个密码在我的Git仓库中提交了很少的文件.是否有一些方法可以自动将整个历史记录中的其他字符串替换为此密码,以便没有它的痕迹?理想情况下,如果我可以编写简单的bash脚本接收字符串来查找和替换并完成整个工作本身,例如:

./replaceStringInWholeGitHistory.sh "my_password" "xxxxxxxx"
Run Code Online (Sandbox Code Playgroud)

编辑:这个问题与那个问题不重复,因为我要求在不删除整个文件的情况下替换字符串.

Cir*_*四事件 32

git filter-repo --replace-text

Git 2.25man 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
Run Code Online (Sandbox Code Playgroud)

然后使用:

echo 'my_password==>xxxxxxxx' > replace.txt
git filter-repo --replace-text replace.txt
Run Code Online (Sandbox Code Playgroud)

或与 Bash 魔法等效的内容:

git filter-repo --replace-text <(echo 'my_password==>xxxxxxxx')
Run Code Online (Sandbox Code Playgroud)

使用这个简单的测试存储库进行测试:https://github.com/cirosantilli/test-git-filter-repository和替换字符串:

d1==>asdf
d2==>qwer
Run Code Online (Sandbox Code Playgroud)

上面的内容默认作用于所有分支(如此具有侵入性!!!),仅作用于选定的分支,请使用:git filter-repo:它可以用于特定分支吗?例如:

--refs HEAD
--refs refs/heads/master
Run Code Online (Sandbox Code Playgroud)

并且仅对指定的提交范围进行操作,您可以:How to modify only a range of commits with git filter-repo而不是整个分支历史记录?

--refs HEAD~2..master
--refs HEAD~2..HEAD
Run Code Online (Sandbox Code Playgroud)

--replace-text选项记录在: https: //github.com/newren/git-filter-repo/blob/7b3e714b94a6e5b9f478cb981c7f560ef3f36506/Documentation/git-filter-repo.txt#L155

--replace-text <表达式文件>::

包含表达式的文件,如果找到,将被替换。默认情况下,每个表达式都被视为文字文本,但 支持regex:和前缀。glob:您可以使用==>一些替换文本来结束该行,以选择默认的替换选项***REMOVED***

如何在单个文件中替换:git-filter-repo 在单个文件中用表达式替换文本

当然,一旦你公开推送了密码,那就太晚了,你将不得不更改密码,所以在这种情况下我什至不会费心进行替换:从 Git 历史记录中删除敏感文件及其提交

相关:如何替换 git 历史记录中文件中的文本?

在 git-filter-repo ac039ecc095d 上测试。


Elp*_*Kay 10

首先,找到可能包含密码的所有文件.假设密码是abc123,分支是master.您可能需要排除那些abc123仅作为普通字符串的文件.

git log -S "abc123" master --name-only --pretty=format: | sort -u
Run Code Online (Sandbox Code Playgroud)

然后将"abc123"替换为"******".假设其中一个文件是foo/bar.txt.

git filter-branch --tree-filter "if [ -f foo/bar.txt ];then sed -i s/abc123/******/g foo/bar.txt;fi"
Run Code Online (Sandbox Code Playgroud)

最后,强制推master送到远程存储库(如果存在).

git push origin -f master:master
Run Code Online (Sandbox Code Playgroud)

我做了一个简单的测试并且它有效,但我不确定你的情况是否合适.您需要处理来自所有分支的所有文件.对于标签,您可能必须删除所有旧标签,并创建新标签.

  • @KarolSelak错误说你有一个名为`test`的ref和一个名为`test`的文件.这是一个命名冲突.如果你希望Git将`test`解释为ref,那么使用`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. (2认同)

Kar*_*lak 5

首先,我要感谢ElpieKay,他发布了我的解决方案的核心功能,我只是将其自动化。

所以,我终于有了我想要的剧本。我把它分成了相互依​​赖的部分,可以作为独立的脚本。它看起来像这样:

censorStringsInWholeGitHistory.sh:

#!/bin/bash
#arguments are strings to censore

for string in "$@"
do
  echo ""
  echo "================ Censoring string "$string": ================"
  ~/replaceStringInWholeGitHistory.sh "$string" "********"
done
Run Code Online (Sandbox Code Playgroud)

用法:

~/censorStringsInWholeGitHistory.sh "my_password1" "my_password2" "some_f_word"
Run Code Online (Sandbox Code Playgroud)

替换StringInWholeGitHistory.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
Run Code Online (Sandbox Code Playgroud)

用法:

~/replaceStringInWholeGitHistory.sh "my_password" "********"
Run Code Online (Sandbox Code Playgroud)

替换StringInBranch.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
Run Code Online (Sandbox Code Playgroud)

用法:

~/replaceStringInBranch.sh master "my_password" "********"
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

用法:

~/findFilesContainingStringInBranch.sh "my_password" master
Run Code Online (Sandbox Code Playgroud)

更改StringsInFileInCurrentBranch.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"
Run Code Online (Sandbox Code Playgroud)

用法:

~/changeStringsInFileInCurrentBranch.sh "abc.txt" "my_password" "********"
Run Code Online (Sandbox Code Playgroud)

我的主文件夹中包含所有这些脚本,这是在此版本中正常工作所必需的。我不确定这是最好的选择,但目前我找不到更好的选择。当然,每个脚本都必须是可执行的,我们可以使用chmod +x ~/myscript.sh.

可能我的脚本不是最佳的,对于大型存储库,它会处理很长时间,但它有效:)

最后,我们可以将经过审查的存储库推送到任何远程:

git push <remote> -f --all
Run Code Online (Sandbox Code Playgroud)

编辑: ElpieKay 的重要提示:

不要忘记删除并重新创建您已推送的标签。他们仍然指向可能包含您的密码的旧提交。

也许我将来会改进我的脚本以自动执行此操作。


归档时间:

查看次数:

1116 次

最近记录:

6 年,6 月 前