如何替换git历史文件中的文本?

Tom*_*Tom 35 git version-control substitution git-filter-branch git-rewrite-history

我一直使用基于接口的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
Run Code Online (Sandbox Code Playgroud)

我试过这个,不幸的是注意到密码确实发生了变化,所有二进制文件都被破坏了.图像等都会被破坏.

有没有更好的方法来做到这一点,不会破坏我的二进制文件?

谢谢.

编辑:

我搞砸了什么.导致二进制文件损坏的实际代码是:

$ git filter-branch --tree-filter "find . -type f -exec sed -i -e 's/originalpassword/newpassword/g' {} \;"
Run Code Online (Sandbox Code Playgroud)

顶部的代码实际上使用我的密码奇怪地删除了所有文件.

Rob*_*ley 83

我建议使用BFG Repo-Cleaner,这是一种更简单,更快速的替代方案,git-filter-branch专门用于重写Git历史记录中的文件.

您应该仔细按照以下步骤操作:https://rtyley.github.io/bfg-repo-cleaner/#usage - 但核心位是这样的:下载BFG的jar(需要Java 7或更高版本)并运行此命令:

$ java -jar bfg.jar  --replace-text replacements.txt -fi *.php  my-repo.git
Run Code Online (Sandbox Code Playgroud)

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

将扫描整个存储库历史记录,并且.php文件(大小不超过1MB)将执行替换:将替换任何匹配的字符串(不在最近的提交中).

完全披露:我是BFG Repo-Cleaner的作者.

  • 如果上面的例子在BFG网站上列出,那就太棒了!我不得不再次谷歌这个问题来找到它们. (4认同)
  • unbelieveable!BFG太棒了! (3认同)
  • 谢谢@Bane - 非常高兴它有所帮助,并感谢您支持该项目! (2认同)

jwe*_*ich 36

您可以通过传递-name "pattern"来避免触及不需要的文件find.

这对我有用:

git filter-branch --tree-filter "find . -name '*.php' -exec sed -i -e \
    's/originalpassword/newpassword/g' {} \;"
Run Code Online (Sandbox Code Playgroud)


Von*_*onC 12

在 Git 2.24(2019 年第四季度)中,git filter-branch(和 BFG)已弃用

等效的将是, using newren/git-filter-repo,及其示例部分

cd repo
git filter-repo --path-glob '*.txt' --replace-text expressions.txt
Run Code Online (Sandbox Code Playgroud)

expressions.txt

literal:originalpassword==>newpassword
Run Code Online (Sandbox Code Playgroud)

正如Hasturkun评论中添加的那样

使用--path-glob(或--path)导致git filter-branch只保留匹配的文件这些规范
仅替换特定文件中的文本的功能在 bfg-ish as-filint-historyscript 中可用。
否则,目前看来这只能通过自定义提交回调实现。
newren/git-filter-repo第 74 期

这是有道理的,考虑到该--replace-text选项本身就是一个blob 回调

  • 使用“--path-glob”(或“--path”)会导致“git filter-branch”仅保留与这些规范匹配的文件。仅替换特定文件中文本的功能可在“bfg-ish”中作为“-fi”或“lint-history”脚本使用。否则,目前看来这只能通过自定义提交回调来实现。另请参阅 https://github.com/newren/git-filter-repo/issues/74 (4认同)
  • 我在一个仓库上尝试了这个,结果是一个只有一次提交的仓库,并且只有 --path-glob 中提到的文件。我预计我的存储库中的许多提交仍然存在,并且与 glob 不匹配的文件未受影响。 (2认同)

Nay*_*Nay 6

我在/usr/local/git/findsed.sh创建了一个文件,其中包含以下内容:

find . -name 'githubDirToSubmodule.sh' -exec sed -i '' -e 's/What I want to remove//g' {} \;
Run Code Online (Sandbox Code Playgroud)

我跑了命令:

git filter-branch --tree-filter "sh /usr/local/git/findsed.sh"
Run Code Online (Sandbox Code Playgroud)

命令说明

运行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'与该文件中的任何内容都不匹配,但会在最后添加一个换行符.因此,我只是告诉find忽略所有其他文件,而不是解决这个问题.

其他有效的命令

另外,我发现这些命令在findsed.sh文件中工作(一次只能有一个命令,而不是多个命令,所以注释#the others out):

find . -name '.publishNewZenPackFromGithub.sh.swp' -exec rm -f {} \;
find . -name '*' -exec grep -H PassToRemove {} \;
Run Code Online (Sandbox Code Playgroud)

请享用!


Cir*_*四事件 6

更多信息:git-filter-repo

/sf/answers/4077651861/提供了基础知识,这里有一些更多信息。

安装

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

使用技巧

这是我倾向于使用的更常见的方法:

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

在哪里:

  • Bash 进程替换允许我们不创建文件来进行简单替换。如果您的 shell 不支持此功能,您只需将其写入文件即可:

    echo 'my_password==>xxxxxxxx' > tmp
    git filter-repo --replace-text tmp HEAD
    
    Run Code Online (Sandbox Code Playgroud)
  • HEAD使其仅影响当前分支

仅修改一系列提交

如何使用 git filter-repo 仅修改一系列提交而不是整个分支历史记录?

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

使用 Python API 替换

对于更复杂的替换,您可以使用Python API,请参阅:如何使用 git filter-repo 作为具有Python模块接口的库?