5

我正在尝试使用 git filter-branch 功能替换 git 存储库中的文本数据。

我编写了一个简单的脚本来搜索各种术语并替换它们。它运行得非常缓慢。我执行了多行 BASH 代码来自定义我的搜索结果和替换操作。我知道我的代码效率不高。我决定继续尝试我的第一条线路,这应该是半有效的。浏览代码库仍然需要很长时间。

是否可以使用 BASH 或其他简单方法来搜索我的文件并并行执行查找和替换操作以加快速度?

如果没有,关于如何更好地处理这个问题还有其他建议吗?

这是我正在执行的 Git 命令:

git filter-branch --tree-filter "sh /home/kurtis/.bin/redact.sh || true" \
    -- --all

这是我的命令实际上正在执行的代码:

find . -not -name "*.sql" -not -name "*.tsv" -not -name "*.class" \
    -type f -exec sed -i 's/01dPassw0rd\!/HIDDENPASSWORD/g' {} \;
4

5 回答 5

4

git filter-branch 不能并行处理提交,因为它需要知道父提交的哈希(id)来计算当前哈希。

但是您可以加快每个提交的处理速度:

您的代码对每个文件执行 sed。那很慢。改用这个:

find . -not -name "*.sql" -not -name "*.tsv" -not -name "*.class" \
       -type f -print0 \
  | xargs -0 sed -i 's/01dPassw0rd\!/HIDDENPASSWORD/g'

此版本与您的版本完全相同,但 sed 使用尽可能多的文件(参数)执行。Find 的“-print0”和 xargs 的“-0”表示“用零字节分隔文件名”。所以当文件名包含空格、换行、二进制垃圾等时没有问题。

于 2013-01-30T22:24:45.400 回答
3

使用 GNU Parallel,您可以在每个 CPU 上并行化:

find . -not -name "*.sql" -not -name "*.tsv" -not -name "*.class" \
   -type f -print0 |
parallel -q -0 sed -i 's/01dPassw0rd\!/HIDDENPASSWORD/g'

了解更多:https ://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

于 2013-02-03T15:18:46.670 回答
1

我发现这个问题很有趣,所以我玩了一下,并分享了这个部分工作的脚本。我最初的方法有点错误,但它可能会更快(呃)。

我试图通过在每次提交中搜索修改后的文件来提高性能,其中修改包含要替换为的字符串git log -Sstring。但是我忘记了如果我只更改那些,那么修改将出现在下一次提交中,所以我不得不多次运行脚本,但它不会检查所有文件只是修改,因此多次运行可能会更快你的版本,但我不确定如果什么都不做,过滤器分支需要多少时间。

您也许可以使用它的一部分,也许首先使用git log -S.... 你可以通过使用xargsbeforesed而不是for循环来改进它,但是在开发时我更喜欢这种形式。我不知道如何正确地发现父母,这就是为什么我这样做并且必须单独处理初始提交案例。

无论如何,我也是在这里学习的,所以如果您找到解决此问题的好方法,请分享:)

#!/bin/bash

commit=$1
pattern=$2
replace=$3

function replaceall() {
  for f in `git log -S$pattern --pretty="format:" --name-only $1 | egrep -v '.sql$|.class$|.tsv$'`; do
    echo "FILE $f"
    sed -i "s/$pattern/$replace/g" $f
  done
}

parents=`git log --pretty=%P -n 1 $commit`
if test -z "$parents"; then
  echo "ROOT"
  replaceall $commit
else
  for p in $parents; do
    echo "PARENT $p"
    replaceall $p..$commit
  done
fi

用法:git filter-branch -f --tree-filter '/path/to/script.sh $commit 01dPassw0rd\! HIDDENPASSWORD' -- --all

我认为脚本不应该在你的 git 工作目录中,因为树过滤器会添加它在重写时找到的所有内容,但我不确定这一点。

于 2013-01-31T19:22:17.740 回答
1

您需要BFG Repo-Cleaner,它是在 JVM 中运行的更快、更简单的替代方案,git-filter-branch并且明确设计用于从 Git 存储库中删除私有数据。它是多线程的,并针对您所描述的任务进行了优化。它通常比你快 10-50 倍git-filter-branch- 你的 repo 越大,它就越快。

下载 Java jar,创建一个private.txt列出要删除的密码等的文件(每行一个条目),然后运行以下命令:

$ java -jar bfg.jar  --replace-text private.txt  my-repo.git

将扫描您的存储库历史中阈值大小(默认为 1MB)的所有文件,并且任何匹配的字符串(不在您最近的提交中)将被替换为字符串“***REMOVED***”。然后,您可以使用git gc清除死数据:

$ git gc --prune=now --aggressive
于 2013-02-02T23:17:41.007 回答
0

递归文本替换的一些基准(来源

0.131411 sec  find-xargs-sd.sh

0.323906 sec  find-xargsparallel-sed.sh
0.326623 sec  find-xargs-sed.sh
0.397934 sec  find-xargs-perl.sh

4.53739 sec  find-exec-sed.sh

10.3247 sec  parallel-sed.sh
于 2022-01-10T15:27:52.353 回答