【问题标题】:How to substitute words in Git history & properly debug related problems?如何替换 Git 历史中的单词并正确调试相关问题?
【发布时间】:2013-11-21 03:49:59
【问题描述】:

我正在尝试从我的 Git 历史记录中删除敏感数据,例如密码。而不是删除整个文件,我只想用removedSensitiveInfo 替换密码。这是我在浏览了许多 StackOverflow 主题和其他网站后得出的结论。

git filter-branch --tree-filter "find . -type f -exec sed -Ei '' -e 's/(aSecretPassword1|aSecretPassword2|aSecretPassword3)/removedSensitiveInfo/g' {} \;"

当我运行这个命令时,它似乎正在重写历史记录(它显示了它正在重写的提交并且需要几分钟)。但是,当我检查所有敏感数据是否确实已被删除时,结果发现它仍然存在。

作为参考,这是我进行检查的方式

git grep aSecretPassword1 $(git rev-list --all)

这显示了与搜索查询匹配的所有数百个提交。没有任何东西被替换。

知道这里发生了什么吗?

我仔细检查了我正在使用的正则表达式,它似乎是正确的。我不确定还要检查什么或如何正确调试它,因为我的 Git 知识非常初级。例如,我不知道如何测试 1) 我的正则表达式是否不匹配任何内容,2) sed 没有在所有文件上运行,3) 文件更改没有被保存,或者 4) 其他东西。

非常感谢任何帮助。

附: 我知道有关此主题的几个 StackOverflow 线程。但是,我找不到关于在所有(ASCII)文件(而不是指定特定文件或文件类型)中替换单词(而不是删除文件)的方法。不确定这是否应该有所作为,但所有建议的解决方案都不适用于我。

【问题讨论】:

  • 您不能简单地从代码库中删除对您密码的所有引用并更改密码吗?换句话说,你首先应该解决在你的代码库中有这样的密码的问题。如果您将它们从代码库中取出,然后更改密码,您在乎旧密码是否仍然存在于历史记录中?
  • 理论上可以,但在我的情况下不实用。

标签: regex git replace sed git-filter-branch


【解决方案1】:

看起来不错。请记住,filter-branch 保留 refs/original/ 下的原始提交,例如:

$ git commit -m 'add secret password, oops!'
[master edaf467] add secret password, oops!
 1 file changed, 4 insertions(+)
 create mode 100644 secret
$ git filter-branch --tree-filter "find . -type f -exec sed -Ei '' -e 's/(aSecretPassword1|aSecretPassword2|aSecretPassword3)/removedSensitiveInfo/g' {} \;"
Rewrite edaf467960ade97ea03162ec89f11cae7c256e3d (2/2)
Ref 'refs/heads/master' was rewritten

然后:

$ git grep aSecretPassword `git rev-list --all`
edaf467960ade97ea03162ec89f11cae7c256e3d:secret:aSecretPassword2

但是:

$ git lola
* e530e69 (HEAD, master) add secret password, oops!
| * edaf467 (refs/original/refs/heads/master) add secret password, oops!
|/  
* 7624023 Initial

(git lola 是我的别名 git log --graph --oneline --decorate --all)。是的,它在那里,但在 refs/original 名称空间下。清除它:

$ rm -rf .git/refs/original
$ git reflog expire --expire=now --all
$ git gc
Counting objects: 6, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), done.
Total 6 (delta 0), reused 0 (delta 0)

然后:

$ git grep aSecretPassword `git rev-list --all`
$ 

(与往常一样,在 repo 的副本上运行 filter-branch 以防万一;然后删除原始 refs,使 reflog “现在”到期,并且 gc'ing 意味着东西真的消失了)。

【讨论】:

  • 我完全按照您的指示进行操作,但问题仍然存在。关于如何以一种我可以找出问题所在的方式进行调试的任何建议?我开始觉得正则表达式不正确匹配,即使它是一个非常基本的。
  • 您可能还会有标签或其他引用挂在“预过滤”提交上。查找git grep 找到了哪些提交,并查看哪些引用导致了它们。您还可以检查有问题的修订版(甚至在使用 filter-branch 之前)并尝试手动 find ... 以确保 sed 对相关文件执行您想要的操作。
  • 是的,关于还有其他标签/引用,您可能是对的。我认为命令也会过滤它们,但显然我错了。最后,我选择了 Roberto 的 BFG 解决方案,它完美无缺。
【解决方案2】:

git-filter-branch 是一个功能强大但难以使用的工具 - 要正确使用它来完成您的任务,您需要了解几件晦涩的事情,每件事情都可能导致您遇到问题正在看。因此,与其立即尝试调试它们,不如退后一步,看看原来的问题:

  • 在所有文本文件中替换给定的字符串(即密码)(不指定特定的文件/文件类型)
  • 确保更新后的 Git 历史记录不包含旧密码文本
  • 尽可能简单地执行上述操作

这个问题有一个量身定制的解决方案:

使用 BFG...而不是 git-filter-branch

BFG Repo-Cleaner 是 git-filter-branch 的更简单替代品专门设计用于从 Git 存储库历史记录中删除密码和其他不需要的数据。

BFG 在这种情况下帮助您的方式:

  • BFG 为 10-720x faster
  • 它会自动在 所有 标记和引用上运行,unlike git-filter-branch - 只有在添加了非凡的 --tag-name-filter cat -- --all 命令行选项时才会这样做(请注意,示例您在问题中给出的命令没有这个,这可能是您的问题的原因)
  • BFG 不生成任何 refs/original/ 引用 - 因此您无需执行额外的步骤来删除它们
  • 您可以将密码表示为简单的文字字符串,而不必担心得到regex-escaping right。如果您真的需要,BFG 也可以处理正则表达式。

使用 BFG

仔细遵循usage steps - 核心位只是这个命令:

$ java -jar bfg.jar  --replace-text replacements.txt  my-repo.git

replacements.txt 文件应包含您想要执行的所有替换,格式如下(每行一个条目 - 请注意不应包含 cmets):

PASSWORD1 # Replace literal string 'PASSWORD1' with '***REMOVED***' (default)
PASSWORD2==>examplePass         # replace with 'examplePass' instead
PASSWORD3==>                    # replace with the empty string
regex:password=\w+==>password=  # Replace, using a regex

将扫描您的整个存储库历史记录,并且所有文本文件(大小小于 1MB)都将执行替换:任何匹配的字符串(不在您的 latest 提交中)都将被替换.

全面披露:我是 BFG Repo-Cleaner 的作者。

【讨论】:

  • 很好 - 运行良好...另外,我从未见过运行时打印政治信息的 OSS 项目。
  • 嘿@Roberto,请帮忙!在我完成步骤(最后是 git push)以替换我的 git repo 历史中的密码(它们不再在当前版本中 - 在上游/fork 中,仅在历史中),并创建一个 PR - 我看到很多PR 中不相关的更改 - 它试图更新其他文件(没有密码)。这是预期的还是我遗漏了一些东西(我不想将此 PR 与这么多更改合并)。它不应该只更新所需的文件(其中密码替换为 REMOVED,我遵循了这个rtyley.github.io/bfg-repo-cleaner
  • @Roberto - 只是想添加更多细节,$ bfg --replace-text passwords.txt my-repo.git 之后的结果看起来不错,因为它只显示那些有密码的文件。但是在 git push 和创建 PR 之后 - 它显示地狱PR 中的许多其他文件,包括 Readme.md 文件。在我为所有密码和其他几个存储库执行此操作之前,我正在尝试做一个快速 POC,期待获得帮助!
猜你喜欢
  • 2011-09-04
  • 2020-04-18
  • 2017-12-29
  • 2017-02-23
  • 2017-08-17
  • 2013-05-05
  • 1970-01-01
  • 2019-02-21
  • 1970-01-01
相关资源
最近更新 更多