Github 的清点对象算法
使用 Github 的时候,你有没有见过下面的提示?
这段提示说,远程代码库一共有4350078个对象需要克隆。
这就叫”清点对象”(counting objects),Github需要实时计算出来,需要克隆的对象总数。
这个过程非常慢,根据Github的披露,像Linux kernel这样巨大的库,清点一次需要8分钟!也就是说,发出git clone
命令后,会干等八分钟,然后才会开始真正的数据传输。这当然是无法忍受的。Github团队一直想解决这个问题。
后来,他们终于发现了一种新的算法,现在清点一次只要3毫秒!
为了理解这个算法,你必须先知道,什么是Git的对象。简单说,对象就是文件,最重要的对象有三种。
- 快照对象(Commit)
- 目录对象(Directory)
- 文件对象(File)
每次提交代码的时候,会生成一个commit对象,里面有对应的当前”目录对象”的名字。”目录对象”保存了代码根目录所含有的子目录和文件信息。每一个子目录就是另一个”目录对象”,每一个文件则是”文件对象”,里面是具体的文件内容。
所以,”清点对象”就是清点各种commit、目录、文件等。git clone
和git fetch
操作都需要清点对象,因为需要知道,到底下载哪些对象文件。
清点对象的原始算法如下。
- 列出本地所有分支最新的一个commit
- 列出远程所有分支最新的一个commit
- 两者进行比较,只要有不同,就意味着分支发生变动
- 每一个发生变动的commit,都清点其中具体变动的子目录和文件
- 追溯到当前commit的父节点,重复第四步,直至本地与远程的历史一致为止
- 加总所有需要变动的对象
上面的过程说明,”清点对象”是一个文件遍历算法,变动的对象会被一一清点到,这就意味着大量的文件读操作。对于大型代码库来说,这个过程非常慢。
Github团队想到的新算法,是建立一个Bitmap索引,即为每一个commit生成一个二进制值。
打开本地Github仓库的.git/objects/pack/
目录,你会看到一个索引文件和一个数据文件,它们就是Bitmap。简单说,这两个文件索引了当前代码库的所有对象,然后使用一个二进制值代表这些对象。有多少个对象,这个二进制值就有多少位。它的第n位,就代表数据文件里面的第n个对象。
每个commit都会有一个对应的二进制值,表示当前快照包含的所有对象。这些对象对应的二进制位都为1,其他二进制位都为0。
这样做的好处是,不用读取commit对象,只要读取这个二进制值,就会知道当前commit包含了哪些节点。更妙的是,两个二进制值只要做一次XOR运算,就会知道哪些位(即哪些对象)发生了变动。而且,因为新的对象总是添加到现有二进制位的后面,所以只要读取多出来的那些位,就知道当前commit比上一次commit多出了哪些对象。
这样一来,”清点对象”就变成了二进制值的比较运算,因此速度极快。进一步的介绍,请参看官方文档《Bitmap的解释》,《Bitmap的格式》。
目前,Github的生产环境已经部署了这套算法,用户再也不用为了清点对象,而苦苦等待了。而且,Github团队还把它合并进了Git,这意味着,从此所有Git实现都可以使用Bitmap功能了,因此将来肯定还会有更多好玩的用法出现。
- 【干货】用于机器学习的线性代数速查表
- 使用机器学习预测天气(第一部分)
- linux 常用指令
- LCS 算法:Javascript 最长公共子序列
- 短网址(short URL)系统的原理及其实现
- 设计和实现一款轻量级的爬虫框架
- JavaScript实现模糊推荐的input框(类似搜索框)
- hadoop streaming编程小demo(python版)
- 一个scrapy框架的爬虫(爬取京东图书)
- mongodb生产环境(副本集模式)集群搭建配置
- ELK日志收集分析系统配置
- 【学术】如何在15分钟内建立一个深度学习模型?
- Elasticsearch(GEO)空间检索查询
- java spark-streaming接收TCP/Kafka数据
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android空心圆及层叠效果实现代码
- 如何更改Dialog的标题与按钮颜色详解
- Android编程之数据库的创建方法详解
- android studio集成ijkplayer的示例代码
- Android开发实现浏览器全屏显示功能
- Android动态人脸检测的示例代码(脸数可调)
- Android抽奖轮盘的制作方法
- Android 获取屏幕的多种宽高信息的示例代码
- Android编程实现禁止StatusBar下拉的方法
- Android自定义view圆并随手指移动
- Android仿微信发送语音消息的功能及示例代码
- 详解Android studio ndk配置cmake开发native C
- Android编程实现禁止状态栏下拉的方法详解
- Android进度条ProgressBar的实现代码
- Android画画板的制作方法