使用 Git Sparse Checkout 只下載部分專案以加速 Clone 速度
Clone 大型儲存庫耗時很長又佔空間,例如樹梅派原始碼高達一百二十萬次提交 clone 一次需要長達 15 分鐘,我們也不需要全部檔案和歷史,這時就可以使用 sparse-checkout 以排除指定檔案避免全部下載。
儲存庫過大有兩種原因,分別是 儲存庫包含大檔案或單純的文件數量過多,本教學會分別示範並且搭配其他指令同時使用多管齊下,最後包含實際使用範例,包含如何在十秒內克隆完樹梅派儲存庫。
TL;DR
本章節是簡單範例所以設定一層,平常建議 1000 起跳方便回滾歷史同時避免奇怪的問題。
情境一:文件數量過多,只取出特定目錄
我們以大型 monorepo openjdk 實際測試,假設我們開發時只需要用到 src/base
和 src/desktop
兩個資料夾,指令如下:
git clone --filter=blob:none --no-checkout --depth=1 --sparse https://github.com/openjdk/jdk; cd jdk
# Git 2.37 之後因為預設啟用 cone 模式不需要這行
# git sparse-checkout init --cone
git sparse-checkout set src/java.base src/java.desktop
git checkout
現在我們處於 sparse checkout 的 cone 模式,此模式只支援加入目錄不支援排除目錄,git sparse-checkout set
則是將要加入的目錄寫入 .git/info/sparse-checkout
,最後在 checkout 時根據此規則取出目錄。
情境二:儲存庫包含大檔案,排除指定檔案
剛剛是 cone 模式,此問題則需要 no-cone 模式解決。以 Blowfish 主題為例,這個儲存庫提交太多圖片導致容量過大。
git clone --filter=blob:none --no-checkout --depth=1 --sparse https://github.com/nunocoracao/blowfish.git; cd blowfish
# Git 2.37 之後因為預設啟用 cone 模式所以需要這行
git sparse-checkout init --no-cone
git sparse-checkout set '/*' '!exampleSite/*' '!images/*' '!assets/img/*' '!*.png'
git checkout
請注意兩種模式的 pattern 語法不相容。no-cone 的和 .gitignore 完全一樣,以上述指令為例,意思是
/* 加入全部檔案
!exampleSite/* 排除該目錄
!images/* 排除該目錄
!assets/img/* 排除該目錄
!*.png 排除所有png檔
可以看到第一行 /*
加上後面的語法就等同於 gitignore 的邏輯,是黑名單的概念;至於 cone 模式的語法則是簡單把白名單的加入資料夾,在 cone 模式之下只能新增要 checkout 的資料夾無法排除。
詳細說明
大家應該都看過 The Will Will Web 的介紹,雖然很詳細完整但是讀的時候覺得文章花花綠綠的不太好讀,真正提筆發現全都指令很難避免,於是決定列表式寫出來看起來比較清晰,首先是指令參數介紹
--filter=blob:none
: 不要下載 blobs--depth=1
: 淺克隆,只複製第一層--shallow-since=<date>
: 淺克隆,限定日期--no-checkout
: clone 後不把文件放到工作目錄--sparse
: 設定稀疏檢出 sparse-checkout- 上述五個指令可以獨立使用
接下來是對 sparse checkout 本身的介紹
- cone 代表圓錐,意思是選定一整個資料夾的目錄白名單模式,no-cone 則是和 .gitignore 一樣的黑名單模式
- 為什麼取名叫圓錐模式?
- 使用可以直接編輯
.git/info/sparse-checkout
,git sparse-checkout set
就是修改這個文件。編輯後如果不符合 cone 模式 Git 會提醒你設定衝突並且自動退回 no-cone 模式 - 使用
git sparse-checkout disable
回到一般 checkout 模式
很重要就再說一次
cone 代表圓錐,意思是選定一整個資料夾的目錄白名單模式,no-cone 則是和 .gitignore 一樣的黑名單模式