git 大型项目管理
git 作为一个版本控制工具,管理的通常是一些占用磁盘空间不大的源代码文件等。但是实际应用中,git 也会被用于管理大型项目。
以下介绍了三种可能应用于大型项目管理的方案。
Git LFS
Git LFS 主要用于管理大型文件和二进制文件,例如游戏开发中的美术资源、视频文件、大型数据集等。它通过将大文件的指针存储在 Git 仓库中,而将文件存储在远程的 LFS 存储中,从而避免 Git 仓库变得过于庞大。
使用
安装 git-lfs
1 | sudo pacman -S git-lfs |
其他发行版使用对应的包管理器安装
在一个本地的 Git 仓库中
初始化 git-lfs 的 Git hooks
1 | git lfs install |
查看文件状态
1 | git lfs status |
创建一个大文件 2GB
1 | dd if=/dev/random of=./large_file bs=1024M count=2 |
添加文件到 lfs
1 | git lfs track "large_file" |
支持通配符 (需要使用引号包围名称及通配符,否则会被 shell 解析为匹配的路径)
1 | git lfs track "*.png" # 当前目录下所有 png 文件 |
也可以指定添加文件夹
1 | git lfs track "large_dir/**" # large_dir 目录下所有文件和子目录 |
添加完成后会产生一个 .gitattributes 文件,记录了被 git-lfs 跟踪的大型文件
将大型文件添加到缓存区
1 | git add large_file |
查看 lfs 跟踪的文件
1 | git lfs ls-files |
移除文件
取消对该文件或文件夹的跟踪
1 | git lfs untrack "large_file" |
从缓存区移除文件
1 | git rm -r --cached large_file |
清理不再跟踪或“悬挂”的 LFS 对象
1 | git lfs prune |
推送本地仓库到远程仓库,注意提交包含 LFS 跟踪信息的 gitattributes 文件
1 | git push |
当克隆一个包含 Git LFS 跟踪的大型仓库时
git clone
- 对于 Git LFS 跟踪的文件,
git clone
会下载这些文件的指针(即.git/lfs/objects
中的引用),但不会立即下载文件的实际内容。 git clone
可能会很快完成,因为大文件的指针相对较小。
git lfs pull
- 这个命令专门用于下载 LFS 跟踪文件的实际内容。
git lfs pull
来确保这些文件的完整内容被下载到本地。
通常 git clone
之后再执行 git lfs pull
以得到最新的完整仓库。
将已有的项目迁移到 LFS
将所有的 png 文件导入 LFS 中
1 | git lfs migrate import --everything --include="*.png" |
将 main 分支中所有大于 100Kb 的文件导入 LFS 中
1 | git lfs migrate import --include-ref=main --above=100Kb |
推送
1 | git push --force --all |
远程服务端执行的 gc 命令,清理仓库,通常不需要手动执行
1 | git --git-dir=git-repo.git gc --prune=now |
演示
在本地搭建一个 git 远程仓库
1 | mkdir large-repo |
克隆到本地仓库
1 | git clone /home/entropy/Public/large-repo/large-repo.git |
开启 Git LFS
1 | git lfs install |
开启后会在用户目录下的 .gitconfig 中增加一个 filter 配置
1 | cat ~/.gitconfig |
1 | [filter "lfs"] |
同时在 .git/hooks 中增加了几个 hook 脚本,增加了 .git/lfs 目录
增加对一个大文件的跟踪
1 | git lfs track '*.bin' |
将文件修改为 1K 大小并提交推送
1 | dd if=/dev/random of=a.bin bs=1024 count=1 |
重新克隆仓库,查看仓库大小
1 | cd .. |
可以发现仓库并没有下载原来 10MB 大小的文件
切换到上一个版本,这个版本中包含 10MB 大小的文件
1 | git checkout HEAD~1 |
LFS 会在 checkout 之后从远程仓库拉取文件到本地,再拷贝到工作目录中,因此整个目录大小变成了 20MB
如果只想保留最新版本,可以执行 git lfs prune
删掉历史数据
1 | git checkout master |
使用不同的方式配置跟踪文件
1 | git lfs track '**/*.png' |
迁移已有项目到 LFS
1 | dd if=/dev/urandom of=c.zip bs=1M count=10 |
稀疏克隆
稀疏克隆 (sparse-clone) 允许用户在克隆仓库之后,通过指定某个文件夹或某个文件的路径,仅下载这部分指定的内容,适用于只关注大型仓库中的部分内容的情况。
单独使用稀疏克隆还是会克隆整个仓库的历史和分支,只是不会立即检出。通常稀疏克隆可以和其他参数配合使用,以克隆一个比较精简的仓库。例如,配合 --filter
过滤和 --depth
克隆深度,可以明显减小大型仓库在克隆时的大小。
1 | git clone --filter=blob:none --depth 1 --sparse <git-repo-url> |
使用
初始化稀疏检出,在克隆仓库时使用 --sparse
选项,表示稀疏克隆,不会下载所有内容,但是会下载位于项目根目录下的文件。
1 | git clone --filter=blob:none --depth 1 --sparse <git-repo-url> |
查看 git 仓库中记录的文件和目录,用于后续设置稀疏检出路径
1 | git ls-files |
设置稀疏检出路径,设置 src 和 docs 目录,会自动下载这两个目录的内容
1 | git sparse-checkout set src docs |
添加稀疏检出路径,在已有目录的基础上添加额外的目录,不会覆盖前面设置的稀疏检出路径,使用 set
则会重新设置稀疏检出路径。
1 | git sparse-checkout add tests |
稀疏检出路径会记录在 .git/info/sparse-checkout 文件中。
恢复完整检出,将会下载所有内容
1 | git sparse-checkout disable |
Git Submodules
子模块允许在一个 Git 仓库中嵌套另一个 Git 仓库,适用于项目需要依赖外部库或多个项目需要共享代码的情况。
使用
添加子模块
1 | git submodule add <git-repo-url> module |
添加完成后会在项目根目录下生成一个 .gitmodules 文件,记录了子模块的本地和远程地址信息
查看子模块信息
1 | git submodule |
更新子模块
1 | git submodule update |
修复头指针分离问题
1 | git branch -f main HEAD # 将 main 分支强制指向当前头指针的位置 |
克隆包含子模块的项目
在子模块的目录内执行以下命令递归初始化并下载子模块的内容
1 | git submodule update --init --recursive |
或者分为初始化子模块和更新子模块两步
1 | git submodule init # 初始化子模块 |
也可以在克隆时一步到位地下载所有内容
1 | git clone --recursive <git-repo-url> |
删除子模块的步骤比较繁琐
1.删除子模块文件夹
1 | git rm -r --cached module |
2.删除 .gitmodules 文件中相关子模块的信息 (如果存在),类似于
1 | [submodule "module"] |
3.删除 .git/config 文件中相关子模块的信息 (如果存在)
4.删除 .git 文件夹中的相关子模块文件 (如果存在)
1 | rm -rf .git/modules/module |
参考资料
- 标题: git 大型项目管理
- 作者: Entropy Tree
- 创建于 : 2024-06-28 00:42:25
- 更新于 : 2024-08-14 16:08:02
- 链接: https://www.entropy-tree.top/2024/06/28/git-work-with-large-repo/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。