Appearance
大仓库优化
概述
随着项目的发展,Git 仓库可能会变得非常大,导致克隆、拉取、推送等操作变慢。本章介绍大仓库的优化策略和技巧。
大仓库问题
常见问题
bash
# 克隆速度慢
git clone https://github.com/large-project/project.git
# 可能需要几分钟甚至更长时间
# 拉取速度慢
git pull origin main
# 每次拉取都需要传输大量数据
# Git 操作变慢
git status
git log
git diff
# 响应时间明显增加
# 磁盘空间占用大
du -sh .git
# 可能达到几 GB问题原因
| 原因 | 说明 |
|---|---|
| 历史记录长 | 多年开发积累大量提交 |
| 大文件 | 包含大型二进制文件 |
| 频繁提交 | 每次提交都保存完整快照 |
| 分支众多 | 大量分支和标签 |
| 未清理 | 未运行垃圾回收 |
分析仓库大小
bash
# 查看仓库大小
du -sh .git
# 查看各目录大小
du -sh .git/*
# 查看最大的文件
git rev-list --objects --all | \
git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | \
sed -n 's/^blob //p' | \
sort --numeric-sort --key=2 | \
tail -20
# 使用 git-sizer 工具
# 安装: go install github.com/github/git-sizer@latest
git-sizer
# 查看提交数量
git rev-list --count HEAD
# 查看分支数量
git branch -a | wc -l
# 查看标签数量
git tag | wc -l单体仓库策略
Monorepo 概述
单体仓库(Monorepo)是将多个项目放在一个仓库中的策略。
优点:
- 统一版本管理
- 简化依赖管理
- 方便代码共享
- 原子提交
缺点:
- 仓库体积大
- 克隆时间长
- 权限控制复杂
Monorepo 优化策略
1. 目录结构优化
monorepo/
├── packages/
│ ├── core/
│ ├── utils/
│ └── ui/
├── apps/
│ ├── web/
│ └── mobile/
├── docs/
└── tools/2. 使用工作区
json
// package.json
{
"workspaces": [
"packages/*",
"apps/*"
]
}3. 分离关注点
bash
# 将大型组件拆分为独立仓库
# 使用子模块或子树引用部分克隆
概述
部分克隆(Partial Clone)允许只下载部分对象,按需获取其他内容。
类型
| 类型 | 说明 | 命令 |
|---|---|---|
| 无 Blob 克隆 | 不下载文件内容 | --filter=blob:none |
| 树深度限制 | 限制历史深度 | --filter=tree:<depth> |
| Blob 大小限制 | 不下载大文件 | --filter=blob:limit=<size> |
无 Blob 克隆
bash
# 克隆时不下载文件内容
git clone --filter=blob:none https://github.com/user/repo.git
# Git 会在需要时自动下载文件内容
# 适合只需要历史记录的场景Blob 大小限制
bash
# 不下载超过 1MB 的文件
git clone --filter=blob:limit=1m https://github.com/user/repo.git
# 大文件会在需要时下载树深度限制
bash
# 限制树的深度
git clone --filter=tree:0 https://github.com/user/repo.git
# 只下载根目录的树对象配置部分克隆
bash
# 配置默认使用部分克隆
git config --global clone.filter blob:none
# 配置按需获取的行为
git config --global fetch.showForcedUpdates false部分克隆的限制
bash
# 某些操作需要完整对象
git blame file.txt # 可能需要下载文件
# 解决方法:预先获取
git fetch --unshallow性能优化技巧
1. 使用浅层克隆
bash
# 只克隆最近的提交历史
git clone --depth 1 https://github.com/user/repo.git
# 后续可以获取更多历史
git fetch --unshallow2. 单分支克隆
bash
# 只克隆单个分支
git clone --single-branch --branch main https://github.com/user/repo.git
# 减少不必要的历史下载3. 使用 Git LFS
bash
# 安装 Git LFS
brew install git-lfs # macOS
apt install git-lfs # Linux
# 初始化
git lfs install
# 跟踪大文件
git lfs track "*.psd"
git lfs track "*.zip"
git lfs track "assets/*"
# 查看跟踪规则
git lfs track
# 克隆包含 LFS 的仓库
git lfs clone https://github.com/user/repo.git4. 优化 Git 配置
bash
# 增加缓存大小
git config --global core.packedGitLimit 512m
git config --global core.packedGitWindowSize 512m
# 增加 delta 缓存
git config --global core.deltaBaseCacheLimit 512m
# 启用并行处理
git config --global core.preloadindex true
# 优化 status 性能
git config --global core.untrackedCache true
# 使用更快的状态检查
git config --global status.showUntrackedFiles all5. 使用 sparse-checkout
bash
# 初始化仓库
git init repo
cd repo
git remote add origin https://github.com/user/large-repo.git
# 启用稀疏检出
git sparse-checkout init --cone
# 只检出需要的目录
git sparse-checkout set packages/core apps/web
# 拉取代码
git pull origin main
# 添加更多目录
git sparse-checkout add packages/utils
# 查看当前配置
git sparse-checkout list
# 禁用稀疏检出
git sparse-checkout disable6. 优化 .gitignore
bash
# 忽略不需要跟踪的文件
# .gitignore
# 构建产物
dist/
build/
*.min.js
# 依赖目录
node_modules/
vendor/
# IDE 配置
.idea/
.vscode/
*.swp
# 系统文件
.DS_Store
Thumbs.db
# 日志文件
*.log
logs/
# 临时文件
tmp/
temp/
*.tmp7. 定期清理
bash
# 清理未跟踪的文件
git clean -fd
# 清理忽略的文件
git clean -fdX
# 清理所有未跟踪文件
git clean -fdx
# 清理远程已删除的分支
git remote prune origin
# 清理 reflog
git reflog expire --expire=now --all
# 运行垃圾回收
git gc --prune=now --aggressive8. 使用 bundle
bash
# 创建 bundle 文件
git bundle create repo.bundle --all
# 从 bundle 克隆
git clone repo.bundle repo
# 从 bundle 获取更新
git bundle create updates.bundle origin/main..HEAD
git fetch updates.bundle main:main大文件处理
查找大文件
bash
# 查找历史中的大文件
git rev-list --objects --all | \
git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | \
awk '/^blob/ {print $3, $4}' | \
sort -n | \
tail -20
# 使用脚本
#!/bin/bash
# find-large-files.sh
git rev-list --objects --all | \
while read hash path; do
if [ -n "$path" ]; then
size=$(git cat-file -s $hash 2>/dev/null)
echo "$size $path"
fi
done | sort -n | tail -20移除大文件
bash
# 使用 git-filter-repo 移除大文件
pip install git-filter-repo
# 移除特定文件
git filter-repo --path large-file.zip --invert-paths
# 移除大文件(超过 10MB)
git filter-repo --strip-blobs-bigger-than 10M
# 清理
git reflog expire --expire=now --all
git gc --prune=now --aggressive使用 BFG Repo-Cleaner
bash
# 安装 BFG
brew install bfg # macOS
# 删除大文件
bfg --delete-files large-file.zip
# 删除超过 50MB 的文件
bfg --strip-blobs-bigger-than 50M
# 清理
git reflog expire --expire=now --all
git gc --prune=now --aggressive
git push --force性能监控
Git 内置诊断
bash
# 查看 Git 配置
git config --list --show-origin
# 检查仓库完整性
git fsck
# 统计仓库信息
git count-objects -v
# 输出示例:
# count: 1234
# size: 5678
# in-pack: 9012
# packs: 3
# size-pack: 4567
# prune-packable: 0
# garbage: 0
# size-garbage: 0使用 git-sizer
bash
# 安装
go install github.com/github/git-sizer@latest
# 分析仓库
git-sizer --verbose
# 输出:
# Processing blobs: 12345
# Processing trees: 6789
# Processing commits: 1234
# Processing commits: done
#
# | Name | Value | Level of concern |
# | ---------------------------- | --------- | ------------------------------ |
# | Overall repository size | | |
# | * Commits | | |
# | * Count | 1,234 | |
# | * First commit | 2020-01-01| |
# | * Trees | | |
# | * Count | 6,789 | |
# | * Blobs | | |
# | * Count | 12,345 | |
# | * Total size | 123.4 MiB| * |最佳实践
1. 预防措施
bash
# 使用 pre-commit 钩子检查文件大小
#!/bin/bash
# .git/hooks/pre-commit
MAX_SIZE=10485760 # 10MB
for file in $(git diff --cached --name-only); do
if [ -f "$file" ]; then
size=$(stat -f%z "$file" 2>/dev/null || stat -c%s "$file" 2>/dev/null)
if [ "$size" -gt "$MAX_SIZE" ]; then
echo "错误: 文件 $file 超过 10MB"
exit 1
fi
fi
done
exit 02. 定期维护
bash
#!/bin/bash
# maintenance.sh
echo "清理远程分支..."
git remote prune origin
echo "清理 reflog..."
git reflog expire --expire=30.days.ago --all
echo "运行垃圾回收..."
git gc --prune=now
echo "检查仓库完整性..."
git fsck
echo "维护完成!"3. CI/CD 优化
yaml
# GitHub Actions 优化示例
jobs:
build:
runs-on: ubuntu-latest
steps:
# 浅层克隆
- uses: actions/checkout@v3
with:
fetch-depth: 1
# 或稀疏检出
- uses: actions/checkout@v3
with:
sparse-checkout: |
src/
package.json总结
| 策略 | 命令 | 适用场景 |
|---|---|---|
| 浅层克隆 | git clone --depth 1 | 只需要最新代码 |
| 单分支克隆 | git clone --single-branch | 只需要特定分支 |
| 部分克隆 | git clone --filter=blob:none | 需要历史但不需要文件 |
| 稀疏检出 | git sparse-checkout | 只需要部分目录 |
| Git LFS | git lfs track "*.psd" | 大型二进制文件 |
优化建议:
- 使用 Git LFS 管理大文件
- 定期运行垃圾回收
- 使用部分克隆减少下载量
- 配置合适的 .gitignore
- 预防大文件进入仓库
