熟悉 Git 的小伙伴应该都知道随着 Git 仓库维护的时间越来越久,追踪的文件越来越多,git 存储的 objects 数量会极其庞大,每次从远程仓库 git clone 的时候都会墨迹很久。如果我们不小心 git add 了一个体积很大的文件,且 git push 到了远程仓库,那么我们 git clone 的时候也会很慢。

看一下 GitHub 上的 microsoft/vscode 仓库,都有 九万多个 commit 了,可想而知 objects 的数量应该很恐怖,尝试 clone 一下(一百多万个 objects):

这里微微记录下 Git 仓库瘦身和使用 Git LFS 进行大文件存储管理的几个常规操作。

Git 仓库瘦身

瘦身背景:错误把大文件 push 到了远程仓库

我们可以通过以下命令或者 du -mh 查看 Git 仓库的体积,git-count-objects

# 查看仓库体积情况
git count-objects -vH

示例:可以看到当前仓库体积只有 12.00 KiB 左右

现在我们模拟错误的将大文件上传到远程 Git 仓库的动作:

# 1、生成一个 90MB 大小的文件,Github 做了限制超过 100 MB 大小的文件建议使用 LFS,直接拒绝 push
➜ dd if=/dev/zero of=bigfile bs=90MB count=1
# 2、将这个文件 push 到远程仓库
➜ git add bigfile
➜ git commit -m "add 90MB bigfile"
➜ git push origin master
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 16 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 85.71 KiB | 306.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
remote: warning: See http://git.io/iEPt8g for more information.
remote: warning: File bigfile is 85.83 MB; this is larger than GitHub's recommended maximum file size of 50.00 MB
remote: warning: GH001: Large files detected. You may want to try Git Large File Storage - https://git-lfs.github.com.
To github.com:yeshan333/git-lfs-prune-repo.git
e3baf1a..f057313 master -> master

好,接下来我们假装这个仓库有很多文件,不知道具体是那个文件让 Git 仓库的体积突然变大,导致 clone 很慢。就算知道了是哪里个文件造成的,我们直接删除那个文件是没有用的,我们还需要删除那个文件对应的 Git Object 文件

接下来我们可以通过一下命令将本地 clone 的仓库历史提交过的体积较大的前 5 个文件名与对应的 Object 文件的 ID 罗列出来:

git rev-list --objects --all | grep "$(git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -5 | awk '{print$1}')"

然后我们删除历史提交过的大文件 bigfile,从日志中我们可以看到本地仓库已经移除大文件成功了

➜ git filter-branch --force --index-filter 'git rm -rf --cached --ignore-unmatch bigfile' --prune-empty --tag-name-filter cat -- --all
WARNING: git-filter-branch has a glut of gotchas generating mangled history
rewrites. Hit Ctrl-C before proceeding to abort, then use an
alternative filtering tool such as 'git filter-repo'
(https://github.com/newren/git-filter-repo/) instead. See the
filter-branch manual page for more details; to squelch this warning,
set FILTER_BRANCH_SQUELCH_WARNING=1.
Proceeding with filter-branch... Rewrite e3baf1ac709ae54b60afac9038adcf26fd086748 (1/1) (0 seconds passed, remaining 0 predicted)
WARNING: Ref 'refs/heads/master' is unchanged
WARNING: Ref 'refs/remotes/origin/master' is unchanged
WARNING: Ref 'refs/remotes/origin/main' is unchanged
WARNING: Ref 'refs/remotes/origin/master' is unchanged

接下来我们使用 reflog 和 gc 压缩(清理和回收大文件占用的 objects 空间)看看瘦身效果,最后将变动推送到远程仓库即可:

➜ git reflog expire --expire=now --all && git gc --prune=now --aggressive

➜ git count-objects -vH

➜ git push --mirror
Total 0 (delta 0), reused 0 (delta 0)
To github.com:yeshan333/git-lfs-prune-repo.git
- [deleted] main
+ f057313...e3baf1a master -> master (forced update)
* [new branch] origin/HEAD -> origin/HEAD
* [new branch] origin/main -> origin/main
* [new branch] origin/master -> origin/master

What's the difference between git clone --mirror and git clone --bare

Git LFS 大文件存储

如果我们之前生成的大文件 bigfile 大小超过 100 MB,那么 push 到 Github 的时候,会抛出个 error 错误,并会有条建议使用 LFS (Large File Storage):https://git-lfs.github.com/ 管理这个大文件:

➜ git push origin main
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 16 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 1.85 MiB | 752.00 KiB/s, done.
Total 3 (delta 0), reused 1 (delta 0)
remote: error: Trace: 993cb74d30fdb2342e7243f5a7002c1892d00d3a216b80e64b43ef7e4382b947
remote: error: See http://git.io/iEPt8g for more information.
remote: error: File bigfile is 1907.35 MB; this exceeds GitHub's file size limit of 100.00 MB
remote: error: GH001: Large files detected. You may want to try Git Large File Storage - https://git-lfs.github.com.
To github.com:yeshan333/git-lfs-prune-repo.git
! [remote rejected] main -> main (pre-receive hook declined)
error: failed to push some refs to 'git@github.com:yeshan333/git-lfs-prune-repo.git'
# 仓库初始化 LFS
➜ git lfs install
Updated git hooks.
Git LFS initialized.
# 创建大文件
➜ dd if=/dev/zero of=bigfile200 bs=200MB count=1
1+0 records in
1+0 records out
200000000 bytes (200 MB, 191 MiB) copied, 0.176594 s, 1.1 GB/s
# 指定 LFS 追踪大文件
➜ git lfs track "bigfile200"
Tracking "“bigfile200”"
# 被追踪的文件会记录再 .gitattributes 文件中我们将 .gitattributes 文件 push 到远程仓库即可
➜ cat .gitattributes
"bigfile200" filter=lfs diff=lfs merge=lfs -text
➜ git add .gitattributes
➜ git commit -m "add .gitattributes"
➜ git push # 提交大文件
➜ git add bigfile200
➜ git commit -m "bigfile 200MB"
[master 84fb90b] bigfile 200MB
1 file changed, 3 insertions(+)
create mode 100644 bigfile200
➜ git push
Uploading LFS objects: 100% (1/1), 200 MB | 3.7 MB/s, done.
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 16 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 423 bytes | 423.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To github.com:yeshan333/git-lfs-prune-repo.git
aef9a0b..84fb90b master -> master

开启了 LFS 之后,对应大文件的内容存储在 LFS 服务器中,不再是存储在 Git 仓库中,Git 仓库中存储的是大文件的指针文件,LFS 的指针文件是一个文本文件。

Done?

参考

本文由博客群发一文多发等运营工具平台 OpenWrite 发布

Git 仓库瘦身与 LFS 大文件存储的更多相关文章

  1. GitLab 之 Git LFS 大文件存储的配置

    转载自:https://cloud.tencent.com/developer/article/1010589 1.Git LFS 介绍 Git 大文件存储(Large File Storage,简称 ...

  2. 给你的git仓库瘦身

    很久没有写博客了,最近遇到了一个git问题,比较典型,记录下来与大家分享. 我们使用git版本控制的时候享受了很多便利,不管是代码合并,分支提供给我们的并发,但我们也往往忽略了每次提交之后在我们本地项 ...

  3. Android 瘦身之道 ---- so文件

    Android 瘦身之道 ---- so文件 [TOC] 1. 前言 目前Android 瘦身只有几个方面可以入手,因为apk的结构就已经固定了. res 目录下的资源文件.(通常是压缩图片,比如 矢 ...

  4. git 彻底删除历史记录中的大文件

    Reference 大家一定遇到过在使用Git时,不小心将一个很大的文件添加到库中,即使删除,记录中还是保存了这个文件.以后不管是拷贝,还是push/pull都比较麻烦. === 删除大文件方法 方法 ...

  5. 使用Sparse Checkout 排除跟踪Git仓库中指定的目录或文件

    应用场景 在一个大工程里包含由不同部门开发的模块时,项目的Git仓库肯定很大,造成每次Git操作相对比较耗时.因为开发人员一般只关心他们部门的模块的代码,所以完全可以排除一些他完全不需要用到的目录.这 ...

  6. Git Compare with base,比较大文件时,长时间等待,无法加载

    问题 当使用Git比较一个大文件(几十兆数量级)版本见差异时,会一直等待加载,且内存消耗很大,导致其他进程很难执行.任务管理器中,可以看到此时的TortoiseGitMerge吃掉3G左右的内存. 原 ...

  7. mongoDB 大文件存储方案, JS 支持展示

    文件存储 方式分类 传统方式 存储路径 仅存储文件路径, 本质为 字符串 优点: 节省空间 缺点: 不真实存储在数据库, 文件或者数据库发送变动需要修改数据库 存储文件本身 将文件转换成 二进制 存储 ...

  8. mongo 固定集合,大文件存储,简单优化 + 三招解决MongoDB的磁盘IO问题

    1.固定集合 > db.createCollection(, max:});//固定集合 必须 显式创建. 设置capped为true, 集合总大小xxx字节, [集合中json个数max] { ...

  9. ios大文件存储

    I am using Erica Sadun's method of Asynchronous Downloads (link here for the project file: download) ...

  10. PHP大文件存储示例,各种文件分割和合并(二进制分割与合并)

    最近要对视频进行上传,由于涉及到的视频非常的大,因此采用的是分片上传的格式,下面是一个简单的例子: split.php <?php $i = 0; //分割的块编号 $fp = fopen(&q ...

随机推荐

  1. VUE构建

    VUE 渐进式 JavaScript 框架 易学易用 基于标准 HTML.CSS 和 JavaScript 构建,提供容易上手的 API 和一流的文档. 性能出色 经过编译器优化.完全响应式的渲染系统 ...

  2. 操作系统:linux -- 虚拟文件系统如何管理文件

    本节来瞧下Linux是如何管理文件,也验证下Linux那句口号:一切皆文件 为此,我们需要首先搞清楚什么是 VFS,接着理清为了实现 VFS 所用到的数据结构,然后看看一个文件的打开.读写.关闭的过程 ...

  3. linux中部署自己的系统内核

    1.计算机是如何将系统起起来的?-- PC机的引导流程 PC机BIOS固件是固化在PC机主板上的ROM芯片中,断电也能保存,PC机上电后的第一条指令就是在BIOS固件中,它负责检测和初始化CPU.内存 ...

  4. 阿里云部署Django主要注意事项

    (1)virtualenv 报错 os 没有 PathLike属性 阿里云ubuntu16.0服务器默认python版本分别是2.7.12,3.5.2,而PathLike是在python 3.6时才被 ...

  5. codeup之数组元素原地逆置

    Description 将一个长度为10的整型数组中的值按逆序重新存放. 如:原来的顺序为1,2,3,4,5,6,7,8,9,0,要求改为0,9,8,7,6,5,4,3,2,1 Input 从键盘上输 ...

  6. 【踩坑】VMware Workstation 17.x 中的虚拟机按键反映迟钝

    [踩坑]VMware Workstation 17.x 中的虚拟机按键反映迟钝 目录 [踩坑]VMware Workstation 17.x 中的虚拟机按键反映迟钝 问题描述 笔者环境 解决方法 测试 ...

  7. 自己做的linux动态壁纸软件

    自己做的linux动态壁纸软件 https://github.com/dependon/fantascene-dynamic-wallpaper

  8. Prompt 攻击与防范:大语言模型安全的新挑战

    随着大语言模型(LLM)在企业服务.智能助手.搜索增强等领域的广泛应用,围绕其"Prompt"机制的安全问题也逐渐引起关注.其中最具代表性的,就是所谓的 Prompt Inject ...

  9. maixpy 常用例程整理

    基础控制K210例程 1.1 使用屏幕和摄像头 例程 import sensor, lcd sensor.reset() sensor.set_pixformat(sensor.RGB565) sen ...

  10. RDP远程桌面连接服务

    漏洞原理 Windows远程桌面内核驱动处理MS_T120通道时(管理数据传输时)没有对数据的数据包进行验证限制,没有将信道的指针删除(之后会回来访问恶意的数据包),攻击者无需认证即可向RDP服务(3 ...