我一直使用基于接口的git客户端(smartGit),因此对git控制台没有多少经验。
但是,我现在需要在历史记录中替换所有.txt文件中的字符串(因此,不要删除整个文件而只是替换字符串)。我找到了以下命令:
git filter-branch --tree-filter 'git ls-files -z "*.php" |xargs -0 perl -p -i -e "s#(PASSWORD1|PASSWORD2|PASSWORD3)#xXxXxXxXxXx#g"' -- --all
我试过这个,不幸的是注意到密码确实发生了变化,所有二进制文件都被破坏了。图像等都会被破坏。
有没有更好的方法来做到这一点,不会破坏我的二进制文件?
感谢。
修改
我混淆了什么。导致二进制文件损坏的实际代码是:$ git filter-branch --tree-filter "find . -type f -exec sed -i -e 's/originalpassword/newpassword/g' {} \;"
顶部的代码实际上删除了所有文件,我的密码非常奇怪。
答案 0 :(得分:71)
我建议使用BFG Repo-Cleaner,这是git-filter-branch
的一种更简单,更快捷的替代方案,专门用于从Git历史记录中重写文件。
您应该在这里仔细按照以下步骤操作:https://rtyley.github.io/bfg-repo-cleaner/#usage - 但核心位是这样的:下载BFG's jar(需要Java 7或更高版本)并运行此命令:
$ java -jar bfg.jar --replace-text replacements.txt -fi *.php my-repo.git
replacements.txt
文件应包含您要执行的所有替换,格式如下(每行一个条目 - 请注意不应包含注释):
PASSWORD1 # Replace literal string 'PASSWORD1' with '***REMOVED***' (default)
PASSWORD2==>examplePass # replace with 'examplePass' instead
PASSWORD3==> # replace with the empty string
regex:password=\w+==>password= # Replace, using a regex
regex:\r(\n)==>$1 # Replace Windows newlines with Unix newlines
将扫描整个存储库历史记录,.php
文件(大小不超过1MB)将执行替换:任何匹配的字符串(不在最新提交中)将被替换。
完全披露:我是BFG Repo-Cleaner的作者。
答案 1 :(得分:32)
您可以将-name "pattern"
传递给find
。
这对我有用:
git filter-branch --tree-filter "find . -name '*.php' -exec sed -i -e \
's/originalpassword/newpassword/g' {} \;"
答案 2 :(得分:5)
我在/usr/local/git/findsed.sh创建了一个文件,其中包含以下内容:
find . -name 'githubDirToSubmodule.sh' -exec sed -i '' -e 's/What I want to remove//g' {} \;
我跑了命令:
git filter-branch --tree-filter "sh /usr/local/git/findsed.sh"
命令说明
运行git filter-branch时,会逐个查看您提交的每个修订版本。 --tree-filter在每个已提交的修订版上运行findsed.sh脚本,保存它,然后进入下一个修订版。
find命令查找特定文件或文件集,并在该文件上执行(-exec)sed编辑器。 sed是一个在s /之后接受正则表达式的命令,并用/和/ g之间的字符串替换它(在我的例子中为空)。 {}是对find命令给出的文件路径的引用。文件路径被送到sed,因此sed知道要处理什么。 \;只需结束-exec命令。
将shell脚本和命令分隔成单独的部分,可以减少引号''或“”的复杂性。
<强>特殊性强>
我在mac上成功实现了这个,显然sed是mac上特定的(较旧的?)版本。这很重要,因为它有时表现不同。确保做sed -i''或者它在文件的末尾添加了“-e”,认为这就是我想要命名我的备份文件。 -i''说不要制作备份文件,只需编辑文件就行了,不需要备份文件。
指定-name'filename.sh'帮助我避免了另一个我无法解决的问题。还有另一个带.sh的文件,该文件没有换行符结束。 sed由于某种原因,尽管's / blah / blah / g'与该文件中的任何内容都不匹配,但会在最后添加一个换行符。因此,我只是告诉发现忽略所有其他文件,而不是解决这个问题。
有效的其他命令
此外,我发现这些命令可以在findsed.sh文件中工作(一次只能使用一个命令,而不是多个命令,所以注释#其他命令):
find . -name '.publishNewZenPackFromGithub.sh.swp' -exec rm -f {} \;
find . -name '*' -exec grep -H PassToRemove {} \;
享受!
答案 3 :(得分:1)
可能是shell扩展问题。如果filter-branch在评估命令时丢失"*.php"
周围的引号,则它可能会扩展为空,因此git ls-files -z
列出所有文件。
您可以检查过滤器分支源或尝试不同的引用技巧,但我要做的只是创建一个单行shell脚本来执行树过滤并改为传递该脚本。
答案 4 :(得分:1)
使用Git 2.24(2019年第四季度),git filter-branch
(and BFG) is deprecated。
相当于使用newren/git-filter-repo
及其example section:
cd repo
git filter-repo --path-glob '*.txt' --replace-text expressions.txt
与expressions.txt
:
literal:originalpassword=>newpassword
答案 5 :(得分:1)
有关git-filter-repo
的更多信息
https://stackoverflow.com/a/58252169/895245提供了基本知识,这里有一些更多信息。
安装
从git 2.5开始,至少它没有与主线git一起提供,因此:https://superuser.com/questions/1563034/how-do-you-install-git-filter-repo/1589985#1589985
python3 -m pip install --user git-filter-repo
使用技巧
这是我倾向于使用的更常见的方法:
git filter-repo --replace-text <(echo 'my_password==>xxxxxxxx') HEAD
其中:
HEAD
使其仅影响当前分支仅修改一系列提交
How to modify only a range of commits with git filter-repo instead of the entire branch history?
git filter-repo --replace-text <(echo 'my_password==>xxxxxxxx') HEAD
使用Python API替换
有关更复杂的替换,您可以使用Python API,请参见:How to use git filter-repo as a library with the Python module interface?