偶然发现Git文件夹非常大,使用BGF来处理Git历史Blob文件
我们使用Git
来管理项目的时候,可能会提交一些Blob
的二进制文件,这些文件并不能像文本文件一样采用diff delta
的形式进行版本控制。如果这些文件一直跟随master
的主版本,那么就是属于有效的文件。
然而很多时候这些二进制文件会被删除重建,那么由于Git
的特性,这些文件会一直留在Git
的历史记录中,这样会导致Git
仓库变得庞大,不利于版本控制和迁移。最直观的就是clone
的时候会很慢,而使用--depth=1
则无法看到历史提交的代码。
查找历史文件
历史提交的二进制文件通常我们可以认为是不需要的,然而在多人协作的时候这个事情我们并不能非常确定。因此我们需要主动查找较大的二进制文件来处理,最简单的办法就是直接扫描大文件。
git rev-list --objects --all | grep "$(git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -10 | awk '{print$1}')"
通过这个命令我们可以看到历史提交中最大的10
个文件,然后我们可以根据这个文件的hash
值来查找这个文件的提交记录。如果需要看到文件的大小,也可以再补充下输出。
git verify-pack -v .git/objects/pack/*.idx \
| grep blob \
| sort -k 3 -n \
| tail -10 \
| awk '{print $1, $3}' \
| while read -r hash size; do
file=$(git rev-list --objects --all | grep "$hash")
echo "$file $size"
done
BFG Repo-Cleaner
虽然可以使用git-filter-branch
来处理历史提交,但是这个命令的效率比较低,且容易出现错误。BFG
是一种更简单、更快捷的替代方法,主要是用来处理历史提交的文件,可以删除指定的文件,也可以替换文件内容。
BFG
需要使用Java
来运行,因此需要先确保运行环境JDK >= 8
。之后使用git clone --mirror
来克隆仓库,然后使用BFG
来处理历史提交。
git clone --mirror git://example.com/some-big-repo.git
需要注意的是,使用--mirror
标识会将整个仓库的完整副本克隆下来,包括所有的提交历史,并且不会存在任何普通文件。同样的,当处理完成之后这个仓库所有的分支都会被修改,因此需要谨慎操作。
而如果仅处理单个分支,那就是使用常规的git clone
即可。但是需要注意的是,由于其他分支仍然有可能持有旧的分支内容,因此就必须要将所有涉及到的分支依次处理,这样就非常麻烦了。
接下来就是使用BFG
来处理历史提交,BFG
的使用非常简单,只需要指定需要处理的文件即可。下载BFG
的jar
包可以在https://rtyley.github.io/bfg-repo-cleaner/
中找到。
java -jar bfg.jar --delete-files path/to/file.txt some-big-repo.git
BFG
还提供了一些其他的功能,比如删除指定大小的文件、替换文件内容、删除文件夹、删除文件通用匹配符。
java -jar bfg.jar --strip-blobs-bigger-than 1M some-big-repo.git
java -jar bfg.jar --replace-text pwd.txt some-big-repo.git
java -jar bfg.jar --delete-folders path some-big-repo.git
java -jar bfg.jar --delete-files '*.png' some-big-repo.git
但是这里的匹配模式也存在局限,例如无法同时指定文件和大小,例如需要移除> 1M
的png
文件是做不到的,经过测试其匹配模式总是倾向于后设置的模式。不过这里并没有阅读源码,只是简单的测试判断。
此外,不需要担心BFG
会删除HEAD
的提交,BFG
不会处理HEAD
的提交,即使BFG
会从早期的历史记录中删除文件,当然也可以通过--no-blob-protection
来关闭保护。
WARNING: The dirty content above may be removed from other commits, but as
the *protected* commits still use it, it will STILL exist in your repository.
在处理完成后,在同级目录下会生成report
文件夹,其中包含了处理的文件信息,可以查看处理的文件数量、大小等信息,以及HASH
变更的信息。在检查无误后,要将历史记录的过期时间设置为现在,且需要使用git
来清理无引用的数据,这样就可以将BFG
处理的数据真正删除。
cd some-big-repo.git
git reflog expire --expire=now --all && git gc --prune=now --aggressive
此时就可以通过du
命令检查文件夹的大小了,通常我们只需要关注.git
文件夹即可。
du -sh .git
最后,直接使用git push
来推送到远程仓库即可,这样就完成了历史提交的处理。注意如果使用分支模式的话,就需要加入-force
选项来强制推送。
git push
这里还需要有一个额外的步骤,需要让每个参与者将本地的仓库删除,然后完整重新clone
最新的仓库,防止持有旧数据的仓库重新推回仓库。此外,也可以使用git-filter-repo
来实现类似的处理。
GitHub
从历史记录中删除文件并不是简单的事情,如果需要我们手动来执行操作的话,就很像我们从某一次提交开始,不断向后rebase
。那么在这个过程中自然就会导致commit
的hash
值发生变化,从而出现一些问题,这里我们主要关注在GitHub
的表现。
- 如果二进制文件是在很久前的提交,例如
5
年前的提交,而假设我们仅会删除此提交的某个文件,对于其他的提交并没有处理。但是由于需要重写历史提交记录,这就会导致从5
年前引入的id
开始到最新的提交全部被重写,这部分可以在BFG
的Commit Tree-Dirt History
中关注到。 - 前边我们也提到了
BFG
会将hash
变化信息写入report
文件夹,实际上在重写的commit
描述信息中,也会发现Former-commit-id: xxx
的数据,用以标识这个commit
重写前的引用。 - 在
GitHub
的contributions
面板中,也就是绿色的瓷砖部分,会出现重写commit
的历史提交出现重复贡献的现象,也就是说原来可能仅有1
个提交,现在变成了2
个,对于这个问题是可以减小影响面的。 - 虽然
contributions
面板中会出现重复的提交,但是通过api
获取的提交记录总数中并不会出现重复的数量增量,也就是说GitHub
并没有将重写的commit
计入历史提交记录中。 - 对于通过分支模式而不是
mirror
模式清理的单独分支,虽然通过BFG
可以将历史提交的二进制文件删除,但是其commit
数量的计算会出现问题,其会切断fork
之前的联系,也就是说原本fork
分支的提交记录会被重新计算。 - 虽然对于主分支的提交数量不会影响,但是此时如果我们打开重写过后的
commit
描述,可以发现仍然可以找到原本的commit
。这就意味着这个object
实际上并没有被删除,只是不再被引用,而是处于游离指针的状态。
实际上这里的影响面还是挺大的,特别是对于早些时间引入的二进制文件,会导致大范围的历史提交记录重写。
对于contributions
面板的影响,也是看起来比较大的问题,不过我们可以先fork
主分支,然后再将主分支设置为fork
分支,然后再更改名称的形式来解决这个问题。但是这个方式并没有完全解决问题,还是会因为提交日期的重写而导致contributions
面板的数据不准确,不过影响面小了很多。
而对于其他问题,通常都是无法避免的问题,因为Git
的特性决定了这个问题的存在。如果需要处理历史提交中私有文件的泄漏,则通常认为是不可靠的,此时必须要立即修正密钥。因此无论是当前提交还是在处理历史提交的时候,需要谨慎操作,不要泄漏私密文件,尽量避免对历史提交的处理。
Blog
参考
- https://api.github.com/repos/user/repo
- https://bbs.huaweicloud.com/blogs/343828
- https://github.com/newren/git-filter-repo
- https://rtyley.github.io/bfg-repo-cleaner/
- https://www.cnblogs.com/sowler/p/17550629.html
- https://api.github.com/search/commits?q=author:user
偶然发现Git文件夹非常大,使用BGF来处理Git历史Blob文件的更多相关文章
- win10用户文件夹重命名,启用administrator账户,删除文件夹时提示找不到该项目
这一切都源自楼主洁癖一般的强迫症. 楼主在重置win10后的安装过程中用microsoft账户登录的电脑,发现用户文件夹名称怪怪的,于是想重命名一下.楼主发现重命名用户文件夹并不能简单地用F2搞定,于 ...
- python 查找文件夹下以特定字符开头的某类型文件 - os.walk
Python os.walk() 方法 os.walk() 方法用于通过在目录树中游走输出在目录中的文件名,向上或者向下.os.walk() 方法是一个简单易用的文件.目录遍历器,可以帮助我们高效的处 ...
- VS 2010不显示头文件源文件和所有以前分类的文件夹,*.h 和*.cpp都显示在同一个文件
打开VS后不显示头文件源文件和所有以前分类的文件夹,*.h 和*.cpp都显示在同一个文件 点击右图红色指示显示所有文件夹按钮,就能恢复.
- 用批处理文件自动备份文件及文件夹,并自动删除n天前的文件
原文:用批处理文件自动备份文件及文件夹,并自动删除n天前的文件 ---恢复内容开始--- 下是备份的批处理,添加到"计划任务"中,设定时间自动运行 复制代码 代码如下:@echo ...
- Linux将一个文件夹或文件夹下的所有内容复制到另一个文件夹
Linux将一个文件夹或文件夹下的所有内容复制到另一个文件夹 1.将一个文件夹下的所有内容复制到另一个文件夹下 cp -r /home/packageA/* /home/cp/packageB ...
- FTP文件夹错误:【打开FTP服务器上的文件夹时发生错误。请检查是否有权限访问该文件夹】
资源管理器访问FTP服务器报错,提示FTP文件夹错误:[打开FTP服务器上的文件夹时发生错误.请检查是否有权限访问该文件夹]. 详细信息: 200 Switching to ASCII mode. 2 ...
- windows资源管理器多标签打开 windows文件夹多标签浏览 浏览器tab页面一样浏览文件夹 clover win8 win10 报错 无响应问题怎么解决 clover卡死 clover怎么换皮肤
大家都知道,我们打开一堆文件夹的时候,是什么样子 “厚厚的一叠”图标堆叠在一起的,非常的不方便 那么,是不是可以像浏览器一样的tab页面展示呢? 答案是可以的 安装好就是这样子的 是不是方便漂亮了很多 ...
- Python模块包(pycharm右键创建文件夹和python package的区别)中__init__.py文件的作用
在eclipse中用pydev开发Python脚本时,我遇到了一个这样的现象,当我新建一个pydev package时,总会自动地生成一个空的__init__.py文件,因为是python新手,所以很 ...
- QTemporaryDir及QTemporaryFile建立临时目录及文件夹(创建一个随机名称的目录或文件,两者均能保证不会覆盖已有文件)
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址:本文标题:QTemporaryDir及QTemporaryFile建立临时目录及文件夹 本文地址: ...
- 用python遍历一个图片文件夹,并输出所有路径到一个 txt 文件
1 #coding:utf8 2 import os 3 import sys 4 def listfiles(rootDir, txtfile, label=0): 5 ftxtfile = ope ...
随机推荐
- 离线安装IDEA插件:详细步骤指南
离线安装IDEA插件:详细步骤指南 网络环境下载插件包 访问 https://plugins.jetbrains.com/ 一.准备工作 找到可用的插件文件 访问 https://plugins.je ...
- Hetao P1307 树的剖分 题解 [ 蓝 ] [ 树形 dp ] [ 贪心 ]
树的剖分:很厉害的性质题,代码也很好写.运用到了奇偶性拼凑答案的 trick. 观察 首先发现一个很重要的条件:一个点的点权只可能是 \(0,1,2\). 这个条件开始我们可能无法用上,于是先想最后的 ...
- Luogu P9646 SNCPC2019 Paper-cutting 题解 [ 紫 ] [ manacher ] [ 贪心 ] [ 哈希 ] [ BFS ]
Paper-cutting:思维很好,但代码很构式的 manacher 题. 蒟蒻 2025 年切的第一道题,是个紫,并且基本独立想出的,特此纪念. 判断能否折叠 我们先考虑一部分能折叠需要满足什么条 ...
- .Net 配置绑定 IOptions
准备 首先准备下appsettins.json以及目标类 appsettins.json "StudentSettings": { "Id": 1023 ...
- OneDrive分享、多人操作电脑中大文件的方法
本文介绍基于OneDrive网盘实现电脑大文件共享.协同办公的方法. 1 前言 作为网盘的重度用户,在学习.工作.生活中可以说少不了与各类云盘打交道.在这一过程中,也慢慢了解到不同网盘软件的特 ...
- VS2019 找不到资产文件 “xxxx\obj\project.assets.json”运行NuGet包还原以生成此文件
参考地址:https://blog.csdn.net/weixin_42835409/article/details/107033059 下载 log4net 源码打开,编译报错: 严重性 代码 说明 ...
- ABC393C题解
大概评级:橙. 送分题. 题意就是让你统计有多少条边是重边或自环. 设 \(u_i\) 表示第 \(i\) 条边的左端点,\(v_i\) 表示第 \(i\) 条边的右端点. 那么如果 \(u_i = ...
- 【配置化】C# dapper是怎么实现的?精短ORM
目录 一.什么是dapper 二.实现问题与思路 & 源码参考 三.小结 一.什么是dapper dapper是个组件,一个dll文件,可以通过NuGet下载. 作用:快速访问数据库并自动完成 ...
- sql sever查询库中每个表是否存在某个列名 列出表名
select t.TABLE_NAME from information_schema.columns t where t.COLUMN_NAME='列名';
- linux服务问题传文件连不上问题远程问题等
通过iptables相关命令实现防火墙的打开和关闭 1.首先可以在打开的终端使用iptables --help查看帮助使用命令: 2.查看防火墙状态:service iptables status(此 ...