我已经将一堆敏感数据提交到我的本地存储库中,但尚未发布。
敏感数据分散在项目中的不同文件夹中,我想从 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
在我看来,有两种策略:
- 要么我的模式有些错误,我需要改变它。
- 或者我应该做一些循环 。
如果可能的话,选项一似乎更明智。
当你运行命令时,你的命令首先由你的 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