Git LFS迁移与管理Gitlab仓库,加快Git拉取(多种方式)

372 阅读7分钟

前言

GitLab作为当前最受欢迎的代码管理平台,广泛应用于企业开发中。然而,随着代码提交次数和项目规模的增加,仓库体积会迅速膨胀。特别是由于Git上传的便捷性,开发人员常常会将大量非代码文件(如图片、二进制文件等)直接上传到仓库中。这些文件通常体积较大,导致仓库拉取速度变慢,且难以管理,严重影响团队的工作效率。随着时间的推移,这一问题会愈发严重。

通过Git LFS(Large File Storage)技术,可以将这些非代码文件从仓库中分离出来,进行单独管理。这种方式不仅能有效解决仓库膨胀问题,还能保持原有的代码拉取、提交等操作流程不变,确保开发人员的工作习惯不受影响。

在本篇博文中,小编将详细介绍如何通过多种方式使用Git LFS,对GitLab仓库中的非代码文件进行迁移和管理,帮助团队更高效地管理项目资源。


一、Git Lfs加快Git拉取的原理

在 GitLab 上的仓库,底层结构通常由两个仓库组成:主仓库(.git)和 Wiki 仓库(.wiki.git)。主仓库保存项目的源代码,而 Wiki 仓库保存项目的维基文档。

  • 主仓库(.git):包含了项目的所有源代码和版本控制数据,当运行git clone 或者git pull时,实际上是在与主仓库进行交互。
  • Wiki仓库(.wiki.git):这是一个独立的Git仓库,专门用于存储项目的Wiki页面。

当我们从Gitlab中拉取代码时,会发现拉取后的项目文件夹中,会包含一个.git文件夹,这个文件夹叫做裸仓库,其里面包含的内容则是从底层结构的主仓库(.git)获取而来,裸仓库的目录结构如下所示:

  • branches/ :包含本地分支的引用。每个文件代表一个分支,文件内容是该分支当前指向的提交的哈希值。
  • hooks/ 包含 Git 钩子脚本。这些脚本在特定的 Git 操作(如提交、推送、检出等)时自动执行
  • objects/ :包含所有 Git 对象(提交、树、blob 等)的存储。这些对象以文件形式存储,每个文件代表一个对象。
  • refs/ :包含引用(分支、标签等)的存储。每个引用文件包含一个提交的哈希值。
  • logs/ :包含引用日志(reflog)文件。这些文件记录了引用(分支、HEAD 等)的历史变更。
  • config:包含仓库的配置文件。这个文件存储了仓库的配置信息,如远程仓库地址、用户信息、分支配置等。
  • description:包含仓库的描述信息。这个文件通常用于服务器端的仓库,显示在仓库列表中。
  • HEAD:指向当前 HEAD 引用。通常是一个分支名,表示当前工作目录对应的分支。
  • index:索引文件,包含当前工作目录的暂存区信息。这个文件记录了即将提交的文件的状态。
  • packed-refs:包含打包的引用。这个文件用于优化引用的存储,减少文件数量。

当我们使用 git clone 命令克隆仓库时,Git 会在本地创建一个完整的工作目录,并从 GitLab 服务器下载对应仓库的所有数据(包括提交历史、分支信息等),存储到本地工作目录的 .git(裸仓库) 中。克隆完成后,Git 会自动检出默认分支(通常是 main 或 master),并根据 .git 目录中的数据将代码完整地还原到本地工作目录中,供开发者使用。

而一个仓库在被Git Lfs管理后,在拉取下来的.git(裸仓库)中,会多一个lfs文件夹,主要用于存储与 Git LFS 相关的数据和配置信息,包括存储 LFS 对象的实际内容、日志文件、配置文件等。而这部分内容就是从object中迁移出去的,并且将Git LFS管理前后的.git文件夹进行相互对比发现:

旧object大小   >     新object大小   +     lfs文件大小

旧.git(裸仓库)大小 >    新.git(裸仓库)大小

​编辑

这是由于GIt LFS会将迁移的文件进行单独管理,拉取的时候再另外下载下来保存在 .git (裸仓库)的lfs文件夹中,这个过程由于Git LFS支持自动按需拉取,只会在使用对应文件时才会自动下载对应文件,所以拉取下来的大小相较于迁移前会减少,并且Git LFS支持多线程下载,拉取的速度也要快于未迁移前的拉取。


二、原生方式迁移

以*.exe文件为例,将其迁移到Git LFS进行管理。

第一步: 克隆旧仓库,克隆下来的仓库,包含旧仓库的所有引用和配置。

git clone --mirror 旧仓库地址

第二步:执行git lfs migrate命令,命令会遍历仓库中的所有历史提交,查找包含 .exe 文件的提交。对于每个找到的 .exe文件,Git LFS 会将其内容从 Git 仓库的常规对象存储中移除,并替换为一个指向 Git LFS 对象存储的指针文件。这个指针文件包含文件的 LFS 对象 ID 和一些元数据,但不包含文件的实际内容。--everything 参数确保迁移所有分支和提交中的匹配文件。

 git lfs migrate import --include="*.exe" --everything

第三步: 在执行 git lfs migrate import 后,历史提交被重写,旧的提交对象(包括被迁移的 .exe 文件的原始提交)会变成未引用对象。这些未引用的提交会被 git gc --prune=now 命令删除。本地.git文件夹中也存在之前不再需要的git log 缓存,会被一并清理和释放空间。

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

第四步: 创建一个新的仓库,更新远程仓库的 URL 到新的仓库地址。

git remote set-url origin 新仓库地址

注:尽管上一步已经清理了本地未引用对象,但由于 GitLab 服务器可能对某些对象设置了保护机制,不允许直接清除。如果尝试将更改推送到原仓库,可能会因权限问题导致操作失败。即使强制推送,由于服务器上仍保留部分旧对象,拉取项目时可能会变得更慢,因为 .git (裸仓库)会同时包含旧对象、新对象和未引用对象,导致体积膨胀。因此,建议将迁移后的仓库推送到一个新的远程仓库,以避免此类问题。

第五步:推送到新的远程仓库。

git push --force

第六步:重新拉取代码,便能够在.git(裸仓库)中发现lfs文件夹。


三、BFG Repo-Cleaner(BFG)

BFG是专门为清理 Git 仓库历史中的大文件或敏感文件而设计的工具,它直接操作 Git 的对象模型,避免了 Git 的一些额外开销,因此速度更快。在1.12.5版时,开始支持Git LFS。

​编辑

具体操作:发布 Git LFS 支持 ·rtyley/bfg-repo-cleaner


四、git-lfs-migrate(推荐)

git-lfs-migrate提供了一个更简单的命令行接口,用户只需指定需要迁移的文件类型或路径,工具会自动处理历史重写和 Git LFS 迁移的细节,而且还封装了原生 Git LFS 迁移的多个步骤(如 git lfs migrate import 和 git reflog expire 等),减少了用户手动操作的复杂度。

​编辑

具体操作:bozaro/git-lfs-migrate: 用于转换旧仓库以使用 git-lfs 功能的简单项目


五、总结

本篇主要介绍了,Git LFS加快Git拉取的原理,并介绍了原生、BFG Repo-Cleaner、git-lfs-migrate三种迁移方式。