如何修剪我的回购历史的特定部分以消除膨胀
How to prune a specific part of my repo's history to eliminate bloat
我试图使用 this GitHub help page 中描述的技术从我们公司 Git 存储库的一些旧提交中删除一些敏感信息。使用 filter-branch,我能够根据自己的喜好修改 repo 的历史记录。
不幸的是,我犯了一个错误,从原点做了 pull
并在回购上做了一些进一步的工作。通过这样做,我相信我已经有效地将原始 'tainted' 存储库 (A) 与我的 'fixed' 存储库 (B) 合并,因为提交对象的数量已从 3000 翻倍到 6000。
现在,我可以 运行 filter-branch 再次执行并强制推送来修复我所拥有的,但是 repo 仍然 'bloated' 将其大小加倍。
我大致知道合并发生的位置,但不知道确切的提交。我希望能够识别并证明哪个提交是罪魁祸首,然后永久删除提交树 A。我有一些关于如何完成的潜在想法...
- 修改将 A 与 B 连接起来的特定提交,然后 运行ning 一个 p运行e 以垃圾收集其下的所有内容
- 通过从历史记录中完全删除该提交并稍后在 p运行e
之后复制它
- 重新定位到 repo B 头部的最后一次提交,并挑选它上面的所有内容,除了我与 A 合并的那一个(不过不确定挑选是否会把整个提交树拉回来!)
我欢迎所有建议!
modifying that specific commit that joins A with B
你确实不能这样做。但是您可以做一些可能同样好或足够好的事情:您可以制作该提交的 copy,但在提交副本之前,使其仅引用 B-side parent,而不是 A-side parent 和您要删除的旧历史记录。
一旦你复制了 那个 提交,你还必须复制它的直接 children。新副本将与原件相同,只是它们指的是副本,而不是原件。
当然,在复制了那些children之后,您现在必须复制它们的 children。新副本将引用其他新副本。这会一直重复,直到您到达最近的提交。
基本上,那么,您需要做的就是再次运行 git filter-branch
。这次的过滤器是:当您到达连接 A 和 B 的特定提交时,制作一个不这样做的副本。 复制所有其他提交 "as is"。 filter-branch 命令知道从第一个更改开始替换为新的 parent。当复制较早的提交时(那些在 A 面,以及在这个错误之前出现在 B 面的那些),"copies" 将 bit-for-bit 与原件相同,因此 filter-branch 将结束 re-using 原创.
最终结果将是就好像你已经改变了那个特定的提交,除了它和它的所有后代将是新的提交。然后,您可以将此存储库克隆到一个根本不引用 side-A 提交的新克隆,并且它们将不会被复制;或者你可以,正如你所建议的那样,将它们 p运行e 掉(但这出奇地困难,因为 Git 迫切希望避免丢失工作,即提交)。无论如何,一旦完成,您必须说服存储库的所有用户放弃他们以前的克隆并切换到这个新的 re-shrunken 存储库。
此时剩下的问题是如何说服 Git 更改那个特定提交的 parentage。有两种简单的方法可以做到这一点:
- 使用 "parent filter":请参阅 filter-branch 文档
- 首先使用
git replace
构建替换提交,然后使用 git filter-branch
使用替换进行存储库复制,然后丢弃替换,因为它现在已合并到复制的提交中。
后者更容易正确,因为如果你搞砸了,你可以简单地删除替换。但是,如果您了解所有这些,前者也不难做到正确,对于单个提交:只需编写一个 shell 形式的脚本片段:
[ $GIT_COMMIT = <hash> ] && echo "-p <B-parent-hash>" || cat
用作您的--parent-filter
。
幸运的是,我相信只需重复我原来的操作就可以解决问题,即 运行 filter-branch
在我的回购协议中再次清理了 'duplicate' 提交。
由于我的过滤过程只是从每次提交中删除特定文件,因此 运行 在我修改后的存储库 (B) 上再次使用相同的过滤器无效 (B' = B) 而 运行它在 repo A 中的提交导致与 B 相同的提交。
由于提交哈希是根据更改的内容及其祖先的哈希计算的,并且因为 A 和 B 中的祖先现在实际上是相同的,所以我最终在树的两侧得到了相同的提交哈希。 .. 因此重复项神奇地消失了!我的新存储库现在包含 3000 多个提交对象,和以前一样。
进一步阅读:
How does git assure that commit SHA keys for identical operations/data are still unique?
How to get the git commit count?
我试图使用 this GitHub help page 中描述的技术从我们公司 Git 存储库的一些旧提交中删除一些敏感信息。使用 filter-branch,我能够根据自己的喜好修改 repo 的历史记录。
不幸的是,我犯了一个错误,从原点做了 pull
并在回购上做了一些进一步的工作。通过这样做,我相信我已经有效地将原始 'tainted' 存储库 (A) 与我的 'fixed' 存储库 (B) 合并,因为提交对象的数量已从 3000 翻倍到 6000。
现在,我可以 运行 filter-branch 再次执行并强制推送来修复我所拥有的,但是 repo 仍然 'bloated' 将其大小加倍。
我大致知道合并发生的位置,但不知道确切的提交。我希望能够识别并证明哪个提交是罪魁祸首,然后永久删除提交树 A。我有一些关于如何完成的潜在想法...
- 修改将 A 与 B 连接起来的特定提交,然后 运行ning 一个 p运行e 以垃圾收集其下的所有内容
- 通过从历史记录中完全删除该提交并稍后在 p运行e 之后复制它
- 重新定位到 repo B 头部的最后一次提交,并挑选它上面的所有内容,除了我与 A 合并的那一个(不过不确定挑选是否会把整个提交树拉回来!)
我欢迎所有建议!
modifying that specific commit that joins A with B
你确实不能这样做。但是您可以做一些可能同样好或足够好的事情:您可以制作该提交的 copy,但在提交副本之前,使其仅引用 B-side parent,而不是 A-side parent 和您要删除的旧历史记录。
一旦你复制了 那个 提交,你还必须复制它的直接 children。新副本将与原件相同,只是它们指的是副本,而不是原件。
当然,在复制了那些children之后,您现在必须复制它们的 children。新副本将引用其他新副本。这会一直重复,直到您到达最近的提交。
基本上,那么,您需要做的就是再次运行 git filter-branch
。这次的过滤器是:当您到达连接 A 和 B 的特定提交时,制作一个不这样做的副本。 复制所有其他提交 "as is"。 filter-branch 命令知道从第一个更改开始替换为新的 parent。当复制较早的提交时(那些在 A 面,以及在这个错误之前出现在 B 面的那些),"copies" 将 bit-for-bit 与原件相同,因此 filter-branch 将结束 re-using 原创.
最终结果将是就好像你已经改变了那个特定的提交,除了它和它的所有后代将是新的提交。然后,您可以将此存储库克隆到一个根本不引用 side-A 提交的新克隆,并且它们将不会被复制;或者你可以,正如你所建议的那样,将它们 p运行e 掉(但这出奇地困难,因为 Git 迫切希望避免丢失工作,即提交)。无论如何,一旦完成,您必须说服存储库的所有用户放弃他们以前的克隆并切换到这个新的 re-shrunken 存储库。
此时剩下的问题是如何说服 Git 更改那个特定提交的 parentage。有两种简单的方法可以做到这一点:
- 使用 "parent filter":请参阅 filter-branch 文档
- 首先使用
git replace
构建替换提交,然后使用git filter-branch
使用替换进行存储库复制,然后丢弃替换,因为它现在已合并到复制的提交中。
后者更容易正确,因为如果你搞砸了,你可以简单地删除替换。但是,如果您了解所有这些,前者也不难做到正确,对于单个提交:只需编写一个 shell 形式的脚本片段:
[ $GIT_COMMIT = <hash> ] && echo "-p <B-parent-hash>" || cat
用作您的--parent-filter
。
幸运的是,我相信只需重复我原来的操作就可以解决问题,即 运行 filter-branch
在我的回购协议中再次清理了 'duplicate' 提交。
由于我的过滤过程只是从每次提交中删除特定文件,因此 运行 在我修改后的存储库 (B) 上再次使用相同的过滤器无效 (B' = B) 而 运行它在 repo A 中的提交导致与 B 相同的提交。
由于提交哈希是根据更改的内容及其祖先的哈希计算的,并且因为 A 和 B 中的祖先现在实际上是相同的,所以我最终在树的两侧得到了相同的提交哈希。 .. 因此重复项神奇地消失了!我的新存储库现在包含 3000 多个提交对象,和以前一样。
进一步阅读:
How does git assure that commit SHA keys for identical operations/data are still unique?
How to get the git commit count?