我被带到版本控制一个以前没有版本控制的项目。
没想到,我将所有文件添加到存储库,并在我开始处理它时立即开始跟踪它。
现在存储库非常庞大,太大而无法推送到git hub。所以我开始删除所有过多的文件,并使用git filter-branch使用此命令从历史记录中消除它们。
sudo git log --all --pretty=format: --name-only --diff-filter=D | sort -u | while read -r line; do sudo git filter-branch -f --tree-filter "rm -rf { $line }" HEAD; done
问题?有太多过多的文件,这就是救世主在它完成之前可能会回来的,并且我需要快速地将其发送到github。
所以加快这个过程,我看到我可以在孤儿分支中提交最新的文件
git checkout --orphan <new-branch-name>
所以,为了让我感动,我喜欢做的就是将这个提交推送到github,继续运行清理操作,然后在完成后再将两个分支重新组合在一起。
以这种方式
1-----10
1a------Xa (1a = 10)
变为
1-----10-1a------Xa
或者可能
1------10------Xa
因此,最终我们保存所有历史。
这可能吗?我在时间紧迫的情况下,并不想失去一切。
答案 0 :(得分:2)
如所描述的那样是不可能的,因为提交的ID(&#34;真实姓名&#34;)是其哈希校验和,其包括其所有历史记录。因此,在两个分支上包含这五个提交的repo中:
A--B--C--D <-- with-big-files
D' <-- cleaned
你可以推送任何一个分支,但你永远不能让D'
拥有像前一个任何其他提交一样的东西。 D'
是根提交,并且始终是根提交。
可以做的是,例如,添加此cleaned2
分支:
A--B--C--D <-- with-big-files
D' <-- cleaned
A'-B'-C' <-- cleaned2
然后合并:
A--B--C--D <-- with-big-files
D'---------E <-- cleaned
/
A'-B'-C' <-- cleaned2
然后丢弃名称 cleaned2
。 (如果您愿意,cleaned2
可以包含D''
,其中包含D
和/或D'
的副本,但C'
为其父级。)
请注意,无论您使用的是git filter-branch
还是BFG,还是使用这种手动方法,您最终得到的都是原始提交的一堆副本,您已经在副本中的大文件。
编辑:这不是问题的答案,但我想我应该添加这个旁注。您已将filter-branch识别为太慢,但现在正在解决另一个问题,而不是简单地加速过滤器分支。
首先,您使用git filter-branch
(--tree-filter
)的过滤器是最慢的方法。以--index-filter
执行每个删除操作的速度要快得多(尽管仍然不是非常快速)。
其次,实际上更重要的是,您不应该使用一个完全复制存储库中每个提交的传递来删除每个文件,而应该一个传递存储库中的每个提交以删除所有这些文件(仍然使用索引过滤器,以避免将每个提交复制到工作树)。
驱动所有这一切的关键是git filter-branch
的工作方式,我在上面提到过。在Git中更改提交是不可能的,因此像所有Git命令一样,filter-branch
不会。它只是似乎,并且看起来似乎某些提交被更改,Git 将提交到 new >提交,然后隐藏原件并假装副本是原件。
运行git filter-branch HEAD
次复制可从HEAD
到达的每次提交。我不知道您的存储库中有多少提交,但是我们可以说从HEAD
可以访问150个提交,并删除20个文件。您每次删除一个文件,因此首先复制150个提交以删除文件A.然后复制150个提交(减去文件A的提交)以删除文件B.然后复制150个提交(减去A和B)删除文件C,依此类推。这意味着你要制作150 x 20 = 3000份。
使用--index-filter
(使用git rm --cached --ignore-unmatch
)会使3000份副本的运行速度比使用--tree-filter
快几个数量级。一次删除所有文件将生成150份副本。如果每次改进都将时间减少到原始的1/20,那么同时进行两次改进会将其减少到大约1/400。