Git LFS 即 Git Large File Storage,Git 大文件存储
本文全面介绍 Git LFS 技术,详细讲解了其工作原理和实现机制。文章解释了 Git LFS 如何通过指针文件替代实际大文件、使用 smudge 和 clean 过滤器处理文件转换以及 pre-push 钩子实现大文件上传。包含完整的安装配置步骤、常用命令用法、文件追踪设置,以及如何处理新增大文件和导入历史文件的实用场景。
原理#
针对音乐、图片、视频、图表、数据库等类型文件等各种 大文件,使用 Git-LFS 技术的本地仓库使用这些文件的 指针文件 代替实际文件,而实际文件存储在远程端,本地仓库会实时追踪这些文件的变动,并更新。
根据 git lfs 官方帮助文档描述:
Git LFS 基于 Git 的 .gitattributs 配置文件的特性,用 smudge 过滤器基于 指针文件 寻找大文件内容,用 clean 过滤器在对大文件改动时,创建指针文件的新版本。同时还用 pre-push 钩子将大文件上传到 Git LFS 服务器,即在 git-push 时,如果提交中包含被 LFS 跟踪的大文件,pre-push 钩子会检测到,并执行上传 Git LFS 服务器的动作。
因此,如果一个仓库中包含 LFS 内容,但是在推送时不想推送这类文件,只要加上 --no-verify 选项就行,即:
$ git push --no-verify--no-verify 选项告诉 git push 完全跳过 pre-push 钩子。
前面提到被 LFS 管理的文件,本地仓库中保存的内容实际上是指针文件,其格式类似于下面这样:
$ git show HEAD:2.svg
version https://git-lfs.github.com/spec/v1oid sha256:158213f90f8b27012034c6f58db63e1861b12aa122d98910de311bf1cb1e50a0size 14651(END)version 表示 LFS 的版本
oid 表示文件对象的唯一 hash 值
size 表示文件的大小
安装#
安装依赖:Git >= 1.8.5
Linux 系统:
curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash
sudo apt-get install git-lfs其它操作系统上的安装,见官方安装文档:
配置#
- 在 Git 仓库中为仓库设置相关配置:
git lfs install此时会在仓库的 .git/config 配置文件中,增加一项新配置:
[lfs] repositoryformatversion = 0- 选择要用 LFS 追踪的文件:
git lfs track "*.svg"git lfs track "*.png"....git lfs track 会更改仓库中的 .gitattributes 配置文件 (如果之前不存在这个文件,则会自动新建):
$ cat .gitattributes*.svg filter=lfs diff=lfs merge=lfs -text*.png filter=lfs diff=lfs merge=lfs -text通过 git lfs lf-files 查看被 LFS 追踪的文件:
$ git lfs ls-files9a3c7dae41 * 1.pngd61cf5835a * 2.png158213f90f * 3.svg- 如果不想 LFS 追踪某个文件:
$ git lfs untrack "1.png"- 向仓库保存、提交该配置:
git add .gitattributesgit commit -m "add .gitattributes"使用场景#
在 Git 仓库中,对于非文本文件,如各种多媒体文件,软件制品文件,二进制文件等等,这些文件往往体积比较大,使用 Git 直接管理会导致仓库的体积迅速膨胀,进而导致 Git 的许多操作变慢,同时也影响仓库上传到远程端。
针对这些情况,有人开发出了 git-lfs 工具来特别管理这些大文件。
- 使用 LFS 管理新增大文件
git add 1.png && git commit -m "add 1.png file"git add 2.svg && git commit -m "add 2.svg file"提交完成后,提交到远程仓库
$ git push origin master
$ git push origin masterEnter passphrase for key '/home/git/.ssh/id_ed25519':Locking support detected on remote "origin". Consider enabling it with: $ git config lfs.https://gitee.com/hightest/lfs-demo.git/info/lfs.locksverify trueUploading LFS objects: 100% (3/3), 1.2 MB | 0 B/s, done.Enumerating objects: 11, done.Counting objects: 100% (11/11), done.Delta compression using up to 6 threadsCompressing objects: 100% (10/10), done.Writing objects: 100% (10/10), 1.56 KiB | 1.56 MiB/s, done.Total 10 (delta 2), reused 0 (delta 0), pack-reused 0remote: Powered by GITEE.COM [GNK-6.1]To gitee.com:hightest/lfs-demo.git dfe8b09..5f03bab master -> master使用 LFS 管理历史文件:
如果一个仓库中原来已经提交了一些大文件,此时即使运行 git lfs track 也不会有效的。
为了将仓库中现存的大文件应用到 LFS,需要用 git lfs migrate 导入到 LFS 中:
$ git lfs migrate import --include-ref=master --include="example.svg"migrate: Sorting commits: ..., done.migrate: Rewriting commits: 100% (3/3), done. master cd0e331924399a68701f2594b5b097ce3d4352d8 -> c85c99e2b44567f981e35a23fc652c3e34c184ce v1.0 23431a38b6dc7eec07654f2f87f33012d9e600b0 -> 53b93fc2cefad6ad3075e0c5533e3eca70ed7828 v1.1 0368d5926372916d04cc72d863a97eb17c1e9807 -> db49cdd8bcf50cd8b18c770fe2dc260ad99bec8amigrate: Updating refs: ..., done.migrate: checkout: ..., done.
--include-ref选项指定导入的分支如果向应用到所有分支,则使用
--everything选项
--include选项指定要导入的文件,可以使用通配符,批量导入。
上述操作会改写提交历史,如果不想改写历史,则使用 --no-rewrite 选项,并提供新的 commit 信息:
$ git lfs migrate import --no-rewrite -m "lfs import"将本地历史提交中的文件纳入到 LFS 管理后,如果重改了历史,再次推送代码时,需要使用强制推送。
- 克隆的仓库包含 LFS 管理的文件
如果克隆的仓库中包含 LFS 管理的文件,但最开始获取代码时,没有完全获取 LFS 对象,则文件只会显示为文本指针,此时需要收到获取文件的内容:
$ git lfs pull# 这相当于:$ git lfs fetch$ git lfs checkout参考链接#
https://git-scm.com/docs/gitattributes
https://zzz.buzz/zh/2016/04/19/the-guide-to-git-lfs/
https://docs.github.com/en/github/managing-large-files/about-git-large-file-storage