Git bundle 离线迁移:完整包可以克隆,增量包还要核对前置提交
没有可用远程服务器时,要把一段仓库历史交给另一台机器,复制工作目录只能带走当前文件,无法自然保留提交关系。Git bundle 可以把对象与选定引用放进单个文件,再通过克隆或获取导入。它尤其适合离线搬运已经提交的历史。
但文件存在不代表接收方能够使用。完整包可以从头建立仓库,增量包通常省略已约定拥有的历史,需要接收方具备前置提交。验收应在目标仓库执行 verify,而不是只在发送方检查一次;发送方本来就拥有那些对象。
同时构造能独立使用和依赖历史的包
下面保存为 demo.sh,用 Bash 和 Git 运行。脚本仅创建新的临时目录与仓库,不访问网络,不接触现有项目。第一次提交生成完整包;第二次提交生成从第一版之后开始的增量包。接收仓库先克隆完整包,再检查和导入增量。
另建空仓库作为反例,验证增量包在缺少基础历史时会被拒绝。输出文件和测试仓库留在这次创建的临时目录中,方便需要时继续检查。提交身份只设置在新仓库里,名字和邮箱均为演示值。
AI概念示意图:以抽象物件说明本文主题,不代表真实界面或运行结果。
set -euo pipefail bundle_demo=$(mktemp -d) git init -q -b main "$bundle_demo/source" cd "$bundle_demo/source" git config user.name Demo git config user.email demo@example.invalid git config commit.gpgsign false printf 'one\n' > note.txt git add note.txt git commit -qm first git tag base git bundle create "$bundle_demo/full.bundle" --all printf 'two\n' >> note.txt git commit -qam second git bundle create "$bundle_demo/update.bundle" base..main git clone -q "$bundle_demo/full.bundle" "$bundle_demo/receiver" cd "$bundle_demo/receiver" git bundle verify "$bundle_demo/update.bundle" > "$bundle_demo/verify.log" 2>&1 git fetch -q "$bundle_demo/update.bundle" main:refs/heads/imported test "$(git show imported:note.txt)" = $'one\ntwo' test "$(cat note.txt)" = one printf 'receiver: prerequisite present; imported=two; working=one\n' git init -q -b main "$bundle_demo/empty" if git -C "$bundle_demo/empty" bundle verify "$bundle_demo/update.bundle" \ > "$bundle_demo/missing.log" 2>&1; then printf 'unexpected verification success\n' >&2 exit 1 fi printf 'empty: incremental bundle rejected\n' git -C "$bundle_demo/empty" bundle verify "$bundle_demo/full.bundle" \ > "$bundle_demo/full-check.log" 2>&1 printf 'empty: full bundle accepted\n'
验证成功之后仍要选择导入位置
三行输出依次确认接收仓库可导入增量、空仓库拒绝增量,以及空仓库接受完整包。第一行还特意比较 imported 分支与当前工作文件:获取对象并创建新分支,不会自动把当前检出内容切到第二版。导入与采用版本是两步。
例子把增量写到新的 imported 引用,便于先比较再决定如何合并。若直接更新已有分支,需要考虑目标分支当前状态和快进关系。不要因为 bundle 来自自己,就跳过差异审查;发送时的分支位置与接收时的工作状态可能已经不同。
base..main 表达的是提交集合边界,不是文件改动清单。它保留 main 这一命名引用,并把基础提交作为前置条件。文件名叫 update 并不会自动赋予增量语义,真正决定范围的是创建命令使用的版本参数。
把仓库历史与工作现场分开盘点
--all 可以选入本地引用所能到达的对象,但不能把 bundle 等同于整个项目目录备份。未提交的工作区内容、暂存区状态、钩子和本地配置不属于这条传输流程。需要保留这些信息时,应先列出清单,选择各自合适的保存方式。
子模块仓库和 Git LFS 的外部对象也要单独核对。主仓库记录了引用或指针,并不意味着对应内容已经进入这一个包。恢复演练应实际检出目标版本并运行必要检查,不能只看提交数量一致就认为所有依赖都齐全。
verify 检查格式与前置历史是否满足,不替你证明发送者身份,也不确认代码值得执行。传输时可另核对来源和文件摘要;接收后先查看引用、提交和差异。对象验证、来源确认与业务验收,分别回答不同问题。
用于周期性离线同步时,应把增量的基础提交标识随包记录,并保留一份能够独立恢复的完整包。定期在空目录演练完整恢复,再在有基础历史的仓库演练增量导入,才能发现“日常都能更新,换机器却恢复不了”的缺口。


