如何修剪我的回购历史的特定部分以消除膨胀

时间:2017-10-13 15:45:54

标签: git git-branch git-filter-branch

我试图使用this GitHub help page中描述的技术从我们公司的Git repo上的一些旧提交中删除一些敏感信息。使用filter-branch,我能够根据自己的喜好修改repo的历史记录。

不幸的是,我做错了从原点做pull并在回购上做了一些进一步的工作。通过这样做,我相信我已经有效地将原来的'污染'回购(A)与我的'固定'回购(B)合并,因为提交对象的数量已经从3000增加到6000。

Visual explanation

现在,我可以再次运行filter-branch步骤并强制推送以修复我拥有的内容,但是repo仍然“膨胀”以使其大小加倍。

我大致知道合并发生的位置,但不知道精确的提交。我希望能够识别并证明哪个提交是罪魁祸首,然后永久删除提交树A.我有一些关于如何做到这一点的潜在想法......

  • 修改将A与B连接,然后运行修剪以对其下的所有内容进行垃圾收集的特定提交
  • 完全从历史记录中删除该提交,然后在修剪之后复制它
  • 重新定位回购B头上的最后一次提交并挑选它上面的所有内容,除了我与A合并的那个(不确定樱桃采摘是否会将整个提交树拉回来,但是!)

我欢迎所有建议!

2 个答案:

答案 0 :(得分:1)

  

修改使用B

连接A的特定提交

你真的不能这样做。但是你可以做一些可能同样好或者足够好的事情:你可以制作该提交的副本,但在提交副本之前,让它只引用B端父级,而不是A侧父母和您想删除的旧历史。

但是,复制 提交后,您还必须复制其直接子项。新副本将与原件相同,除非它们引用副本,而不是原件。

当然,复制这些孩子后,您现在必须复制他们的孩子。新副本将参考其他新副本。这会一直重复,直到您到达最近的提交。

基本上,您需要做的是再次运行git filter-branch。此次过滤器是:当您到达与B连接A的特定提交时,请创建一个不会执行该操作的副本。所有其他提交都会被复制"按原样#34 ;。 filter-branch命令知道从第一次更改开始替换新父项。当复制先前的提交(在A面上的那些,以及在B面前出现在这个错误之前的那些)时,"复制"将与原件一点一点地相同,因此filter-branch将最终重新使用原件。

最终结果将是,好像您已经更改了一个特定的提交,除了它及其所有后代将是 new 提交。然后,您可以将此存储库克隆到一个新的克隆,该克隆根本不会引用A方提交,并且它们将不会被复制通过;或者你可以按照你的建议将它们剪掉(但是这很难,因为Git拼命想避免失去工作,即承诺)。在任何情况下,一旦这是一个,您必须说服存储库的所有用户放弃他们以前的克隆并切换到这个新的重新收缩的存储库。

此时剩下的问题是你如何说服Git改变那个特定提交的父母。有两种简单(ish)方法可以做到这一点:

  • 使用"父过滤器":请参阅过滤器分支文档
  • 首先使用git replace构造替换提交,然后使用git filter-branch使用替换进行存储库复制,然后丢弃替换,因为它现在已合并到复制的提交中。 / LI>

后者更容易正确,因为如果你搞砸了,你可以简单地删除替换。但是,如果您了解所有这些,那么对于单个提交,前者也难以做到正确:只需编写表单的shell脚本片段:

[ $GIT_COMMIT = <hash> ] && echo "-p <B-parent-hash>" || cat

用作--parent-filter

答案 1 :(得分:0)

通过剪切运气,我相信简单地重复我原来的行动已经解决了这个问题,即在我的回购邮件上再次运行filter-branch已经清理了重复的问题&#39;提交。

由于我的过滤过程只是从每次提交中删除特定文件,因此在我修改的repo(B)上再次运行相同的过滤器没有效果(B&#39; = B),而在repo A中的提交上运行它在提交中与B相同。

由于提交哈希是由更改的内容和其祖先的哈希值计算的,并且因为A和B中的祖先现在实际上是相同的,所以我最终在树的两边都有相同的提交哈希值...因此副本神奇地消失了!我的新repo现在像以前一样包含超过3000个提交对象。

进一步阅读:

How does git assure that commit SHA keys for identical operations/data are still unique?

How to get the git commit count?