土法炼钢兴趣小组的算法知识备份

【Git 内部】fetch/push 与 pack 传输落地

文章导航

分类入口
opensource
标签入口
#git#git-internals#fetch#push#pack#shallow#FETCH_HEAD

目录

本地 git fetch 后,.git/objects/pack/ 常突然变大——远端把对象打成 pack 传来,git index-pack 解包入库。理解传输在磁盘上的落点,能解释「只 fetch 一个分支为何 pack 很大」「浅克隆为何有 shallow 文件」。

本文讲 pack 落盘与 ref 更新;展开 HTTP smart 协议路由或服务器实现(见 gitprotocol-pack 规范边界)。


一、fetch 概要

git fetch <remote>

  1. 与远端协商(have/want SHAs)。
  2. 接收 pack 字节流(可能 thin pack)。
  3. git index-pack 写入 objects/pack/pack-*.pack + .idx
  4. 更新 refs/remotes/<remote>/<branch>(或配置指定的 ref)。
  5. FETCH_HEAD:本次抓取的 ref 与 SHA 列表。
fetch 接收 pack 后写入 objects/pack 并更新 refs/remotes 与 FETCH_HEAD

对象格式与本地 commit 相同;pack 布局见 第 07 篇


二、FETCH_HEAD

文本文件,每行:

<sha>       <ref-description>

git pull 合并时读此文件决定合并目标。多次 fetch 会覆盖/追加(行为依版本与参数)。


三、refs/remotes

git clone 后:

.git/refs/remotes/origin/HEAD
.git/refs/remotes/origin/master   # 示例

指向上次 fetch 见到的远端 tip。与本地 refs/heads/* 独立;git push 更新远端服务器上的 ref,本地 refs/remotes 在下次 fetch 才同步。

git clone --bare 无 remotes 目录,仅有 refs/heads(实测 bare 克隆清单含 packed-refs)。


四、浅克隆与 shallow 文件

git clone --depth 1 <url> 只拉最近历史;.git/shallow 列出边界 commit(仍视为 tip,但 parent 可能不在库中):

2b24b26a117ef5cfdbf88040e282ec86085e6b1f

git fetch --unshallow 补全历史后,实测 shallow 文件消失(Git 2.54.0 实验)。

浅克隆 .git/shallow 边界与 rev-list 停止位置

浅仓库的 git rev-list 遇边界停止;对象仍存于 pack/松散对象。


五、push 的本地副作用

git push 主要改远端 ref;本机通常:

若 push 被拒,本地无额外损坏;若用 git push --force,远端 ref 移动,与本机 objects 无直接关系。


六、本地协议实验

无需网络:

git init --bare /tmp/bare.git
cd /tmp/wt && git clone /tmp/bare.git . -q
echo hi > f && git add f && git commit -qm h && git push -q
cd /tmp/clone && git clone /tmp/bare.git clone -q
find clone/.git/objects/pack -type f
cat clone/.git/shallow 2>/dev/null || true
git clone --depth 1 file:///tmp/bare.git shallow -q && cat shallow/.git/shallow

七、本文边界


参考资料

系列索引Git 内部结构 · 上篇merge/rebase · 下篇worktree/submodule

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。


By .