首页 > 解决方案 > 在 macOS 上使用树过滤器和 sed 从 Git 提交中删除敏感数据

问题描述

我尝试阅读多篇关于sed以及如何从已提交的文件中删除密钥的帖子。我正在尝试这个

git filter-branch --tree-filter \
"sed -i '' 's/my_sensitive_data/<your-api-key>/' ./app/src/main/java/com/demo/Test.kt"

我不断得到sed ./app/src/main/java/com/demo/Test.kt: No such file or directory。但如果我接受同样的命令

sed -i '' 's/my_sensitive_data/<your-api-key>/' ./app/src/main/java/com/demo/Test.kt

从我运行git filter-branch命令的目录中,该sed命令会适当地替换它。

我正在运行 macOS catalina 并使用 ZSH。我在这里可能做错了什么?

标签: gitmacossedzsh

解决方案


使用git filter-branch,Git 在每次提交时运行过滤器。1 即树过滤器:

  • 检查提交(在临时目录中);
  • 运行指定的命令(在那个临时目录中);和
  • 从该命令留下的任何内容构建替换提交。

filter-branch 命令对要复制的每个提交重复此操作。(这就是 filter-branch 所做的:它复制提交。原件继续存在。)

你的一些提交有文件;该sed命令将对这些提交起作用。您的某些提交缺少该文件,并且sed在这种情况下该命令失败。失败(git filter-branch被视为过滤命令的非零退出状态)会导致git filter-branch自身停止并且不执行您想要的过滤。

解决方案是避免sed在文件不存在时完全运行此命令。有两种方法可以做到这一点(见脚注 1),但最简单的是修改你的命令以首先检查。代替:

sed -i '' 's/my_sensitive_data/<your-api-key>/' ./app/src/main/java/com/demo/Test.kt

你会使用:

if [ -f app/src/main/java/com/demo/Test.kt ]; then
    sed -i '' 's/my_sensitive_data/<your-api-key>/' app/src/main/java/com/demo/Test.kt
fi

注意:如果你把它压缩成一行,它至少需要一个分号。我把它去掉了(也把它去掉了./,因为它是多余的)以使这些线条更适合发布目的。


1从技术上讲,它仅在您告诉它的提交上运行过滤器,这可能比每次提交都要少。将访问的提交是那些通过正引用显式或隐式命名的提交,不包括那些通过负引用显式或隐式命名的提交。这句话中有相当多的行话,值得将其拆解一下:

  • 肯定引用是前面没有否定的引用,也没有用于否定引用的各种特殊句法方法中的任何一种。这方面的简单示例包括feature(分支名称)、v2.1(标记名称)和a1234567(缩写的提交哈希)。

  • 否定引用是前面有否定的引用,或者用于否定的语法:^feature, ^v2.1, ^a1234567。对于否定语法的简单示例,请考虑master..feature:这完全等同于写作feature ^master

  • 该短语显式或隐式地指的是 Git 正在遍历提交图这一事实。有关这意味着什么的正确教程,请参阅Think Like (a) Git

命令行中提到的所有正面引用都会导致 Git 遍历提交图,标记要复制的提交。所有负面引用都会导致 Git 遍历图表,取消标记提交。如果您将过程视为“先标记,然后取消标记”,您会得到正确的结果:只有标记的提交会被复制和过滤。如果您将其视为“首先取消标记”,那么“标记之后”阶段必须尊重所有早期的“取消标记”。(Git 实际上以一种复杂的交错方式执行此操作,因此它总能得到正确的结果,但比简单的两遍算法更快。)

那些作为分支名称的正面引用会导致名称被记住。然后,Git 将所有标记的提交按适当的顺序排列——根据复制过程的需要进行拓扑排序——并开始复制。当它复制时,它会构建一个从旧哈希 ID 到新哈希 ID 的映射。在复制过程结束时,对于每个保存的分支名称,Git 强制名称指向新的哈希 ID 而不是旧的,过滤现在完成。

因此,如果有一个简单(或复杂!)的范围表达式让 Git仅枚举您需要复制和过滤的提交,您可以使用它,而不是在过滤器中进行测试。例如,假设敏感数据是专门在 commit 中引入的badf00d,其父级是cafedad:因此所有好的提交都可以到达cafedad,所有的提交都在以 开头badf00d并一直持续到master.

之前 的一些提交cafedad,可能还有cafedad自己的提交,缺少文件Test.kt,因此sed它们会失败。在这种情况下:

git filter-branch <filter-specifiers> -- cafedad..master

可以解决问题,因为这将复制和过滤限制为仅(a)具有文件和(b)需要编辑的那些提交。


推荐阅读