Submodule 與 LFS 在 CI 中的瓶頸拆解
子模組把「多個遠端」串成樹狀拉取:任一層級逾時都會讓整段 job 失敗。Git LFS 則在 smudge 階段額外打批次請求,與 git fetch 競爭頻寬。跨境 遠端 Mac CI 上常見組合痛點包括:未設定 --jobs 導致子模組序列化、LFS 預設並行不足、以及快取鍵過粗使 LFS 物件無法命中。
- 1. Checkout 父倉固定 SHA(避免浮動分支上子模組指標漂移)。
- 2.
git submodule sync --recursive對齊.gitmodules與實際 URL(尤其剛切換 HTTPS/SSH 時)。 - 3.
git submodule update --init --recursive --jobs 4(4~8視 CPU/頻寬調整)。 - 4. 若 clone 時設
GIT_LFS_SKIP_SMUDGE=1:在父倉與各子模組目錄執行git lfs pull(必要時加--include縮小範圍)。 - 5. 驗證
git lfs ls-files無 missing,再進入 Xcode/SwiftPM 建置。
並行拉取與鎖檔策略對照表
「能不能並行」取決於鎖定的是提交還是浮動分支,以及是否允許 LFS 延後下載。
| 策略 | 並行拉取 | 鎖檔/一致性 | 適用情境 |
|---|---|---|---|
子模組固定 commit + --jobs N | 高(多遠端同時) | 以父倉記錄的 submodule SHA 為準 | 正式 release/App Store 建置 |
子模組跟蹤分支(remote 未鎖) | 中(仍受遠端節流影響) | 每日可能漂移,需額外稽核 | 內部整合分支(不建議上線) |
GIT_LFS_SKIP_SMUDGE=1 + 批次 lfs pull | 高(與 submodule 分階段) | 與 .lfsconfig/遠端 URL 綁定 | 大型素材、多層子模組 |
| 單執行緒預設 smudge | 低 | 行為直觀但耗時 | 本機除錯或小倉 |
# 並行子模組 + LFS 並行示例(CI 環境變數或全域設定) export GIT_LFS_SKIP_SMUDGE=1 git config --global submodule.fetchJobs 8 git config --global lfs.concurrenttransfers 16 git config --global lfs.activitytimeout 600 git submodule update --init --recursive --jobs 8 git lfs pull
lfs.concurrenttransfers 常設 8~32(視託管方節流);頻寬極窄時可降到 4 換取較少連線競爭。若需限制單連線速率,可在代理層做 QoS,或使用 lfs.basictransfersonly true 強制簡單 HTTP(部分企業防火牆較友善)。
快取與增量 fetch 參數清單
- LFS 物件:掛載
~/.git/lfs/objects(或$HOME/.cache/git-lfs,依版本);鍵建議含hashFiles('.gitattributes')+hashFiles('**/.lfsconfig')+ 父倉GITHUB_SHA前綴。 - Git 物件:使用
git clone --filter=blob:none或維護裸鏡像目錄;鍵含.gitmodules與子模組指標合併雜湊。 - 增量 fetch:
git fetch --depth=50 origin $SHA;子模組內同樣 shallow,避免拉全歷史。 - HTTP 緩衝:
git config --global http.postBuffer 524288000;http.lowSpeedLimit/http.lowSpeedTime可依頻寬調整以防假死。
快取鍵過細會降低命中率,過粗會帶入過期 LFS 指標;實務上常以「.gitmodules + 子模組 commit 合併雜湊」為一級鍵,二級再以「當次 pipeline 觸發提交」區分。
失敗重試與逾時閾值
- Git fetch/clone:包一層指數退避,例如 3~5 次,基底 5s、上限 120s;對
RPC failed、empty pack重試有效。 - LFS batch:
lfs.activitytimeout建議 300~900 秒;跨洋鏈路可與lfs.dialtimeout一併拉高。 - 429/402:對配額與節流錯誤應縮短重試或改走備援儲存,避免打滿 API 配額。
遠端 Mac 網路與磁碟水位檢查
在掛載快取前,先確認節點不會因磁碟滿導致 LFS 寫入半套失敗。建議於 pre-job 腳本檢查:可用空間 ≥ 預估Git + LFS 快取 + 建置產物總和的 1.5 倍;網路可抽樣 curl -o /dev/null -s -w '%{time_total}\n' 對託管 API 與 LFS 端點量測,若連續樣本 RTT 或錯誤率超過內部 SLO,觸發下一節的鏡像/直連切換。
- 同一 job 內對鏡像域名連續 3 次 5xx 或 TLS 握手失敗 → 下一輪改
git remote set-url為直連上游。 - 建立連線時間 > 2000 ms(可調)且持續兩個 job → 暫停鏡像,僅對該倉庫走官方端點。
- 恢復條件:直連連續成功 N 次(如 10)且平均 RTT 低於閾值,再切回鏡像以省頻寬。
FAQ:鑑權失敗與配額
檢查子模組 URL 是否與父倉相同鑑權方式(全 HTTPS + PAT 或全 SSH + deploy key)。git submodule sync 後重跑;SSH 需在遠端 Mac上配置 ssh-agent 與 known_hosts。細部逾時參數可再對照站內 Git 拉取穩定性 FAQ。
常見為 402/429 或帶配額文案的錯誤。應啟用/升級託管儲存、將冷資料改工件庫或自建 LFS,並在 CI 對該錯誤停止盲目重試。
會。頻寬固定時過多 TCP 連線會造成重傳與節流;請以實測在 4~16 間找甜蜜點,並與 submodule.fetchJobs 一併調整。