① CI에서 Submodule+LFS가 만드는 병목(왜 동시에 터지나)
슈퍼프로젝트 fetch 뒤 서브모듈마다 왕복이 붙고, LFS는 포인터와 객체 전송이 분리됩니다. 캐시 키가 흔들리면 매 잡마다 대역을 다시 씁니다.
- 순차 초기화:
submodule update가 한 줄씩이면 RTT×서브모듈 수만큼 지연. - LFS 스머지: 클론 직후 모든 포인터를 당기면 CPU·소켓이 한꺼번에 바빠짐.
- 캐시 키 누락:
.gitmodules·서브모듈 SHA·LFS 객체 지문이 키에 없으면 히트율이 거의 0에 가깝습니다.
- 슈퍼프로젝트
git fetch origin "$SHA"후git checkout --detach FETCH_HEAD(또는 브랜치 고정). git submodule sync --recursive로 URL 재정렬(미러 전환 시 필수).GIT_LFS_SKIP_SMUDGE=1을 유지한 채GIT_SUBMODULE_JOBS=8 git submodule update --init --recursive --depth 1(필요 시 depth 조정).git lfs install확인 후git lfs pull또는 작업 디렉터리별git lfs pull --include="path/*".- 빌드 스크립트에서 서브모듈 경로가 준비된 뒤에만 Xcode·SwiftPM·CocoaPods 단계 실행.
② 병렬 풀과 lockfile(고정 SHA) 전략 비교표
팀이 항상 최신 서브모듈 헤드를 당기는지, 슈퍼프로젝트에 핀된 커밋만 쓰는지에 따라 파이프라인 설계가 갈립니다.
| 항목 | 병렬 풀 + 캐시(추천: 핀된 SHA) | 매 잡 remote 최신 추적 |
|---|---|---|
| 서브모듈 | GIT_SUBMODULE_JOBS=8, shallow, 동일 미러 URL |
git submodule update --remote → 재현성↓, 캐시 무효↑ |
| LFS | 스머지 지연 후 lfs pull, concurrenttransfers 조절 |
매번 전체 객체 스캔, 할당량·시간 변동 큼 |
| lockfile | 슈퍼프로젝트 커밋이 서브모듈 SHA 고정 → 캐시 키 안정 | 서브모듈 브랜치 헤드 변동 시 키 자주 변경 |
| 실패 시 | 동일 SHA 재시도·미러 전환만으로 복구 용이 | 어느 모듈이 바뀌었는지 추적 비용 증가 |
Xcode·바이너리 의존이 있으면 슈퍼프로젝트에 핀된 서브모듈 SHA + LFS 입력 기준으로 캐시 키를 잡는 편이 안전합니다.
③ 캐시·증분 fetch 파라미터 체크리스트
공유 볼륨·러너 캐시 경로를 쓰면 잡 간 재사용이 쉬워집니다. 캐시 키에 서브모듈·LFS 입력을 넣어야 히트가 의미 있습니다.
git config lfs.storage "$RUNNER_CACHE/git-lfs"로 공유 스토어 지정, 슈퍼프로젝트는 워크스페이스 전체 tarball 또는 git clone --reference-if-able로 워밍(서브모듈별 .git/modules 단독 캐시는 키·무결성 관리가 어려워 팀마다 정책 필요).hashFiles('.gitmodules') + hashFiles('**/Podfile.lock') 등 빌드 입력 + runner.os + xcode-version + 슈퍼프로젝트 git rev-parse HEAD(또는 소스 tarball 해시).git fetch origin "+refs/heads/*:refs/remotes/origin/*" 후 git checkout "$SHA", 서브모듈은 git submodule update --init --recursive만 재실행.조직 정책상 전역 설정이 어렵다면 CI 스텝에서만 GIT_CONFIG_COUNT / GIT_CONFIG_KEY_* / GIT_CONFIG_VALUE_*로 주입하거나, 해당 잡용 .lfsconfig를 리포지토리에 둡니다.
④ 실패 재시도·타임아웃·미러↔직연결 전환 임계
수치는 출발점입니다. 회선·리전에 맞게 조정하세요. 미러 전략 개요는 Git 미러·프록시 비교를 참고하면 선택이 빨라집니다.
- HTTP·Git 클라이언트:
git config --global http.lowSpeedLimit 1000,http.lowSpeedTime 600(10분 이하 속도 시 중단 판단 완화). - 재시도 래퍼: 동일 명령에 지수 백오프 3~5회, 최소 5초·최대 60초 간격(예:
for i in 1 2 3 4 5; do git fetch … && break || sleep $((i*5)); done). - 미러로 전환(예시 임계): 직연결에서 연속 3회 동일 단계 실패, 또는 단일 LFS 객체 전송이 120초 이상 진행률 없음.
- 직연결로 복귀(예시 임계): 미러 평균 처리량이 직연결 대비 30% 미만으로 5분 이상 유지되거나, 미러가 오래된 객체를 반환(체크섬 불일치)할 때.
⑤ 원격 Mac 네트워크·디스크 워터마크 점검
LFS·서브모듈은 디스크·inode를 순간적으로 많이 씁니다. 잡 전 df -h로 작업 볼륨 여유(예: 15GB 미만 경고), 필요 시 diskutil apfs list로 APFS 여유를 확인하세요. RTT가 800ms를 넘기면 concurrenttransfers를 먼저 낮춘 뒤 미러·프록시를 검토합니다.
⑥ FAQ: LFS·서브모듈 인증 실패와 할당량
401/403: 토큰은 URL 삽입보다 credential.helper·호스트별 시크릿으로 분리, LFS 스코프 확인. 서브모듈이 다른 호스트면 자격 증명도 별도.
할당량: 동시 전송 축소 + LFS 스토어 공유로 중복 전송 감소. 외부 미러가 어려우면 전용 Mac에 캐시 전용 프록시만 두는 선택도 있습니다.
경로 오류: git submodule status의 -는 미초기화. Xcode 상대 경로·sparse checkout 충돌 여부를 확인하세요.
정리
원격 Mac CI에서 Submodule과 LFS를 같이 쓸 때는 초기화 순서(sync → 병렬 update → LFS pull), 병렬도와 lockfile(핀 SHA)의 균형, 캐시 키에 .gitmodules·헤드·도구 버전 포함, 재시도·타임아웃·미러 전환 임계를 한 세트로 고정하는 것이 핵심입니다. 전용 노드에서 캐시와 미러를 장기 유지하려면 MacPull 요금·플랜과 구매 페이지에서 원격 Mac(Mac Mini 등)을 선택하고, 운영·회선 질문은 고객 지원·홈·기술 블로그로 이어가시면 됩니다(해당 페이지는 로그인 없이 열람 가능).