无法使用bash脚本从git历史记录中删除文件

时间:2015-04-16 19:13:38

标签: git bash sh git-bash

我写的这个bash脚本有问题。我正在尝试应用this procedure from Github documentation的第3步从我们的git历史记录中删除存储库历史记录中的所有文件。例如,如果.gitignore忽略.txt,我想从历史记录中删除所有.txt。等等。每个.gitignore行。

我可以在示例文件中使用通配符。所以我可以运行以下命令删除所有.txt文件:

git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch *.txt' --prune-empty --tag-name-filter cat -- --all

所以我尝试制作一个bash脚本来做同样的事情。

我制作了一个简单的.gitignore文件来测试它,如下所示:

#foo
*.txt
*.docx

我的shell脚本如下所示:

#!/bin/bash

s1="#"
str1="'git rm --cached --ignore-unmatch "
str2="'"

cat .gitignore | while read line
do
    if [[ $line == *"$s1"* ]]
    then
        echo #skip
    else
        str3=$str1$line$str2
        git filter-branch --force --index-filter $str3 --prune-empty --tag-name-filter cat -- --all
    fi
done

但是,这会产生以下输出:

fatal: bad revision 'rm'
fatal: bad revision 'rm'

(.gitignore文件的每一行一次)

我做错了什么?

1 个答案:

答案 0 :(得分:7)

我相信这可能会做你想要的。

#!/bin/bash

cat .gitignore | while read line
do
    if [[ $line == *#* ]]
    then
        echo #skip
    else
        git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch '"$line" --prune-empty --tag-name-filter cat -- --all
    fi
done

我避免了所有那些只是复杂事情的无意义的中间变量。 (虽然从str1删除单引号并删除str2可能已经足够了,但就我而言,这是更加理智。)

过滤器只需要是一个字符串,但是你如何构造该字符串取决于你。

您也可以从gitignore收集所有模式,并且只运行一次filter-branch(此时也不需要--force)。

#!/bin/bash

patts=()
while read -r line
do
    if [[ $line != *#* ]]; then
        patts+=("$line")
    fi
done < .gitignore

git filter-branch --index-filter 'git rm --cached --ignore-unmatch '"${patts[*]}" --prune-empty --tag-name-filter cat -- --all

另请注意,您可能应该确定此处仅处理简单模式,因为rm.gitignore对模式的理解并不完全相同,我不认为