如何在Git历史中替换单词正确调试相关问题?

时间:2013-11-09 00:26:44

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

我正在尝试从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)其他东西。

非常感谢任何帮助。

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

2 个答案:

答案 0 :(得分:9)

git-filter-branch是一个功能强大但功能强大的工具 - 要正确使用它,您需要了解一些不起眼的事情,而且每一个都可能是你看到的问题。因此,不要立即尝试调试它们,让我们退一步看看原来的问题:

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

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

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

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

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

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

使用BFG

小心点击usage steps - 核心位只是这个命令:

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

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

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)都将执行替换:任何匹配的字符串(不在最新提交中)将被替换

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

答案 1 :(得分:2)

看起来不错。请记住,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 Just In Case的副本上运行filter-branch;然后删除原始引用,使reflog“现在”到期,并且gc'ing,意味着东西真的消失了。