git bundle 到底是什么,为什么运维都用它做离线备份和跨网迁移?
文丨唐莫盈
一、先来个你大概率遇到过的场景
你要把一个带完整提交历史的 Git 仓库,挪到另一台机器上。
那台机器在隔离网(涉密机房、工控环境、飞机上的笔记本),连不上公司 GitLab;或者要发给客户的内网,两边根本没有互相可达的代码服务器;又或者公司的远程仓库正好挂了,但同事就坐在你旁边,U 盘能传。
这时候第一反应往往是:把整个 .git 目录拷进 U 盘。能用,但三个坑立刻冒出来——
① .git 是目录不是文件,拷起来慢,还容易漏了隐藏文件;② 拷完你没法校验完整性,传坏了一点头铁不知道;③ 下次只改了 10 个提交,你又得把整个目录再拷一遍。
git bundle 就是为这种"没网、或者不想走服务器"的场景生的。一条命令,把整个仓库打包成一个自包含的二进制文件,像普通文件一样用 U 盘、邮件、即时通讯工具传来传去,对方拿到后能 clone、能 fetch、能 verify。
二、git bundle 是什么
一句话:它是 Git 原生的"把仓库打成一个可移动文件"的传输格式,从 Git 1.5.0(2007 年)就在了,只是太低调,很多人没用过。
它和 git archive(只导源码快照、不带历史)不一样,也和 git format-patch(把提交转成一堆邮件补丁)不一样——bundle 里面是完整的 Git 对象(commit / tree / blob),对方拿到后拥有和原仓库一模一样的提交历史。
打包出来的 .bundle 文件,本质就是个"只读的、单文件的远程仓库"。
三、核心命令,就这五个
# 1. 全量打包:把仓库所有引用(分支+标签)打成一个文件 git bundle create repo.bundle --all
# 2. 只打包某个分支及其历史 git bundle create repo.bundle master
# 3. 校验对方能不能用:会列出"前提提交" git bundle verify repo.bundle
# 4. 看这个包里带了哪些分支/标签 git bundle list-heads repo.bundle
# 5. 接收方:像克隆普通仓库一样克隆它 git clone repo.bundle myrepo
最实用的是增量更新。你第一次发了全量包,过两周只想把新增的提交发过去,不用再传整个仓库:
# 只打包"从 v1.0 到 master 新增的提交"
git bundle create update.bundle v1.0..master
# 接收方:先 verify 确认他本地已经有 v1.0 这个基准
git bundle verify update.bundle git fetch update.bundle master:local-master
verify 这一步很关键:如果接收方缺了基准提交(比如他手上根本没有 v1.0),Git 会直接报错告诉你"还差哪些提交",绝不会给你一个半吊子仓库。
四、真实使用场景
五、几个容易踩的坑
① bundle 不含工作区文件、untracked 文件、reflog、stash、配置、hook——它只打包你显式指定的引用对应的 Git 对象。没提交的东西,打不进去。
② Git LFS 的大文件内容不在 bundle 里。bundle 只带 LFS 指针文件,真正的二进制大文件得另外走 LFS 传输,否则对方 clone 下来的是一堆指针。
③ 增量包基准必须对方已有。a..b 里的 a 得在接收方仓库里可达,否则 verify 直接失败。不确定就发 --all 全量,最稳。
④ bundle 是只读传输介质,不是活远程。你 clone / fetch 它没问题,但别指望往 .bundle 文件里 push。
六、和常见"搬代码"方式横向比一下
七、结尾蹲个后续
git bundle 本身不复杂,但一旦配上增量基线管理和离线 CI 分发,就能在隔离交付、灾备、跨网发布这些"正经活儿"里顶大用。
下一篇我打算接着聊:怎么把 bundle 串进离线环境的持续交付——比如工控现场、涉密网的"U 盘式发版"流水线怎么搭。想看的在评论区扣 1,攒够需求我就写。
参考:Git 官方文档 git-bundle(git-scm.com/docs/git-bundle)、Pro Git 第二版「Git 内部原理 - 传输协议」章节。
本文部分资料由 AI 辅助整理。
— END —

