Три узких места до стабильного checkout:
- Раздувание графа объектов. Полный
git cloneтянет историю, которую сборке не нужно; при нестабильном WAN обрыв на миллионах объектов стоит дороже, чем повтор короткого среза. - Смешение таймаутов HTTP и логики job. Без
GIT_HTTP_LOW_SPEED_LIMITраннер держит слот, пока сокет «ползёт»; внешне это похоже на медленный компилятор, хотя проблема — только транспорт Git. - Гонки на общем object store. Неверный
alternatesили запись в зеркальный каталог из параллельных джобов даёт повреждённые pack-файлы; безgit bundle verifyиfsckдефект всплывает на этапе линковки.
Трансграничный сценарий: задержка, джиттер и политика сокетов Git
На удалённом Mac в облаке первичный риск — не CPU, а длинный маршрут до корпоративного forge. Зафиксируйте переменные до любого clone: export GIT_HTTP_LOW_SPEED_LIMIT=5000 и export GIT_HTTP_LOW_SPEED_TIME=600 — так Git прервёт зависший HTTP, не дожидаясь дефолтных десятков минут. Для SSH используйте GIT_SSH_COMMAND="ssh -o ConnectTimeout=15 -o ServerAliveInterval=30" чтобы отличать обрыв туннеля от ошибки авторизации.
HEAD ветки релиза, --depth=32 обычно достаточно для blame и короткой истории; увеличивайте глубину только когда аналитика требует полного лога.Сравнение транспортов: где bundle, где shallow
| Режим | Объём по сети | Контроль целостности |
|---|---|---|
| Полный clone по HTTPS | Максимальный; растёт с историей | Стандартный index-pack; медленный повтор при обрыве |
git clone --filter=blob:none --depth=N |
Низкий за счёт отложенных blob | Последующие git fetch должны уважать ту же глубину |
git bundle между двумя SHA |
Детерминированный файл артефакта | Обязателен git bundle verify перед распаковкой |
| Зеркало + alternates только чтение | Почти нулевой при тёплом кеше | Требуется изоляция записи и периодический git fsck --connectivity-only |
Стратегия срезов git bundle между базовой и вершиной ветки
Соберите артефакт на стабильном билдере внутри периметра: git bundle create ci-OLD..NEW.bundle OLD_SHA..NEW_SHA --progress. Имя файла должно содержать оба конца диапазона, чтобы ключ кеша CI однозначно ссылался на набор объектов. На Mac-раннере: git clone --depth=1 file:///path/ci-OLD..NEW.bundle workspace, затем git remote set-url origin https://forge.example.com/org/repo.git и git fetch origin refs/heads/main:refs/remotes/origin/main с той же глубиной.
git bundle verify ci-OLD..NEW.bundle git clone --depth=32 --filter=blob:none --single-branch \ file:///Volumes/cache/ci-OLD..NEW.bundle work cd work && git remote set-url origin "$FORGE_URL"
Повторное использование объектного хранилища: alternates и запрет записи
Разместите git clone --mirror на отдельном томе и укажите абсолютный путь в .git/objects/info/alternates либо экспортируйте GIT_ALTERNATE_OBJECT_DIRECTORIES=/Volumes/git-mirror/repo.git/objects. Каждая джоба пишет только в свой .git/objects; очиститель pack-файлов не должен трогать зеркало. Для одноразовых воркеров допустим GIT_OBJECT_DIRECTORY указывающий на tmpfs, но тогда bundle остаётся единственным источником новых объектов.
Повторные fetch при сбоях и составление ключа кеша CI
Оберните git fetch в цикл с паузами две четыре восемь секунд и потолком пяти попыток на стадию. Логируйте GIT_TRACE_CURL=1 только при отладке, иначе артефакты раздуваются. Ключ кеша соберите как конкатенацию: идентификатор пула раннеров, имя ветки, короткий SHA вершины, целое depth, строка фильтра (blob:none или пусто), SHA-256 имени bundle-файла. Любое изменение глубины или фильтра обязано промахивать кеш, иначе вы получите частичный граф без нужных коммитов.
for i in 1 2 3 4 5; do git fetch --depth=32 --prune origin "+refs/heads/$BRANCH:refs/remotes/origin/$BRANCH" && break sleep $((2**i)) done
Матрица решений: когда комбинировать bundle и shallow
| Сигнал | Рекомендуемая связка | Риск если игнорировать |
|---|---|---|
| RTT > 180 мс и частые обрывы | bundle ночью + shallow clone из файла | Долгие висящие слоты MacPull |
| Нужен blame глубже N коммитов | Увеличить depth, отказаться от минимального shallow | «missing blob» при checkout старых файлов |
| Несколько репозиториев одного монорепо-зеркала | Общий alternates + локальные packs | Коррупция при записи в зеркало |
| За forge включён WAF с лимитом тела | Меньшие bundle-файлы по двум промежуточным SHA | HTTP 413 и молчаливый retry |
Операционный конвейер: шесть шагов с приёмкой
Шаг 1. Экспорт лимитов WAN и SSH keepalive в профиль службы раннера.
Шаг 2. Скачать или смонтировать bundle, выполнить git bundle verify; при ошибке — не распаковывать.
Шаг 3. git clone с --filter=blob:none и согласованной глубиной; зафиксировать git rev-parse HEAD в артефакте.
Шаг 4. Подключить alternates или чистый удалённый origin; проверить git remote -v.
Шаг 5. Выполнить git fsck --connectivity-only после первого успешного fetch.
Шаг 6. Сохранить строку ключа кеша и журнал попыток fetch для постмортема.
bundle verify с первого раза; p95 длительности git fetch при depth 32; число промахов кеша после смены только фильтра без смены SHA bundle.
Следующий шаг: узел, тарифы и справка без входа
Закрепите Apple Silicon рядом с вашим egress и повторите матрицу на реальном канале. Откройте список статей блога, сравните тарифы, оформите аренду или начните с центра помощи по SSH и доступу; обзор платформы — на главной MacPull.
Mac Mini M4 под стабильный Git checkout в CI
Выберите узел рядом с вашим forge, зафиксируйте shallow и bundle в одном пайплайне без обязательного входа на маркетинговые страницы.