如何在保持尽可能多的历史的同时,从git的历史中清除一个词?

时间:2016-06-30 18:53:56

标签: git

  

TL; DR:我们的git存储库中有一个短语必须从历史中删除,而不仅仅是分支的头部。除了从开发和创建新存储库的头部中删除它之外还有哪些其他方法?我们希望保持尽可能多的历史。

背景

出于icky法律原因,我和我的团队必须从我们的代码库中删除所有单词的实例(我们称之为Voldemort只是为了娱乐和相关性)。令人讨厌的是,我们不仅要从分支机构的提示中删除Voldemort,我们必须将其从我们的存储库中的每次提交中删除(该诉讼是 >“没有开发人员能够合理地恢复到伏地魔在代码中的状态”

我们不再使用Voldemort,但代码中有一些地方仍然提到像评论一样。 (是的,作为法律诉讼的一部分,我们必须从我们的代码中删除侵权评论。)

最初的计划是清除不得提及的单词,然后创建一个新的存储库并将当前状态作为初始提交。我们不想失去我们所有的历史 1 !所以我们想知道是否有办法避免这种情况。

所以,问题是我们如何在尽可能多地保留历史 1 的同时从历史中删除Voldemort这个不可提及的词?另外,我们可以做些什么来确保它不在任何提交中?我们想知道如何检查我们的工作以确保它已经消失。

  

1:根据历史记录,我并不是指具体的提交,我只是想查看文件的历史记录,知道是谁做了什么,如果历史记录是对我没关系在git意义上的“重写历史”中,我实际上猜测它是唯一的方法。

有关回购状态的信息

  • 目前开发分支机构是免费的Voldemort,但我们在清除提交之前和之后都有“有意义的”提交
  • 可能只有初始提交有任何添加Voldemort 的行(因为我们从SVN迁移到git并且很久以前就添加了Voldemort)
  • 可能用Voldemort修改任何文件的唯一提交是删除它的那些(就像我说的那样,它是很老的东西)

猜测方法

似乎我们想要做git log --patch | grep 'Voldemort'之类的事情来查找添加Voldemort的提交,然后对编辑提交的所有内容进行交互式变更,其中添加了Voldemort以添加其他内容或根本不添加任何内容。

3 个答案:

答案 0 :(得分:2)

结帐git filter-branch Progress<T>

答案 1 :(得分:1)

使用BFG Repo CleanerArray#zip比[{1}}更快,更容易使用。

要在所有文件中使用文字git filter-branch替换所有出现的Voldemort,您只需:

*** REMOVED ***

答案 2 :(得分:0)

我感谢Ewan Mellor指出我正确的方向,但答案非常小,我认为这需要更多细节。

提醒

如果您在执行此操作之前对repo进行了新的克隆,请确保您拥有所有遥控器的本地分支(例如git checkout master; git checkout develop; git checkout feature/some-undone-feature等)。

我们做了什么

> git filter-branch --tree-filter "~/purge.sh" \
                    --msg-filter "sed -e 's/voldemort/<word removed due to lawsuit>/gI'" \
                    --tag-name-filter "cat" \
                    -- --all

清除脚本(可能是一行,但它更干净):

#!/bin/bash

files=$(grep -rli 'voldemort')

for file in ${files}; do
    sed -i -e 's/voldemort/<word removed due to lawsuit>/gI' ${file}
done

后续步骤

既然你已经完成了,你会想要检查这些问题:

  1. Remove refs/original/heads/master from git repo after filter-branch --tree-filter?:这会向您显示如何删除git filter-branch所做的备份。
  2. Listing and deleting Git commits that are under no branch (dangling?):这将确保您的本地仓库中没有任何坏词。在我们的案例中需要这样做,因为如果我们的笔记本电脑上有坏词,公司可能会被起诉和/或如果他们找到Voldemort软件,他们可能会执行远程擦除。您可能希望在远程仓库上运行此命令,但如果您不能,那么可能只需创建一个新的(具有略微不同的名称或URL以确保没有人错误地推送它或合并,撤消所有的辛勤工作!)
  3. 解释

    • --tree-filter "~/purge.sh"
      • 对于每次提交,针对工作树(~/purge.sh)运行--tree-filter ...脚本
        • 制作包含voldemortgrep ... 'voldemort'
        • 的文件列表
        • 从这里递归,列出名称(不是内容),而不考虑案例(-rli
        • 列表中的每个文件(for file in ${files}; do
          • 将该短语voldemort的每个实例替换为该文件中的<word removed due to lawsuit>sed ... -e s/.../.../ ${file}
          • 没有备份(-i
    • --msg-filter "sed -e 's/voldemort/<word removed due to lawsuit>/gI'"
      • voldemort替换单词短语<word removed due to lawsuit>的每个实例(sed -e s/.../.../
      • 即使一行中有两个而且不考虑案例(/gI
      • 提交消息中的
      • --msg-filter ...
    • --tag-name-filter "cat"
      • 对于每个代码,在新提交时将其重命名为旧名称(如果这不是现有代码,那么
    • -- --all
      • 为存储库中的每个提交执行此操作(是的,这是两个破折号,后跟一个空格,然后是另外两个破折号)

    关于性能的说明

    您可能想知道我们为什么不在sed -i -e 's/voldemort/<word removed due to lawsuit>/gI'中的每个文件上执行--tree-filter。原因是因为很多较慢。我认为因为它在每次提交中重写每个文件...即使不能命名的单词不在文件中。它加快了这个过程(至少10倍,可能是100倍,不想等待第一种方式完成),首先通过grep -rli 'voldemort'获取问题文件列表。