GIT LFS 原理杂谈

例子

这里做些例子展示,方便理解。

不开LFS

git init

: 提交大文件,文件166m
git add isbin.bin  
git commit -m "初始化"
: --------------- 本地仓库大小 321  MB  (≈实际文件166+ git log变更166)---------------

: 修改文件
echo a >> isbin.bin
git add isbin.bin
git commit -m "修改大文件"
: --------------- 大小 476 MB (约等 321MB + 166M)---------------

: 二次修改文件
echo b>>isbin.bin
echo b>>text.txt
git add isbin.bin text.txt
git commit -m "修改大文件2次"
: --------------- 大小 631 MB (约等 478MB + 166M) ---------------  

: 推送远端(使用本地裸仓库,git init --bare 创建,方便演示)
git push --progress "D:\lfs\noLFSbare" master

: 从远端克隆(使用本地裸仓库,方便演示) 
git clone D:\lfs\noLFSbare --progress
: --------------- clone 库的大小 631 MB ;源文件和庞大的git log变更历史 ---------------  

开LFS

git init

: 开启 lfs 功能及文件追踪
git lfs install
git lfs track "*.bin"
git add .gitattributes
git commit -m "LFS初始化"

: 上传大文件,文件166m
git add isbin.bin  
git commit -m "初始化"
: --------------- 大小 333 MB (另外加上166m git lfs 缓存) ---------------

: 修改文件
echo a >> isbin.bin
git add isbin.bin
git commit -m "修改大文件"
: --------------- 大小 499 MB (另外加上166m *2 git lfs 缓存)---------------

: 二次修改文件
echo a >> isbin.bin
git add isbin.bin
git commit -m "修改大文件"
: --------------- 大小 666 MB  (另外加上166m *3 git lfs 缓存)---------------

: 推送远端(使用本地裸仓库,git init --bare 创建,方便演示)
git push --progress "D:\lfs\LFSbare" master

: 从远端克隆(使用本地裸仓库,方便演示) 
git clone D:\lfs\LFSbare --progress
:--------------- clone下来的仓库 大小 333 MB (真实文件另外加上166m git lfs 缓存) 
:真实文件是缓存拷贝出来,其实clone下载只有一半---------------

: clone 下来的新仓库 回退版本
git reset --hard HEAD~1
: --------------- 大小 499 MB ---------------  
: 回退版本时从lfs 下载上一版本的文件做本地缓存,并替换工作目录下的文件

例子小结

需要注意的是一个混淆点,GIT LFS不能缩减本地仓库的大小,只有在频繁变更二进制文件,才可以有效缩减的远端仓库大小,提高clone或者pull的速度!

详解

查看git log历史中的大文件文件,我们可以看到这些庞大的二进制文件,都转换成文件指针文本,大致格式如下。

version https://git-lfs.github.com/spec/v1
oid sha256:efe51849f1f4d4003a64ba0d430425e991d5f9c1c64691663ad58192b3bb8932
size 174684142

那问题来了,我们在例子中使用的提交命令是明明一样的。LFS是那是如何将文件做转换的呢?

GIT HOOK 及GIT attributes提供无感使用体验

在一个本地仓库执行git lfs install或者clone带lfs的仓库时,在.git\hooks文件夹中有一下四个文件在这里插入图片描述
执行对应git操作时会自动或前或后执行对应的钩子函数,查看里面的内容也非常简单,判断git lfs是否存在并且执行配套的git lfs命令。

而另一个则是 GIT attributes文件,lfs 跟踪文件时,添加一个文件.attributes文件,简单来说,就是对bin文件,git 识别成文本,指定filter、merge及diff文件比对规则,其中filter用来执行检出和stage时源文件和文件指针转换的操作。

*.bin filter=lfs diff=lfs merge=lfs -text

git attributes介绍

git hook与 attributes都是git的原生特性。

lfs 源文件缓存及文件指针对应规则

从上面的一些说明,我们可以已经可以对 git lfs的性质做一下简单的总结了,他只是一个git的外挂式的插件,或者说一个enhancer,利用git原生特性,让git 不在管理真实的二进制文件,而是一个pointer性质的文件。

那lfs如何根据这些文件指针获取真正的源文件的呢?

同样,git lfs 默认会在当前仓库的.git目录创建lfs文件夹,这里面存储着git lfs的各个版本的源文件缓存,需要注意这些是缓存,而不是git的一部分,这也是能提高git性能的根本原因,这些缓存删除对git没有任何影响,上面的例子中我们可以看到,clone 带lfs的仓库,虽然只会下载最新版本的文件指针指向的文件版本,而历史文件只有当我们做另外的reset或者checkout之类的操作是,才会去下载。

指针获取对应文件规则:
文件指针有一个oid 对象id,对应的文件则是.git/lfs/objects/OID[0:2]/OID[2:4]/OID

例如

version https://git-lfs.github.com/spec/v1
oid sha256:efe51849f1f4d4003a64ba0d430425e991d5f9c1c64691663ad58192b3bb8932
size 174684142

则对应的文件缓存应当在**.git\lfs\objects\ef\e5**
文件名efe51849f1f4d4003a64ba0d430425e991d5f9c1c64691663ad58192b3bb8932
如果不存在则会像lfs服务器下载。

走服务器的http请求大概如下,主要还是根据sha256算出来的oid。

// POST https://lfs-server.com/objects/batch
// Accept: application/vnd.git-lfs+json
// Content-Type: application/vnd.git-lfs+json
// Authorization: Basic … (if needed)
{
“operation”: “download”,
“transfers”: [ “basic” ],
“ref”: { “name”: “refs/heads/main” },
“objects”: [
{
“oid”: “12345678”,
“size”: 123
}
],
“hash_algo”: “sha256”
}

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值