【问题标题】:How to use git filter-branch on pattern of folders如何在文件夹模式上使用 git filter-branch
【发布时间】:2019-12-28 04:32:33
【问题描述】:

我已经向我的本地存储库提交了一堆尚未发布的敏感数据。

敏感数据分散在项目的不同文件夹中,我想从 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. 或者我应该用 bash 做一些循环。

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

【问题讨论】:

  • 你似乎需要一个完整的脚本,而不是单行脚本,你可以在其中做任何你想做的事情。
  • 所以* 在这种情况下不会展开?
  • 我不知道,但即使是这样,如果有很多文件夹,您的命令行可能会太长。这种方法最初是错误的。
  • 地址是相对的,因此不会比您在命令中看到的三个级别更深。

标签: bash git git-filter-branch


【解决方案1】:

您的命令在运行时首先由您的 shell 评估。所以:

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

单引号保护整个事物不受外壳的影响,并将其作为--index-filter 传递给--index-filter 以供以后使用。此时单引号已消失。

问题出在:git filter-branch 的过滤器在过滤时被 另一个 shell 评估(技术上,运行 git filter-branch 的 shell 本身)。这另一个 shell evals 命令:

eval $filter

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

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

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

如果扩展成功,会发生一件事;如果没有,就会发生其他事情。具体发生什么取决于 shell(bash 可以配置为以几种不同的方式运行;POSIX sh 更可预测)。

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

您可以使用以下方法从等式中取出一些变量:

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

以便第二个 shell 看到:

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

这将强制第二个 shell 通过:

javascript/*/.sensitiveData

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

【讨论】:

  • 感谢@torek 的详尽回答。我逃脱了星号 \* 并没有帮助。我还按照您的建议运行了命令git ls-tree -r javascript/*/.sensitiveData,并收到以下错误fatal: Not a valid object name javascript/folder1/.sensitiveData,这似乎表明这里的模式至少是有效的。有什么想法吗?
  • git ls-tree -r 需要一个 提交哈希 ID 参数。这里的想法是查看您希望从中删除这些文件的提交之一,以确保 javascript/*/.sensitiveData 应该匹配所有文件。因此,假设您想要删除的文件的提交之一是a123456;使用git ls-tree -r a123456 并观察输出。
  • 感谢@torek 我刚刚使用了另一种使用 bash 的解决方案(并在此过程中学习了一些 bash)。这是一个简单的for in,但效果很好。已经从你的回答中学到了很多。将检查git ls-tree。再次感谢:D
【解决方案2】:

最后,解决我的问题的是一个使用 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

【讨论】:

    猜你喜欢
    • 2012-08-16
    • 2012-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-29
    • 2020-07-22
    • 1970-01-01
    相关资源
    最近更新 更多