Skip to content

Git 大文件存储

· 6 min
TL;DR

Git LFS 即 Git Large File Storage,Git 大文件存储

本文全面介绍 Git LFS 技术,详细讲解了其工作原理和实现机制。文章解释了 Git LFS 如何通过指针文件替代实际大文件、使用 smudge 和 clean 过滤器处理文件转换以及 pre-push 钩子实现大文件上传。包含完整的安装配置步骤、常用命令用法、文件追踪设置,以及如何处理新增大文件和导入历史文件的实用场景。

原理#

a diagram showing how Git LFS works

针对音乐、图片、视频、图表、数据库等类型文件等各种 大文件,使用 Git-LFS 技术的本地仓库使用这些文件的 指针文件 代替实际文件,而实际文件存储在远程端,本地仓库会实时追踪这些文件的变动,并更新。

根据 git lfs 官方帮助文档描述:

Git LFS 基于 Git 的 .gitattributs 配置文件的特性,用 smudge 过滤器基于 指针文件 寻找大文件内容,用 clean 过滤器在对大文件改动时,创建指针文件的新版本。同时还用 pre-push 钩子将大文件上传到 Git LFS 服务器,即在 git-push 时,如果提交中包含被 LFS 跟踪的大文件,pre-push 钩子会检测到,并执行上传 Git LFS 服务器的动作。

因此,如果一个仓库中包含 LFS 内容,但是在推送时不想推送这类文件,只要加上 --no-verify 选项就行,即:

Terminal window
$ git push --no-verify

--no-verify 选项告诉 git push 完全跳过 pre-push 钩子。

前面提到被 LFS 管理的文件,本地仓库中保存的内容实际上是指针文件,其格式类似于下面这样:

Terminal window
$ git show HEAD:2.svg
version https://git-lfs.github.com/spec/v1
oid sha256:158213f90f8b27012034c6f58db63e1861b12aa122d98910de311bf1cb1e50a0
size 14651
(END)

version 表示 LFS 的版本

oid 表示文件对象的唯一 hash 值

size 表示文件的大小

安装#

安装依赖:Git >= 1.8.5

Linux 系统:

Terminal window
curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash
sudo apt-get install git-lfs

https://packagecloud.io/github/git-lfs/install#bash

其它操作系统上的安装,见官方安装文档:

https://github.com/git-lfs/git-lfs#installing

配置#

Terminal window
git lfs install

此时会在仓库的 .git/config 配置文件中,增加一项新配置:

Terminal window
[lfs]
repositoryformatversion = 0
Terminal window
git lfs track "*.svg"
git lfs track "*.png"
....

git lfs track 会更改仓库中的 .gitattributes 配置文件 (如果之前不存在这个文件,则会自动新建):

Terminal window
$ cat .gitattributes
*.svg filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text

通过 git lfs lf-files 查看被 LFS 追踪的文件:

Terminal window
$ git lfs ls-files
9a3c7dae41 * 1.png
d61cf5835a * 2.png
158213f90f * 3.svg
Terminal window
$ git lfs untrack "1.png"
Terminal window
git add .gitattributes
git commit -m "add .gitattributes"

使用场景#

在 Git 仓库中,对于非文本文件,如各种多媒体文件,软件制品文件,二进制文件等等,这些文件往往体积比较大,使用 Git 直接管理会导致仓库的体积迅速膨胀,进而导致 Git 的许多操作变慢,同时也影响仓库上传到远程端。

针对这些情况,有人开发出了 git-lfs 工具来特别管理这些大文件。

Terminal window
git add 1.png && git commit -m "add 1.png file"
git add 2.svg && git commit -m "add 2.svg file"

提交完成后,提交到远程仓库

Terminal window
$ git push origin master
$ git push origin master
Enter 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 true
Uploading 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 threads
Compressing 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 0
remote: 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 中:

Terminal window
$ 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 -> db49cdd8bcf50cd8b18c770fe2dc260ad99bec8a
migrate: Updating refs: ..., done.
migrate: checkout: ..., done.

--include-ref 选项指定导入的分支

如果向应用到所有分支,则使用 --everything 选项

--include 选项指定要导入的文件,可以使用通配符,批量导入。

上述操作会改写提交历史,如果不想改写历史,则使用 --no-rewrite 选项,并提供新的 commit 信息:

Terminal window
$ git lfs migrate import --no-rewrite -m "lfs import"

将本地历史提交中的文件纳入到 LFS 管理后,如果重改了历史,再次推送代码时,需要使用强制推送。

如果克隆的仓库中包含 LFS 管理的文件,但最开始获取代码时,没有完全获取 LFS 对象,则文件只会显示为文本指针,此时需要收到获取文件的内容:

Terminal window
$ git lfs pull
# 这相当于:
$ git lfs fetch
$ git lfs checkout

参考链接#

https://git-lfs.github.com/

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