工程指南

雲端 Mac 大型 iOS 儲存庫取出最佳化實作

雲端 Mac 大型 iOS 儲存庫取出最佳化實作

當 iOS 儲存庫累積多年提交歷史、設計原始檔、螢幕錄影與測試治具後,第一次部署到雲端 Mac 時,很容易把「機器準備太慢」誤判為 CPU 或磁碟效能問題。實際瓶頸往往早在建置前就已出現:一般 Git 物件被完整下載,Git LFS 在取出階段自動抓取所有大型檔案,但 CI 最後只編譯其中一個 App。正確做法不是盲目快取整個目錄,而是先固定輸入,再分層控制提交物件、工作區路徑與 LFS 內容。

先量測取出成本

不要只記錄 git clone 的執行時間。至少應拆分為網路傳輸、工作區展開與 LFS 下載三個階段,並保存以下結果:

git --version
git lfs version
du -sh .git
du -sh .git/lfs 2>/dev/null || true
du -sh .
git count-objects -vH
git lfs ls-files | wc -l

第一次執行與重複使用工作區的執行必須分開量測。第一次執行反映遠端傳輸成本;重複使用工作區則能暴露無效清理、歷史物件累積與 LFS 快取膨脹。也應記錄最終提交值,而不是只留下分支名稱:

git rev-parse HEAD
git status --short

最佳化的目標不是讓目錄看起來更小,而是確保同一個提交、同一組目錄與同一批 LFS 物件都能穩定重建。

結合部分複製與稀疏取出

部分複製的 blob:none 會延後下載一般檔案內容,稀疏取出則限制工作區實際展開的目錄。兩者可以搭配使用,但不會自動限制 Git LFS,因此必須明確略過第一次 smudge。

export GIT_LFS_SKIP_SMUDGE=1
git clone --filter=blob:none --no-checkout "$REPO_URL" app
cd app
git lfs install --local
git sparse-checkout init --cone
git sparse-checkout set App Packages Shared
git fetch --depth=1 origin "$BUILD_REF"
git checkout --detach FETCH_HEAD
git rev-parse HEAD

--cone 模式適合依目錄組織的專案,規則簡單,也較不容易發生父目錄檔案意外消失的情況。AppPackagesShared 必須替換為實際建置相依項目;如果工作區、指令碼或設定檔位於儲存庫根目錄,必須確認這些檔案仍包含在取出範圍內。

部分複製需要遠端支援物件篩選。若命令出現篩選能力警告,應將其視為已退回一般複製,並重新記錄 .git 大小,不能假設最佳化已經生效。

只抓取目前工作需要的 LFS 物件

完成取出後,LFS 檔案仍可能只是指標。先列出目前提交引用的物件,再依工作所需路徑抓取:

git lfs ls-files
git lfs pull --include="App/Assets/**,Shared/Fixtures/**"
git lfs fsck

路徑篩選應依據實際建置輸入,而不是根據副檔名猜測。介面測試可能依賴圖片、影片與本地化測試治具;如果只抓取原始碼目錄,編譯可能通過,測試卻會在執行階段失敗。

檢查項目 合格結果 常見問題
git lfs ls-files 可看到目前提交中的 LFS 追蹤項目 .gitattributes 未隨目標提交取出
檔頭檢查 檔案是實際二進位內容 仍是包含 oid sha256 的指標
git lfs fsck 本機物件驗證通過 下載中斷或物件目錄損壞
git status --short 工作區沒有非預期修改 工具在取出後改寫資源檔案

不要把沒有路徑限制的 git lfs pull 放進共用初始化指令碼,否則每項工作都會下載與自身無關的素材。更穩妥的做法是讓每條流水線自行宣告所需的 LFS 輸入集合。

處理 CI 中的並行工作與憑證

每項 CI 工作都應使用獨立工作區。多項工作共用同一個可寫入儲存庫時,稀疏規則、索引鎖定與 LFS 暫存檔可能互相干擾。即使使用的是相同唯讀程式碼,也不要讓兩項工作同時修改 .git/info/sparse-checkout

憑證只應在抓取階段注入,並將權限限制為目標儲存庫所需範圍。完成 git fetchgit lfs pull 後,應清除暫時環境變數與憑證輔助設定。記錄中不得輸出含有權杖的遠端位址,可使用以下命令確認顯示內容是否安全:

git remote -v
git config --local --get-regexp 'credential|lfs' || true

子模組必須另外處理。主儲存庫的部分複製與稀疏規則不會自動套用到子模組;如果子模組也使用 LFS,應在其目錄中安裝本機 LFS 設定,並執行對應的抓取操作。

避免不安全的清理方式

git lfs prune 適合由單一工作獨佔的儲存庫,不適合多項工作共用的 LFS 物件目錄。在共用環境中,更安全的策略是為每項工作建立獨立目錄,並在工作結束後整體刪除。若必須重複使用工作區,應先確認沒有並行工作,再執行清理與完整性檢查。

以建置前驗收取代事後猜測

真正執行 xcodebuild 前,應加入一道輕量驗收關卡。它至少要確認提交值正確、工作區乾淨、關鍵專案檔案存在、LFS 指標已被實際內容取代,並輸出磁碟使用量。檢查範例可寫成:

test -f App/App.xcodeproj/project.pbxproj
test -s App/Assets/LaunchVideo.mov
if grep -q "oid sha256:" App/Assets/LaunchVideo.mov; then
  exit 1
fi
git diff --exit-code
git lfs fsck
du -sh . .git .git/lfs

最後保留四項資料:提交雜湊、稀疏目錄清單、LFS include 規則與驗收結果。如此一來,當雲端 Mac 上的工作失敗時,可以先判斷輸入是否完整,再檢查編譯器、簽署或測試記錄,避免把儲存庫準備錯誤包裝成隨機建置故障。

常見問題

部分複製與稀疏取出可以取代 Git LFS 嗎?

不可以。部分複製處理一般 Git 物件的傳輸,稀疏取出限制工作區路徑,Git LFS 則負責指標檔案所代表的大型內容。

為什麼取出後仍然只有 Git LFS 指標檔案?

通常是略過自動下載後沒有執行 git lfs pull。請確認目前提交、include 路徑、憑證與 LFS 設定,再取得所需物件並執行完整性檢查。

CI 任務結束後可以執行 git lfs prune 嗎?

只有在儲存庫與 LFS 物件目錄由該任務獨占時才適合執行。共用儲存空間應改用獨立工作區,並在任務結束後整體回收。

專用雲端 Mac

在獨享實體節點上執行建置任務

按天、週、月或季選擇 MiniRents M4 與 MiniRents M4 Pro,並依團隊與程式碼儲存庫位置選擇節點。設備為獨享實體機,並非虛擬機。

選擇機型並訂購