Shixiang Wang

>上士闻道
勤而行之

使用 Git 存储大文件

王诗翔 · 2020-12-07

分类: config  
标签: git-lfs   gitter  

如果你是一个 gitter,你可能会遇到我今天遇到的问题。

git push 文件太大报警告

当在 Git 仓库中存储大的二进制文件时(>50MB),比如 R 里面的 RData 或 RDS 文件,默认的 git 提交方式无法获取二进制文件的修改,会让仓库越来越大。在这种情况下,将仓库 push 到远程会出现警告。

$ git push
Counting objects: 15, done.
Delta compression using up to 24 threads.
Compressing objects: 100% (15/15), done.
Writing objects: 100% (15/15), 58.66 MiB | 1.46 MiB/s, done.
Total 15 (delta 6), reused 0 (delta 0)
remote: Resolving deltas: 100% (6/6), completed with 4 local objects.
remote: warning: GH001: Large files detected. You may want to try Git Large File Storage - https://git-lfs.github.com.
remote: warning: See http://git.io/iEPt8g for more information.
remote: warning: File xx.rds is 54.69 MB; this is larger than GitHub's recommended maximum file size of 50.00 MB
To https://github.com/ShixiangWang/XX.git
   9a93595..fff62d7  master -> master

我之前的解决办法

既然文件很大,那就不要将它存储在 Git 仓库中了,提前将文件名写入 .gitignore 可以将其忽略掉。但有时候没这么简单,我们也没那么细心,如果已经将大文件添加到 git 仓库中了怎么办呢?

可以使用下面的命令将文件 var/log/system.log 从 git 仓库中移除:

git filter-branch --index-filter 'git rm --cached --ignore-unmatch var/log/system.log' --tag-name-filter cat -- --all

如果想存储文件怎么办

根据前面出现的警告我们知道有个 git-lfs 的工具可以解决这个问题。

Large files detected. You may want to try Git Large File Storage - https://git-lfs.github.com

那么 git-lfs 是什么呢?

Git 大文件存储(Large File Storage,简称LFS)目的是更好地把大型二进制文件,比如音频文件、数据集、图像和视频等集成到 Git 的工作流中。我们知道,Git 存储二进制效率不高,因为它会压缩并存储二进制文件的所有完整版本,随着版本的不断增长以及二进制文件越来越多,这种存储方案并不是最优方案。而 LFS 处理大型二进制文件的方式是用文本指针替换它们,这些文本指针实际上是包含二进制文件信息的文本文件。文本指针存储在 Git 中,而大文件本身通过HTTPS托管在Git LFS服务器上。

一个更清晰的简介如下:

对于包涵大文件(尤其是经常被修改的大文件)的项目,初始克隆需要大量时间,因为客户端会下载每个文件的每个版本。Git LFS(Large File Storage)是由 Atlassian, GitHub 以及其他开源贡献者开发的 Git 扩展,它通过延迟地(lazily)下载大文件的相关版本来减少大文件在仓库中的影响,具体来说,大文件是在 checkout 的过程中下载的,而不是 clone 或 fetch 过程中下载的(这意味着你在后台定时 fetch 远端仓库内容到本地时,并不会下载大文件内容,而是在你 checkout 到工作区的时候才会真正去下载大文件的内容)。

如何使用 git-lfs

安装

安装很简单,我们可以上 https://github.com/git-lfs/git-lfs 查看不同系统怎么安装。像 linux 操作系统可以直接通过包管理器安装,例如 CentOS 上是 yum install git-lfs

使用

假设你目前位于 git 仓库中。

命令形如 git lfs track "*.rds",它就可以标记和追踪所有 rds 后缀名文件,并将其通过 lfs 技术进行存储和传输。

使用上面命令后,在通过下面的命令提交修改。

$ git add .gitattributes
$ git commit -m "track *.rds file using Git LFS"

后面就可以常规使用 git addgit commit 了,例如

$ git add xx.rds
$ git commit -m "add xx.rds"
$ git push

迁移

如果你想将仓库里已经存储的文件修改存储方式为 LFS,那么使用下面的命令进行迁移:

git lfs migrate import --include="*.rds" --everything
migrate: Sorting commits: ..., done.                                                                                    
migrate: Rewriting commits: 100% (12/12), done.                                                                         
  master	fff62d77ddfa2a58e87bb88a77857e7d73ca1f6d -> 3f71d46858f3140fbe70a5d9804a3c43fd2e6dbf
migrate: Updating refs: ..., done.                                                                                      
migrate: checkout: ..., done.      

如果你想要查看哪些文件格式占据的空间比较大,使用下面的命令:

$ git lfs migrate info
migrate: Fetching remote refs: ..., done.                                                                               
migrate: Sorting commits: ..., done.                                                                                    
migrate: Examining commits: 100% (12/12), done.                                                                         
*.xena	12 MB 	  1/1 files(s)	100%
*.gz  	11 MB 	  3/3 files(s)	100%
*.xlsx	9.4 MB	  7/7 files(s)	100%
*.csv 	4.7 MB	  7/7 files(s)	100%
*.css 	2.1 MB	21/21 files(s)	100%

git pull 碰到拒绝合并无关历史

当使用 git push 后,再拉取更新可能会出现拒绝合并无关历史的情况,可以使用下面的命令解决:

git pull origin master --allow-unrelated-histories 

如果发现仓库中的文件大小不对,使用 git lfs install 初始化,然后拉取 git lfs pull

取消文件最终

git lfs untrack '<file-type>'
git rm --cached '<file-type>'
git add '<file-type>'
git commit -m "restore '<file-type>' to git from lfs"

可以进一步使用 git lfs prune 清除本地缓存文件。

参考: