资讯动态

Git LFS 实战:大文件托管与仓库瘦身完整指南

发布时间:2026/10/9 14:20:27 来源:尧图企业网站定制
Git 是绝大多数开发者和运维每天都要摸的版本控制工具而我第一次认真研究 Git LFS是因为一个仓库被大文件撑爆了。当时项目里混了几百 MB 的设计稿、安装包和模型权重每次 git push 都像在寄大件快递GitHub 直接弹出“单文件超过 100MB”的报错本地 .git 目录一路膨胀到几个 GB克隆一次能等半小时。后来我花了一个下午把 Git LFS 彻底用起来仓库从 4GB 瘦到不足 200MB团队协作才重新变得顺畅。这篇文章不绕弯子直接从 Git 和 Git LFS 的实际使用出发把为什么要用、怎么装、怎么配、怎么迁移、团队怎么配合以及我踩过的那些坑全部摊开讲清楚。适合刚装好 Git 正在走流程的新手也适合仓库已经开始臃肿、想用 LFS 治本的进阶用户。1. 为什么需要Git LFS仓库膨胀这个大坑踩过的人才懂1.1 大文件混进Git仓库后会发生什么Git 本身是为文本型源码设计的版本控制工具它保存的不是“文件的变化”而是每个文件在每次提交时的完整快照。这个设计对源码来说很合理因为文本文件体积小压缩率高差分化能力强。但一旦放进来的是二进制大文件事情就完全变味了。举个实测例子一个 500MB 的设计源文件你改了 10 次每次修改都会在 .git 对象库里生成一个新版本的完整 blob 对象。因为二进制文件压缩空间有限而且 Git 对二进制不做增量差分10 个版本就接近 5GB。哪怕你只是改了一个图层、换了一个字体Git 也会老老实实把整个新版本存一遍。这个体积增长不是线性的而是和提交次数强相关改得越频繁仓库膨胀得越凶。仓库变大的直接后果首先是 clone 变慢。新同事拉一次代码要把全量历史对象都下载下来几百 MB 到几个 GB 的项目等十分钟都算正常。其次是 IDE 卡顿IDEA、VS Code 在打开这类仓库时要解析大量对象索引文件一多内存和 CPU 直接拉满。更麻烦的是托管平台的限制GitHub 默认单文件超过 100MB 就会拒绝 pushGitee 也有类似限制一旦触发你连历史提交都推不上去。这里有个生活化的类比普通 Git 仓库就像一个衣柜但你这个衣柜里塞的不是“当前穿的衣服”而是每一件衣服过去所有穿过、改过的版本原件。每换一次款就往衣柜里多塞一件完整的旧款。搬家的时候你得扛着整柜子走。Git LFS 做的事很简单把“历史旧款”全部转移到另一个仓库堆放衣柜里只留一张写着你当前穿哪件的卡片。1.2 Git LFS究竟帮你干了什么Git LFS 的全称是 Large File Storage翻译过来就是大文件存储。它的核心思路不是压缩大文件而是把大文件从 Git 仓库历史中抽离出去。当你用 LFS 跟踪某个文件类型后这个文件的真实内容会存到一个独立的 LFS 对象存储里而 Git 仓库中只保存一个几 KB 的文本指针文件。这个指针记录了真实文件的 SHA-256 哈希和大小Git 提交、分支、合并时操作的只是指针开销小到可以忽略。这样带来的直接收益有三个。第一仓库体积大幅下降clone、pull、push 都恢复成普通源码仓库的速度第二二进制大文件的版本历史由 LFS 存储统一管理你可以随时拉取任意历史版本的真实文件第三大文件在多个分支间共享时同一个 SHA-256 的对象只存一份天然去重。那是不是所有文件都应该走 LFS当然不是。LFS 适合的是二进制、体积大、不便差分的内容比如设计源文件PSD、AI、音视频素材MP4、WAV、压缩包ZIP、7z、模型权重文件h5、pt、pkl、固件包bin、img等。像源码、配置、文档这类文本内容应该继续走普通 Git因为普通 Git 对文本有更好的压缩和差分能力提交历史也更清晰。如果把源码也强行丢进 LFS反而会增加 LFS 对象数量拖慢整体性能。还有一个容易误解的点LFS 并不是把文件“压缩后塞进 Git 仓库”。它是一套独立的传输与存储机制。真实文件存在 LFS 存储端Git 远端只有指针。clone 时你不会立刻下载所有大文件对象而是在 checkout 需要用到某个版本时才从 LFS 存储拉取对应内容。这也是为什么 Git 仓库瘦身之后clone 速度能提升几个数量级。2. 快速上手装好环境20分钟跑通第一次LFS提交2.1 Git和Git LFS环境准备Windows/macOS/Linux先用 Git LFS 之前必须确认机器上已经装好 Git 和 Git LFS 两个东西。很多人只装了 Git一执行 git lfs 命令就报“command not found”然后以为是自己项目配错了其实只是少了 LFS 客户端。Windows 下推荐从 Git 官网下载官方安装包装的时候默认勾选 Git Bash 和 Git GUI 组件。Git Bash 是 Linux 风格的终端后面敲命令会顺手很多。装完 Git 后再单独下载 Git LFS 安装包一路下一步即可。装完打开 Git Bash执行git lfs version能看到版本号就说明安装成功。随后在任意目录跑一次git lfs install这条命令会在全局配置里注册 Git 的 clean/smudge 过滤器之后所有仓库都默认支持 LFS。macOS 上如果已经装了 Homebrew直接brew install git-lfs然后git lfs install就够了。Linux 用户可以用发行版自带的包管理器比如 Debian/Ubuntu 执行sudo apt install git-lfsCentOS/RHEL 用sudo yum install git-lfs。装完后同样要执行git lfs install。这里顺带提一下基础配置。打开终端执行git config --global user.name 你的名字和git config --global user.email 你的邮箱否则第一次提交会报错。另外建议提前配好 SSH 密钥尤其是 LFS 传大文件时SSH 比 HTTPS 更稳定不容易因长时间传输断线。Windows 下用ssh-keygen -t rsa -b 4096 -C 你的邮箱生成密钥然后打开~/.ssh/id_rsa.pub把内容复制到 Gitee 或 GitHub 的 SSH 公钥设置页。加好之后用ssh -T gitgitee.com或ssh -T gitgithub.com验证能看到欢迎语就说明认证通了。很多“SSH 认证失败”的报错十有八九是公钥没添加或者用户名格式写成了git之外的地址。2.2 给仓库装上LFStrack命令与.gitattributes环境就绪后进入项目目录操作。无论是新初始化的仓库还是已经存在的仓库都可以在项目根目录下执行git lfs track。这条命令的作用是告诉 Git“以后凡是匹配这些规则的文件一律走 LFS 流程”。比如我想管理设计源文件、压缩包和模型文件可以这样写git lfs track *.psd git lfs track *.zip git lfs track *.h5 git lfs track *.pt每次执行git lfs trackGit LFS 都会自动更新或创建项目根目录下的.gitattributes文件。这个文件是仓库的一部分必须提交到远端否则其他同事 clone 下来后不会自动匹配 LFS 规则。提交.gitattributes和提交源码一样正常执行git add .gitattributes git commit -m 添加 Git LFS 跟踪规则这里有个新手最容易踩的坑一定要先 track再 add 大文件。如果大文件已经被git add进了暂存区哪怕你后面再执行git lfs track这个文件也已经按普通 Git 对象暂存了LFS 不会自动把它捞出来。此时需要重新处理最简单的方式是git rm --cached 大文件取消暂存然后重新git add。如果文件已经提交进历史了就要用到后面说的 migrate 方案。一切正常的话添加真正的大文件时Git 会在 add 阶段调用 LFS 的 clean 过滤器把真实文件内容交给 LFS 缓存同时生成一个指针文本。push 到远端时终端里会显示Uploading LFS objects: 100% (n/n), xx MB | ...这样的进度这就说明 LFS 生效了。可以用git lfs ls-files查看当前仓库里有哪些由 LFS 跟踪的文件以及它们的状态。3. Git LFS核心原理指针文件、smudge/clean过滤与对象存储3.1 指针文件长什么样为什么它能让仓库瘦身理解了 LFS 的基本流程再深入看它的实现机制后面排查问题时就会清晰很多。Git LFS 的过滤机制依赖 Git 的两类 hook 函数clean 和 smudge。clean 在文件从工作区进入暂存区时触发它读取原始文件计算出 SHA-256 哈希把真实内容写入本地 LFS 对象缓存然后把一个文本指针交给 Git 去版本化smudge 在 checkout 或 clone 时触发它读取指针文件根据 oid 去本地缓存或远程存储拉取真实文件并写回到工作区。所以你在工作区里看到的始终是原始大文件操作上没有任何感知差异。但 Git 仓库内部保存的其实是一个只有几行的文本内容长这样version https://git-lfs.github.com/spec/v1 oid sha256:8f22cf8e24edc1e1d1f8f8b1d0f8c0f2e3a9f4f3f0c7e22b7adb0e18cff08125 size 524288000第一行是 LFS 规范版本号第二行是真实文件的哈希标识第三行是这个文件的字节大小。Git 分支、合并、提交操作的都是这个几 KB 的文本自然轻快得多。打个比方你去商场购物不希望手里捧着大包小包满场跑于是把物品寄存到储物柜只拿一张小票去付款。Git 就是那个拿着小票付款的人而 LFS 是储物柜管理员。你需要真正使用文件时亮出小票指针文件管理员就把对应物品送过来。Git 仓库里存的只是小票而不是物品本身所以历史记录再长也不会出现物品堆积。这里还有个细节值得注意同一个文件内容永远对应同一个 oid所以无论这个文件被复制到多少个目录、被多少个分支引用LFS 存储端都只保留一份真实对象。这也是 LFS 能有效控制存储成本的原因之一。3.2 本地缓存、远程存储与配额计费必须知道的现实问题LFS 的真实对象并不放在 .git 仓库里而是放在本地缓存和远程 LFS 存储两端。本地缓存在 Windows 下通常位于用户目录的~/.git/lfs/objectsLinux/macOS 同理项目内的.git/lfs/objects也可能存在一份。你可以用git lfs env查看当前生效的缓存路径和远程存储地址。远程存储由你使用的托管平台决定。GitHub、GitLab、Gitee 等主流平台都内置了 LFS 服务你只要按对应仓库的 LFS 地址 push 即可。如果是自建 Git 服务器比如 Gitea、GitLab CE需要确保服务器端开启了 LFS 支持或单独部署 LFS 存储服务。配额这个问题很多人直到 push 失败才意识到。GitHub 免费账号的 LFS 存储空间是 1GB带宽每月也是 1GB。这里的“带宽”指的就是下载流量只要有人 clone 仓库、checkout 历史版本、切换到包含大文件的分支都会消耗。如果你的项目里放了一个 800MB 的模型文件两个人各 clone 一次当月带宽基本就耗光了。Gitee 的 LFS 配额也是免费额度有限超出后需要付费扩容或禁止使用。所以我的建议是LFS 适合放“项目开发过程中必须随时同步”的资产比如工程依赖的模型、UI 素材、测试固件。对于几百 GB 级别的数据集、海量日志、完整备份不要往 LFS 里塞那应该放到对象存储、网盘或 CDN 上用独立下载链接管理。真要把大数据集接入项目可以考虑在代码里写一个自动化拉取脚本而不是把数据本身交给 LFS。4. 实操记录完成一次仓库级LFS迁移与团队协作4.1 把已经在Git历史里的大文件迁到LFS含历史重写与不重写方案如果你的仓库是新项目问题不大随时可以用 LFS。但更多人的情况是“我已经在一个仓库里提交了大量大文件历史已经脏了怎么办”先说最简单的方案从当前时间点开始使用 LFS。在项目根目录执行git lfs track加上想要管理的大文件类型提交.gitattributes之后新加入的大文件走 LFS 流程。这个方式的好处是无风险、不会改变历史记录适合新手或团队协作频繁、不便重写历史的场景。但它有一个明显的短板已经被提交进历史的大文件对象仍然留在 Git 对象库里。仓库体积并不会因为你新增了 LFS 规则而自动缩小你只是阻止了它继续恶化。如果你确实想彻底瘦身就需要重写历史。Git LFS 提供了git lfs migrate命令专门做这件事。操作过程分两步git lfs migrate info --everything这条命令先扫描仓库按文件类型统计历史中占用空间最大的扩展名。输出会告诉你哪些类型最“吃体积”比如*.psd占了多少 MB、*.zip占了多少 MB。确认目标后执行导入git lfs migrate import --include*.psd,*.zip,*.h5 --everything--everything表示重写所有分支、所有历史提交。迁移完成后这些大文件对象会从 Git 历史中移除替换为 LFS 指针真实内容转存到 LFS 存储。仓库体积立刻能降下来。但这里必须强调几个注意事项。第一git lfs migrate会改变所有涉及提交的 commit hash分支历史与原来完全不同所有同事需要强制同步并且要提前把工作区改动交干净。第二执行前务必完整备份仓库我通常是直接cp -r 仓库目录 仓库目录.bak备份后即使中途出错也能恢复。第三迁移操作需要足够磁盘空间因为 LFS 要在本地生成对象缓存仓库如果原本有几个 GB磁盘最好预留相同甚至双倍的剩余空间。第四迁移完成后推送远端普通git push会拒绝需要用git push --force --all和git push --force --tags强制更新。强制推送是一把双刃剑团队人多时一定要提前告知并统一操作窗口。4.2 团队协作的LFS工作流克隆、分支合并、拉取与提交规范仓库迁移完成后团队每个人都需要更新本地环境。最干净的协作方式是统一先确认本机git lfs version正常然后重新 clone 仓库。默认情况下git clone在执行 checkout 时会自动触发 smudge 过滤器把当前分支所需的所有 LFS 对象从远端拉取到本地。如果你只想先拿一份没有大文件的源码做快速分析可以用跳过 smudge 的方式GIT_LFS_SKIP_SMUDGE1 git clone 仓库地址这样本地只见指针文件真实大文件不会下载等需要时再手动git lfs pull。这在 CI 环境或内存紧张的开发机上非常实用。日常开发中git fetch和git pull的差别在 LFS 场景下会更明显。git fetch默认只更新远端引用不会把 LFS 对象拉到本地git pull则是 fetch 加 merge同时会调用 LFS 的 smudge把当前分支需要的新对象下载下来。如果团队有人只执行了 fetch 没执行 merge工作区里可能出现指针文件而非真实文件此时运行git lfs pull就能补齐。分支合并和 rebase 时因为 LFS 文件在 Git 内部是文本指针大部分情况下 merge 可以被 Git 自动处理不会像二进制文件那样频繁冲突。但如果两个分支对同一个大文件做了不同修改merge 时会在指针层面出现冲突。这时候不要直接手动编辑指针文件正确做法是保留其中一个版本的指针然后重新用git lfs checkout拉取对应真实文件确认内容后再重新提交。还有几个团队层面值得提前约定的事项。提交时一个 commit 尽量只包含一个明确的大文件变更方便别人 review 和回滚。使用git commit --amend修改最近一次提交的注释或追加漏掉的文件时要注意 amend 会生成新的 commit而 LFS 对象本身不会重新上传因为 oid 没变所以整体操作很安全。另外远程地址管理要统一推荐用 SSH 协议而不是 HTTPS因为 LFS 大文件传输耗时长SSH 断了重连的体验好很多而且不需要频繁输入 token。5. 常见问题与排查技巧实录5.1 问题速查表表格形式下面这张表是我在实际使用 Git 和 Git LFS 过程中整理的高频问题原因和解法都是验证过的遇到情况可以直接照着查。问题现象可能原因排查思路与解决push 大文件时报 remote 拒绝提示文件过大没有配置 LFS 跟踪规则或托管平台单文件限制 100MB先执行git lfs track并提交.gitattributes确认git lfs ls-files里有该文件若在其他仓库已是大文件需用git lfs migrate重写历史clone 后大文件是文本指针而不是真实文件本地未执行git lfs install或 clone 时设置了GIT_LFS_SKIP_SMUDGE1执行git lfs install然后git lfs pull确认远端确实有 LFS 对象LFS push 时报认证失败凭据过期、token 权限不足、SSH 密钥未添加HTTPS 时重新生成并配置 tokenSSH 时用ssh -T gitgitee.com检查连通性确认公钥已上传过滤文件规则.gitattributes不生效大文件已经被 Git 跟踪pattern 写法不对或 .gitattributes 位置不在仓库根目录执行git ls-files看文件是否已入索引已入索引则先git rm --cached file再重新 add使用git check-ignore -v file验证规则仓库体积没有缩小历史提交中仍然保留大文件对象LFS 只影响新提交使用git lfs migrate info定位大文件再用git lfs migrate import --everything重写历史之后运行git gc整理对象库LFS 下载很慢或断线网络不稳定、LFS 对象较大、使用了 HTTPS 长连接被中断改用 SSH 协议在网速稳定的环境下执行git lfs pull必要时拆分大文件拆成多个小对象分次管理git commit --amend后看不到预期效果没有理解 amend 只会修改最近一次提交确认工作区改动已经 addamend 时如需新增文件先 add 再 amend不要对已经推送的提交随意 amend除非确认会强制推送.git目录被 Web 服务器暴露站点配置将仓库根目录设为可访问且没有拒绝 .git 路径在 Nginx/Apache 配置中显式禁止访问.git目录不要把 Git 仓库直接当作网站根目录同时检查.gitignore避免敏感配置文件入库5.2 避坑心得与老手建议Git 和 Git LFS 的坑大多不是功能本身的问题而是使用习惯和协作规范的问题。我总结几条经过反复验证的经验供你参考。第一新仓库从第一天就确定 LFS 边界。在项目根目录建一个清晰的目录约定比如assets/、models/、dist/专门放大文件写进 README。这样团队新成员拉仓库、提交文件时闭着眼睛都知道什么该走 LFS什么不该走。第二track 规则要朝向目录不要用全局通配符无脑匹配。比如git lfs track assets/**/*.png比git lfs track *.png更安全。全局匹配会把散落在代码目录里的图片也纳入 LFS而这些图片本该正常提交。LFS 对象数量一旦过多clone 时 smudge 会逐个下载整体体验照样会变慢。第三定期执行git lfs prune清理本地缓存。本地缓存里的旧版本对象会占用大量磁盘空间prune会删除那些没有被任何 checkout 使用、且远端已存在的对象。注意在跑 prune 前确认当前工作区是稳定的没改完的文件先 commit 或 stash。第四CI 环境不要无脑全量拉取 LFS 对象。构建机上执行git clone时如果默认拉取了所有 LFS 对象既占磁盘又费时间。正确做法是GIT_LFS_SKIP_SMUDGE1 git clone然后按构建需求用git lfs pull --includesdks/**,models/**定向拉取需要的子集。这样构建速度能快非常多。第五换电脑、重装系统之前先把本地还没推过的 LFS 对象 push 到远端。LFS 对象不像 Git 对象会自动出现在每个仓库副本里它依赖远端存储同步。如果旧机器上的本地缓存没有 push新机器git lfs pull会失败只能用git lfs fetch --all从远端找回或者干脆丢失未上传的版本。第六不要用 Git 命令行之外的 GUI 工具盲目推送大文件。IDEA 的 Git 插件、Git GUI、Tower 等工具对 LFS 的支持参差不齐。命令行下git lfs track后再用图形工具拉取时有时候图形工具不会自动执行git lfs install注册的过滤器导致大文件被当成普通文件提交。遇到这种情况回命令行再操作一遍或者用git lfs migrate补救。写到这里多说两句体会。我最早就是没在意把一个包含大量设计稿和安装包的仓库直接丢进 Git结果仓库一路飙到 4GB同事克隆一次能等一上午。后来下定决心用git lfs migrate重写历史虽然过程折腾但仓库最终瘦到不足 200MB日常操作终于恢复正常。现在团队的约定很简单凡是放到 assets、dist、models 目录下的二进制大文件一律走 LFS凡是源码、配置、文档永远走普通 Git。不要等仓库膨胀再来修开工第一天就把 LFS 规则定好能省掉后面无数麻烦。如果哪天你也遇到“Git push 大文件失败”“仓库越来越大”这类问题希望这篇文章里的思路和避坑清单能帮你少走点弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑