你請 Coding Agent 改一個按鈕,卻先等它取得整個專案。Git Repo 瘦身能把這段等待拆開:任務需要多少歷史、哪些檔案內容、哪些目錄?三個答案,對應三個不同開關。
這篇專為第一次接觸 Git、願意照著貼指令的讀者寫。Repo(repository,程式庫)像專案的資料倉庫;clone 是把倉庫取得到自己的電腦。我們先用白話理解,再建立完全自有的小型範例,比較完整 clone、Shallow、Partial+Sparse,故意讓跨目錄依賴和歷史追查出問題,再把它們補回來。
實作使用已有的 Git 與 Python 3.9 以上,適用 macOS/Linux 終端機;不用登入 AI 或下載模型。AlphaLab 於 2026 年 10 月 14 日執行本文三組 Git 與 Python 檢查,保留固定 commit、指令輸出與接收資料流;這是取得與修補流程實驗,未執行 Coding Agent 模型。
先說結論:Git Repo 瘦身有三個抽屜
Shallow 少歷史;Partial 延後內容;Sparse 少攤開。像借書:Shallow 少借舊版本,Partial 先拿目錄、需要時再取書頁,Sparse 只把眼前要用的書攤到桌上。
- 只做當前快照的小測試:先評估淺歷史。
- 要追查或比較分支,但只改少數目錄:先評估 blobless Partial+Sparse。
- 任務橫跨全專案、常離線或下載成本很小:完整 clone 是容易理解的基準。
2026 年 10 月 13 日,Anthropic 的 Scion 工程文章說明其內部版本控制如何採按需取資料、稀疏工作副本。那是特殊規模的自建系統案例。對一般專案,先學 Git 現有開關,測完自己的工作量,再決定是否需要更大的架構改動。
原理:歷史、物件與工作目錄為什麼分開?
Git 的 commit(提交)像一張版本收據;tree 記錄目錄和檔案對應;blob 保存檔案內容。工作目錄則是你實際打開、修改的檔案。.git 放 Git 的資料,旁邊的程式檔案是攤在桌上的副本。先分清這兩處,才知道磁碟究竟省在哪裡。
①「少借舊版」:Shallow 控制歷史深度
痛點是只跑今天的測試,卻要取得多年沿革。Shallow clone 用 git clone --depth=1 URL repo 取得淺歷史;clone 官方說明也指出 depth 預設隱含單一分支。驗收時跑 git rev-parse --is-shallow-repository,再看 git rev-list --count HEAD。它縮短歷史,當前要展開的檔案仍會出現在工作目錄。
②「先拿目錄」:Partial 控制物件下載
痛點是目前只看程式,過去的大型資產卻占很多容量。Partial clone 的 --filter=blob:none 延後 blob;Partial Clone 文件把它與歷史深度視為獨立機制。承諾稍後提供物件的來源叫 promisor remote,像保管尚未取出的書頁。
需要缺少的內容時,Git 會向來源補取。若直接正常 checkout 全專案,當前版本的內容就可能立刻補回來;所以本篇搭配 --no-checkout,先決定 Sparse 範圍。歷史 commit 可存在,不代表每個歷史檔案內容都已在本機。
③「少攤到桌上」:Sparse 控制工作目錄
痛點是只改網站,卻被其他服務與資產淹沒。Sparse checkout 用 git sparse-checkout set --cone apps/web 選目錄;Sparse 官方文件說明 cone 模式還包含根目錄及祖先目錄的直接檔案。把它想成選一整層書架,不是精準到單一書頁的白名單。
本篇對照三套「取得配方」,其中第三套同時用了 Partial 和 Sparse;因此結果不能拆成各自貢獻多少。想辨認單獨 Sparse 的效果,再加第四組完整 clone 後設 Sparse,觀察工作目錄與 .git 的差異。
第一步「固定倉庫」:建立可重做的小型範例
怕每次測到不同版本?先造同一份自有資料。打開終端機,在新的練習位置把以下存成 make_demo.py,執行 python3 make_demo.py。程式只新建 git-clone-demo;名稱已存在就停止,避免蓋到其他工作。隨機內容採固定種子,五份各 256 KiB,刻意模擬不容易互相壓縮的資產歷史。
from pathlib import Path
import os, random, subprocess
root = Path("git-clone-demo").resolve()
root.mkdir() # 已存在就報錯
src = root / "source"
def git(*args):
subprocess.run(["git", *args], cwd=src, check=True)
subprocess.run(["git", "init", "-b", "main", str(src)], check=True)
git("config", "user.name", "AlphaLab Demo")
git("config", "user.email", "demo@example.invalid")
for d in ("apps/web", "packages/shared", "assets"):
(src / d).mkdir(parents=True)
(src / "apps/web/check.py").write_text(
'from packages.shared.price import price\n'
'assert price(2) == 4\nprint("PASS")\n')
(src / "packages/shared/price.py").write_text(
'def price(x):\n return x + 1\n')
def commit(message, day):
git("add", ".")
stamp = f"2026-01-{day:02d}T00:00:00+0000"
env = dict(os.environ, GIT_AUTHOR_DATE=stamp,
GIT_COMMITTER_DATE=stamp)
subprocess.run(["git", "commit", "-m", message],
cwd=src, env=env, check=True)
for i in range(5):
(src / "assets/payload.bin").write_bytes(
random.Random(i).randbytes(262144))
(src / "README.md").write_text(
f"AlphaLab synthetic clone lab version {i}\n")
commit(f"version-{i}", i + 1)
if i == 1:
git("branch", "feature")
git("switch", "feature")
(src / "feature.txt").write_text("side branch\n")
commit("feature", 6)
git("switch", "main")
origin = root / "origin.git"
subprocess.run(["git", "clone", "--bare", str(src), str(origin)],
check=True)
for key in ("uploadpack.allowFilter", "uploadpack.allowAnySHA1InWant"):
subprocess.run(["git", "-C", str(origin), "config", key, "true"],
check=True)
print("DEMO_URL=" + origin.as_uri())
git("rev-parse", "HEAD")
輸出的 DEMO_URL=file:///…/origin.git 是本機來源;把它完整保留。這裡特意用 file:// 的 Git 傳輸,避免純本機路徑 clone 的硬連結最佳化干擾比較。兩個 uploadpack 設定僅套在自建練習倉庫,參數可查官方 config 文件;不要照抄去改公司的伺服器。
本次主分支固定 commit 為 ed7ae5ca0cd78d71d01e0989b03751cdf1dbd46d。若你得到不同 SHA,保留自己的輸出,三組使用同一個 SHA 再比較;Git 設定或環境差異也要記錄。
第二步「只改取得方式」:Git Repo 瘦身三組對照
不知道哪一組有保留歷史?三個新目錄分開跑。以下在 git-clone-demo 內執行;將第一行換成剛才真正的來源 URL。DEMO_URL 是這次練習的變數,full、shallow、partial 是新資料夾名稱。
cd git-clone-demo
DEMO_URL='file:///請換成你的完整路徑/origin.git'
git clone "$DEMO_URL" full
git clone --depth=1 "$DEMO_URL" shallow
git clone --filter=blob:none --no-checkout "$DEMO_URL" partial
git -C partial sparse-checkout set --cone apps/web
git -C partial checkout ed7ae5ca0cd78d71d01e0989b03751cdf1dbd46d
三組都用 git -C 目錄 rev-parse HEAD 核對起點。前兩組的來源 main 已固定在該版本;第三組明確 checkout 到 SHA,會進入 detached HEAD(目前停在版本,而非分支)。若要讓 Agent 提交變更,再在該目錄執行 git switch -c agent-demo-fix 建工作分支。
AlphaLab 的本次環境是 macOS 26.1/Apple Silicon、Git 2.50.1(Apple Git-155)、Python 3.9.6。下圖計時從 clone 前到修補測試通過,包含 Sparse 擴範圍、寫修補與量測呼叫;每組一趟、本機傳輸、有系統快取,不能用來排行網路或 AI 寫程式速度。

pack 數字來自 Git 官方記錄變數 GIT_TRACE_PACKFILE 的接收資料流,不是只加總磁碟上的 .pack:小型 fetch 可能解包成散落物件,單看 pack 檔會漏算。真實網路還有協定、驗證與其他開銷。
要留下自己的收據,可在 clone 前設定 export GIT_TRACE_PACKFILE="$PWD/full-received.packstream";full 的所有 Git 步驟沿用同一個檔案,下一組改成新的絕對路徑,結束執行 unset GIT_TRACE_PACKFILE。wc -c full-received.packstream 顯示累計 bytes。它保存原始程式庫資料,要與私人 Repo 同等保護。
磁碟圖使用檔案長度加總,即 .git 加工作目錄的邏輯位元組,不是檔案系統實際配置量。你也可另用 du -sk full/.git 與 du -sk full 看配置量,但要把它記成另一種口徑,別直接拿來填這張圖。
第三步「把依賴補齊」:找不到模組,先別讓 Agent 重寫
為什麼只改網站,還得看別的目錄?先讀錯誤,再擴工作範圍。在三組各自的 Repo 根目錄跑 python3 -B -c "import runpy;runpy.run_path('apps/web/check.py')"。full 與 shallow 本次得到 AssertionError;partial 先得到 ModuleNotFoundError: No module named 'packages'。
前者已載入程式,但計算結果錯了;後者連共用程式都還沒攤到桌上。此時請 Agent 先核對 apps/web/check.py 的 import、目錄清單及 Sparse 範圍,不要新造一份共用套件來掩蓋問題。
git -C partial sparse-checkout list
git -C partial ls-tree -r --name-only HEAD
git -C partial sparse-checkout add packages/shared
擴目錄後,partial 也會來到相同的斷言失敗。三組都把 packages/shared/price.py 的 return x + 1 改成 return x * 2,再跑原測試,應看到 PASS。最後用 git diff --check 檢查空白錯誤、git diff --name-only 核對只改預定檔案。
這次 Partial+Sparse 接收 pack 累計從 2,208 bytes 增為 2,279 bytes,增加 71 bytes;那是此範例一次補共用程式的成本。正式 monorepo(把多個元件放同一 Repo)還可能依賴根目錄設定、測試工具或其他 package;擴範圍要沿依賴做,任務驗收也要跟著擴。大型 Repo 安全改版教學補的是改動影響範圍。
第四步「補回祖譜」:Shallow 的 blame 與 merge-base
程式通過了,是否就找得回原因?另驗歷史。blame 追查每行的版本來源;merge-base 找兩個版本的共同祖先,像先找家族樹的交會點,再比較各自改了什麼。先讀blame與merge-base 文件,把「目前能改檔」和「歷史可追查」分開驗收。
git -C shallow fetch --depth=1 origin feature:refs/remotes/origin/feature
git -C shallow merge-base HEAD origin/feature
git -C shallow blame HEAD -- packages/shared/price.py
本次兩個分支的淺邊界沒有共同祖先可遍歷,merge-base 結束碼為 1;blame 則把未改過的兩行追到 main 的淺邊界 ^ed7ae5c。完整組與 Partial+Sparse 組追到最初版本 ^0228c42。此範例最初版本也是根提交,所以同樣帶 ^;符號本身不證明淺歷史,還要讀 SHA 與 shallow 狀態。
要補一小段,可用 git fetch --deepen=50 origin 再驗;本篇示範來源完整,直接用下列方式補回可取得的歷史。fetch 官方說明對 --unshallow 的範圍綁定來源是否完整;它也不等於自動增加所有分支的追蹤設定。
git -C shallow fetch --unshallow origin
git -C shallow rev-parse --is-shallow-repository
git -C shallow merge-base HEAD origin/feature
git -C shallow blame HEAD -- packages/shared/price.py
本次補取 feature 與完整歷史後,Shallow 累計接收 pack 為 1,313,741 bytes,接近完整組的 1,313,599 bytes。這說明同一任務後來若要全部沿革,初次省下的資料可能只是延後支付。它不是所有 Repo 的固定比例;壓縮、協商與版本分布會改變結果。
第五步「把桌面展開」:回到完整工作目錄
下一個任務橫跨全專案怎麼辦?先保留修改,再展開。用 git status --short 與 git diff 保存並確認工作;接著執行 git -C partial sparse-checkout disable,重跑測試、核對原修補仍在。
本次 disable 後取回當前大型資產,Partial+Sparse 累計 pack 增為 264,545 bytes,較修補後多 262,266 bytes。這一步把當前工作目錄展開;歷史 blob 仍可按需補取。若下一個任務要讀舊資產,仍得計入新的接收資料。
做離線任務前,先在線跑過所需測試與歷史查詢,再斷線重驗;需要的物件若尚未到本機,按需下載會受到來源可達性影響。若你要容易驗證的完整取得基準,可另外建立新完整 clone,把已保存的修補用 git diff 匯出後再套用,兩份各自驗收。
決策:Coding Agent 的取得策略怎麼選?
- 工作只讀當前快照:從完整組當基準,再試 Shallow;只要新增沿革或分支比較需求,就重驗歷史。
- 小範圍修改、需要沿革:試 Partial+Sparse,把共用套件、根設定及測試依賴列入可擴範圍。
- 全專案搜尋、重構或常離線:評估完整取得;別讓看似省資料的設定,讓故障復原比任務更昂貴。
把 Agent 的開工清單寫成:起始 SHA、工作目錄、Sparse 清單、所需分支、測試入口、允許修改路徑、擴範圍理由。這些屬於 Harness 的環境與驗收;AI Agent Harness 原理能幫你分清模型與執行層。並行工作則接著看Worktree 流程:各自工作副本仍要各自核對取得策略。
若你用 GitHub Agentic Workflows,官方 checkout 指南提醒預設淺歷史與需要正確分支範圍的工作有取捨,並列出 fetch-depth: 0。先讀工作流實際 checkout 設定,不要把本篇 Git CLI 旗標直接當成 YAML 欄位。本文核對截至 2026 年 10 月 14 日。
常見坑:下載範圍與授權範圍要分開
三個瘦身開關都不應被當成權限隔離。Sparse 是檔案呈現範圍,Partial 是資料供應策略,Shallow 是歷史邊界;本篇已示範用指令擴目錄與補歷史。Git 的安全說明另明確指出 fetch/push 協定與伺服器 namespaces 的讀取控制限制。要保護不該共享的資料,應從 Repo 分離、授權與執行環境處理。
外部來源是否支援 filter 要實際核對。若 clone 出現忽略 filter 的警告,就保存輸出、重看下載與物件狀態;remote.origin.promisor 或 remote.origin.partialclonefilter 設定只是線索,不能單靠設定字串宣稱省下多少。
Submodule 是另一份 Repo,Git LFS 則有另一層大檔取用流程;本範例兩者都沒有加入,圖中數字不涵蓋那些下載。正式測量要把套件安裝、LFS、子模組與重試另外記下,再加總任務成本。多 Agent 交接也要讀動手前的意圖衝突檢查,下載少不等於改動會相容。
FAQ:Git Repo 瘦身新手八問
1. Shallow、Partial、Sparse 是三個同義詞嗎?
不是。分別調歷史、物件和工作目錄;本篇記憶法是「少歷史、延後內容、少攤開」。
2. 只用 Sparse,會省掉先前已下載的歷史嗎?
它主要調工作目錄。要減少初次物件取得,從 clone 階段選 Partial 等配方,再量接收資料。
3. Partial 能與 Shallow 一起用嗎?
可以組合。官方把兩者視為獨立機制;組合後也要同時驗歷史和缺少物件,這篇第三組沒有加 depth。
4. blame 有輸出,就能認定找到真正最早修改嗎?
要看歷史邊界。本次 Shallow 有輸出,卻停在較新的 commit;補歷史後再追查。
5. Sparse 漏掉共用套件,應直接複製一份嗎?
先擴範圍。讀 import 與目錄來源,取得真正套件後重跑同一測試。
6. disable 後就成為完整離線 Repo 嗎?
它恢復當前工作目錄。Partial 尚缺的歷史內容仍需另驗,離線前跑過所需查詢。
7. 本次資料少,為什麼修補沒有最快?
多個 Git 步驟與補取有成本。這裡是單次本機觀察;跨網路、多次交接要重新量測。
8. 這能直接證明 Claude Code 比另一個 Agent 快嗎?
這份實驗沒有測模型。我們固定自有修補,量取得流程;模型、提示、工具與品質比較要另設對照。
給新手的三個重點
- 先用固定版本與相同通過條件,確認取得策略仍能完成工作。
- 把第一次取得、補依賴、補歷史和回到完整目錄的成本都留下。
- 工作目錄小、歷史可追查、授權安全,是各自的驗收問題。
接著閱讀
左右滑動查看更多推薦
下一步:先完成一次「缺資料→補資料→測試通過」
今天先建自己的小倉庫,三組核對同一個 SHA,再把 partial 漏掉的 shared 目錄補回、把 shallow 的共同祖先找回。最後問自己:這次任務需要的歷史、內容與桌面,各有多少?少歷史、延後內容、少攤開就從三個名詞,變成你能檢查的三個開關。
想把這套環境與驗收習慣接到自己的 Agent,可在AlphaLab 課程繼續練習,也可從AI 文章專區選下一個工作流。






