Git bundle 是将提交历史、引用和对象打包成单个二进制文件的离线传输方案,用于网络受限场景;它不替代 clone --bare,不包含工作区文件,也不能直接 push,需先 fetch 再 checkout。

bundle 是什么,为什么不用 clone --bare
Git bundle 本质是把提交历史、引用、对象打包成单个二进制文件,适合离线传输或受限网络环境。它不是替代 clone --bare 的通用方案,而是解决「没网络 / 不能直连 / 防火墙拦 SSH/HTTPS」这类硬性限制的备用路径。
常见错误现象:git clone 报 Failed to connect to github.com port 443 或内部 Git 服务器拒绝 SSH 连接,此时 bundle 是唯一能带走完整历史的方式。
注意:bundle 不包含工作区文件(即没有 .git 以外的源码),只含 Git 内部数据;也不能直接 push 回原仓库,必须先解包成本地仓库再同步。
怎么生成 bundle 文件(含 tag 和所有分支)
最常用命令是 git bundle create,但默认只打包当前分支的提交。要导出完整仓库状态,得显式指定引用范围。
- 导出全部分支 + 所有 tag:
git bundle create repo.bundle --all - 只导出 main 和 develop 分支及关联 tag:
git bundle create repo.bundle main develop --tags - 导出从某次提交开始的所有变更(适合增量):
git bundle create delta.bundle <code>git rev-parse v1.2.0..HEAD
性能影响:bundle 文件大小 ≈ git clone --bare 后的 .git 目录压缩后体积,但生成过程不走网络,纯本地计算,大仓库可能耗时几十秒。
怎么验证和导入 bundle 到新机器
bundle 文件不是黑盒,可以用 git bundle list-heads 查看它包含哪些引用,避免传错文件或版本遗漏:
git bundle list-heads repo.bundle —— 输出类似 abc123 refs/heads/main、def456 refs/tags/v1.3.0
导入分两步:先初始化空仓库,再用 git fetch 加载 bundle:
git init my-project && cd my-project-
git fetch ../path/to/repo.bundle --tags(加--tags才能拿到 tag) -
git checkout main(或其它分支名,需与 bundle 中存在的一致)
容易踩的坑:git pull 会失败,因为 bundle 不是远程源;git fetch 后必须手动 checkout,不会自动检出任何分支;如果 bundle 没包含某个分支,git checkout 会报 pathspec 'xxx' did not match any file(s)。
bundle 能否用于后续同步更新
可以,但必须用「增量 bundle」+ git fetch,不能直接 push 到原仓库。
假设原始 bundle 已导入并开发了几天,现在要同步新提交:
- 在原仓库运行:
git bundle create update.bundle <code>git rev-parse v1.3.0..HEAD(v1.3.0 是上次 bundle 的最新 tag) - 在目标仓库执行:
git fetch ../update.bundle,然后git merge FETCH_HEAD或git rebase
关键限制:bundle 的引用范围必须连续,不能跳过中间提交;如果原仓库做了 force-push 或重写历史,增量 bundle 可能失效——这时候只能重新全量打包。
真正容易被忽略的是:bundle 文件本身不带签名,传输过程中若损坏,git fetch 会静默失败或报错 error: object xxx is corrupted,建议传完用 shasum -a 256 校验一致性。


















