如何在文件夹模式上使用 git 过滤器分支



我已经将一堆敏感数据提交到我的本地存储库中,但尚未发布。

敏感数据分散在项目中的不同文件夹中,我想从 git 历史记录中完全删除所有这些。

所有相关文件夹具有相同的名称,并且位于不同文件夹的目录中的同一级别。以下是我的文件夹结构示例:

root
folder1
./sensitiveData
folder2
./sensitiveData
folder3
./sensitiveData

使用以下命令,我能够一次删除一个包含敏感数据的文件夹:

git filter-branch -f --index-filter 'git rm -r --cached --ignore-unmatch javascript/folder1/.sensitiveData' --prune-empty HEAD

但是我想一次性删除所有包含敏感数据的文件夹,因为它们太多了,我想了解它是如何工作的。

但是使用以下命令,不会重写任何内容,并且警告我'refs/heads/master' is unchanged不变:

git filter-branch -f --index-filter 'git rm -r --cached --ignore-unmatch javascript/*/.sensitiveData' --prune-empty HEAD

在我看来,有两种策略:

  1. 要么我的模式有些错误,我需要改变它。
  2. 或者我应该做一些循环

如果可能的话,选项一似乎更明智。

当你运行命令时,你的命令首先由你的 shell 计算。 所以有了:

'git rm -r --cached --ignore-unmatch javascript/*/.sensitiveData'

单引号保护整个东西免受外壳的影响,并将其作为稍后使用的--index-filter传递给git filter-branch。 此时单引号已消失。

问题是:提供给git filter-branch的过滤器在过滤时由另一个 shell(从技术上讲,运行git filter-branch本身的 shell(进行评估。 另一个外壳eval命令:

eval $filter

所以现在第二个外壳重新解释:

git rm -r --cached --ignore-unmatch javascript/*/.sensitiveData

它分解空格处的参数,根据当前工作目录扩展星号,并根据扩展结果调用git rm -r --cached --ignore-unmatched

如果扩张成功,就会发生一件事;如果没有,就会发生其他事情。 确切地说,发生的事情取决于 shell(bash 可以配置为以几种不同的方式运行;POSIXsh更可预测(。

--index-filter的实际当前工作目录通常为空,因此扩展可能会失败。在大多数情况下,这应该将星号原封不动地传递给 Git。 由于git rm的参数(主要是/本质上(是一个路径规范,Git 现在将进行自己的扩展。 这应该已经起作用了,所以要么路径本身是错误的,要么目录不为空,要么你的 shell 有一些奇怪的东西,以至于失败的扩展没有将文字文本javascript/*/.sensitiveData传递给git rm

您可以使用以下命令从此等式中取出一些变量:

'git rm -r --cached --ignore-unmatch javascript/*/.sensitiveData'

以便第二个外壳看到:

git rm -r --cached --ignore-unmatch javascript/*/.sensitiveData

这将强制第二个外壳通过:

javascript/*/.sensitiveData

直接到git rm。 不过,鉴于这可能无论如何都应该有效,因此检查javascript/*/.sensitiveData是否与特定提交中的正确文件匹配是很有趣的,您可以在这些提交中使用git ls-tree -r笨拙/手动地执行此操作。

最后,解决我问题的是一个使用for in结构的小 bash 脚本。

for name in javascript/*/.sensitiveData
do git filter-branch -f --index-filter "git rm -r --cached --ignore-unmatch $name" --prune-empty HEAD
done

最新更新