cover

2026 Удалённый Mac: DS_Store, AppleDouble и rsync/SFTP для CI

Версионируйте исключения, delete только в staging, разделяйте учётки, гейты до переключения видимости; далее ссылки на APFS xattr, files-from и атомарный релиз.

Три нумерованных риска

  1. Вилки видны как ._* на Linux и портят подпись.
  2. .DS_Store искажает дельты каталогов и алерты.
  3. --delete без staging удаляет артефакты при отсутствии парных файлов.

Команды часто объявляют удалённый Mac источником истины для сборок, а затем винят сеть, когда Linux-runner заполняется ._* или .DS_Store. Реже виноват канал: чаще не разведены поверхности записи, нет шаблонов исключений в репозитории с ревью и в заявке не зафиксирован радиус --delete, ограниченный именованным поддеревом staging.

Вилки AppleDouble на «чужих» ФС проявляются как ._* и доходят до подписи или статического анализа при неполном инвентаре. .DS_Store портит дельты каталогов даже при жёстких десктоп-политиках, а rsync --delete без инварианта staging смешивает уборку с удалением реальных артефактов. Не смешивайте сохранение xattr APFS с шумом Finder: в одном runbook это гоняет диагностику между ACL, -aE и простыми exclude без измеримого выигрыша.

Общие учётные данные для интерактивного SFTP и CI делают аудит непрозрачным после drag-and-drop метаданных. Хэшировать только крупные бандлы без сверки дерева оставляет вилки, которые ломают цепочку позже. В структурированных логах держите рядом версию шаблона исключений, ID сборки, путь staging и ревизию манифеста — дежурный должен восстановить картину за минуты.

В разборе инцидентов 2026 снова три профиля: мобильные команды с огромными деревьями DerivedData, контент со смешанными ассетами и артефактами на одном томе, платформы с разными сборками rsync на macOS и Linux. Планирование ёмкости должно учитывать churn inode и число записей каталога, а не только мегабайты в минуту: «зелёный» по объёму прогон может скрыть лавину мелких файлов.

Сдержать дрейф помогают негативные тесты с .DS_Store у publish-якоря, три dry-run со сводными удалениями и передачами против манифеста, раздельные шаблоны push/pull и серверные слои «люди / билдер / read-only якорь для CI». Зафиксируйте в тикете версию шаблона, счётчики шума, область delete и дайджест манифеста до закупки нового оркестратора. NFS, кэши IDE и договорные глубины хэширования разбираются в следующем разделе.

Углубление и пограничные сценарии

Ночные пайплайны и дневные ручные загрузки на одном дереве дают скрытые гонки. Зафиксируйте окна, когда пишет только CI, и отдельно — когда допускаются люди; иначе счётчики шума растут без единого «плохого» коммита.

Экспортированные .xcarchive и .ipa часто содержат xattr, которые не видны в списке файлов. Добавьте выборочный обход с xattr -l на эталонных бинарниках до отправки, не смешивая это с простым исключением ._*.

Старые SMB/NAS могут оставлять скрытые lock-файлы на стороне сервера. Протокол и права squash должны быть в том же тикете, что и exclude-лист, иначе сравнение инвентарей между сторонами бессмысленно.

Кэши CocoaPods, Gradle или npm, скопированные с Mac, раздувают inode. Держите их на отдельном томе или жёстко исключайте; иначе лимиты исчерпываются до шага подписи.

Для медиа-ассетов задайте лимит размера пакета и обязательный LFS/Git-обходчик. Массовый drag-and-drop обходит хуки и возвращает шум Finder.

Логи приложений должны нести ID политики исключений, а не только версию rsync. Тогда скачок счётчиков связывается с конкретным merge в репозитории шаблонов.

Плейбуки ИБ разделите: «взрыв метаданных» и «реальное удаление». Два коротких скрипта — один считает ._*, второй сверяет манифест построчно — экономят часы расследований.

В договоре фиксируйте, кто и на какой глубине считает дерево. Разные глубины дадут расхождение при зелёных пайплайнах обеих сторон.

Быстрый чек-лист: в тикете есть три агрегата (добавлено/изменено/удалено) и они совпали с последним dry-run? Если нет, приложите структурированный лог раньше, чем покупать новый оркестратор.

How-to: шесть шагов

rsync -az \
  --exclude='.DS_Store' \
  --exclude='.AppleDouble' \
  --exclude='._*' \
  --delete \
  ./staging/out/ user@runner:/data/in/
  1. Зафиксируйте константы путей для якоря, staging и runner в одном источнике.
  2. Включайте delete только в поддереве staging.
  3. Базовые исключения для .DS_Store, .AppleDouble, ._* и кэшей IDE.
  4. Три dry-run: удаления и передачи против манифеста.
  5. Разделите интерактивный SFTP и CI с read-only якорем.
  6. Гейт по SHA256 или манифесту до переключения видимости.

Matrix

СценаРешение
Малый репозиторий, мало GUIИсключения + простой хэш
Монорепо с сотнями артефактовfiles-from/манифест до delete
Частые дизайн-отгрузкиStaging + базовый шум
Кросс-ОС CI с подписьюМатрица xattr до видимости

Итог

Версионируемые исключения, delete только в staging, раздельные учётки и гейты до переключения видимости — базовая линия 2026. Аренда Mac не отменяет манифесты, но снижает коллизии человек/автоматизация.

Links

APFS xattr

files-from