git-filter-branch删除字符串,但字符串包含$'\和其他字符

时间:2013-09-05 23:14:00

标签: git perl bash git-filter-branch git-rewrite-history

我正在尝试使用以下内容重写历史记录:

git filter-branch --tree-filter 'git ls-files -z "*.php" |xargs -0 perl -p -i -e "s#(PASSWORD1|PASSWORD2|PASSWORD3)#xXxXxXxXxXx#g"' -- --all

this tutorial中所述。

但是,我的密码字符串包含所有类型的非A-Z字符,例如$'和\,而不是上面例子中简单的'PASSWORD1'类型字符串。

有人可以解释一下我需要逃避什么吗?我无法在任何地方找到这个,而且我已经和它斗争了好几个小时。

4 个答案:

答案 0 :(得分:2)

尝试BFG而不是git filter-branch ...

如果您使用The BFG而不是git-filter-branch,则可以使用更友好的替换格式。创建一个passwords.txt文件,每行一个密码,如下所示:

PASSWORD1==>xXxXx      # Replace literal string 'PASSWORD1' with 'xXxXx'
ezxcdf\fr$sdd%==>xXxXx # ...all text is matched as a *literal* string by default

然后使用此命令run the BFG

$ java -jar bfg.jar -fi '*.php' --replace-text passwords.txt  my-repo.git

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

......不需要逃跑

请注意,解析BFG的唯一一点就是替换文件在这里拆分为“==>”字符串 - 在密码中可能不是 - 并且默认情况下,所有文本都按字面解释。

如果您想要更简洁,可以删除“==>”以及每行后面的所有内容(例如,只有一个密码文件)和默认情况下,BFG将使用字符串“***REMOVED***”替换每个密码。

BFG通常是hundreds of times faster,而不是在大型仓库上运行git-filter-branch,并且选项是围绕这两个常见用例量身定制的:

  • 删除疯狂大文件
  • 删除密码,凭据&其他私人数据

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

答案 1 :(得分:1)

konsolebox提供的精彩帮助的基础上,这真的帮助我解决了这个问题,我最终通过shell进行的解决方案是:

在文件中定义字符串strings.txt

string1
another$string
yet! @nother string
some more stuff to re\move

创建一个Perl脚本perl-escape-strings.pl,用于转义字符串,其中xXxXxXxXxXx是字符串,它们将全部替换为

#!/usr/bin/perl

use strict;
use warnings;

while (<>)
{
        chomp;
        my $passwd = quotemeta($_);
        print qq|s/$passwd/xXxXxXxXxXx/g;\n|;
}

exit 0;

Bash脚本:

# Pre-process the strings
./perl-escape-strings.pl strings.txt > strings-perl-escaped.txt

# Change directory to the repo
cd repo/

# Define the filter command
FILTER="git ls-files -z '*.html' '*.php' | xargs -0 perl -p -i ../strings-perl-escaped.txt"

# Run the filter
git filter-branch --tree-filter "$FILTER" -- --all

但是,由于字符串的数量很大,而且我的存储库很大并且提交了数千次,因此filter-branch方法需要很长时间。所以我将尝试同时在另一个答案中提到的BFG,看它是否更快完成。

答案 2 :(得分:0)

使用包装器脚本:

#!/bin/bash

readarray -t PASSWORDS < list_file

REPLACEMENT='xXxXxXxXxXx'
SEP=$'\xFF'

EXPR=${PASSWORDS[0]}
for (( I = 1; I < ${#PASSWORDS[@]}; ++I )); do
    EXPR+="|${PASSWORDS[I]}"
done
EXPR="s${SEP}(${EXPR})${SEP}$REPLACEMENT${SEP}g"
EXPR=${EXPR//'\'/'\\\\'}; EXPR=${EXPR//'$'/'\\\$'}
EXPR=${EXPR//'"'/'\"'};   EXPR=${EXPR//'`','\`'}
EXPR=${EXPR//'^','\\^'};  EXPR=${EXPR//'[','\\['}
EXPR=${EXPR//']','\\]'};  EXPR=${EXPR//'+','\\+'}
EXPR=${EXPR//'?','\\?'};  EXPR=${EXPR//'.','\\.'}
EXPR=${EXPR//'*','\\*'};  EXPR=${EXPR//'{','\\{'}
EXPR=${EXPR//'}','\\}'};  EXPR=${EXPR//'(','\\('}
EXPR=${EXPR//')','\\)'}

FILTER="git ls-files -z '*.php' | xargs -0 perl -p -i -e \"$EXPR\""

echo "Number of passwords: ${#PASSWORDS[@]}"    
echo "Passwords:" "${PASSWORDS[@]}"
echo "EXPR: $EXPR"
echo "FILTER: $FILTER"

git filter-branch --tree-filter "$FILTER" -- --all

答案 3 :(得分:0)

从内到外构建它。说密码是

a$b'c\d

正则表达式模式将是

a\$b'c\\d

perl命令的一种可能性是

perl -i -pe's/a\$b'\''c\\d/.../g'

(请注意每个'如何替换为'\''。)

现在您需要将其包含在单引号中,以便重复此过程。

... '... perl -i -pe'\''s/a\$b'\''\'\'''\''c\\d/.../g'\''' ...