Это не кликбейт. Мы и правда сделали это! В Microsoft мы работаем с очень большим монорепозиторием, который между собой называем 1JS. Недавно мы достигли 1000 активных пользователей в месяц, около 2500 пакетов и ~20 млн строк кода! Последнее клонирование репозитория вернуло невероятные 178 ГБ.
По множеству причин, это попросту слишком большой размер, некоторые ребята из Европы попросту не могут успешно клонировать репозиторий из‑за его размера.
Вопрос в том, как это вообще произошло?!
Урок #1
Когда я впервые присоединился к репозиторию несколько лет назад, я заметил, что он растет. Когда я впервые его склонировал, его размер составлял около одного‑двух гигабайт, но через несколько месяцев он уже достигал около 4 гигабайт. Трудно было понять, почему именно это происходит.
Тогда я использовал инструмент git-sizer
, который поведал мне несколько деталей о некоторых больших блобах. Они возникают, когда кто‑то случайно добавляет бинарные файлы и мало, что можно сделать в таком случае, кроме ограничения размеров файлов — фичи Azure DevOps. В целом, после того, как файл попал в репозиторий, он в каком‑то смысле «застревает» в истории.
Также было показано предупреждение о неудаленных файлах изменений Beachball. Мы используем их как Changesets, достигая того же результата, как и при использовании semantic‑release, где мы говорим пакетам, как автоматически увеличивать их диапазоны версий в соответствии с semver.
В какие‑то моменты у нас было больше 40 тысяч таких файлов в одной папке, что приводило к созданию огромных tree‑объектов при каждом добавлении новых файлов в этой папке.
Итак, урок номер один, который мы извлекли, был…
Не храни тысячи файлов в одной папке
Чтобы облегчить ситуацию, мы сделали две вещи. Первая — pull request в beachball для вноса нескольких изменений в один файл вместо создания отдельного файла на каждый пакет.
Вторая — мы написали пайплайн, который периодически выполняется и при запуске автоматически чистит папку изменений для избежания ее разрастания.
Ура! Мы пофиксили раздувание git!
Урок #2
Наш флоу версионирования поддерживает зеркало main
под названием versioned
, хранящее актуальные версии пакетов, чтобы избежать конфликтов git в main
и иметь возможность точно видеть, какие коммиты относятся к какой semver версии, выпускаемой посредством пакетов NPM. (Это потребует отдельного поста, ну да ладно…)
Я заметил, что версионированная ветка становилась все сложнее и сложнее для клонирования из‑за ее размера. Но мы уже разобрались с проблемой файлов изменений и все, что происходило в ветке versioned
с точки зрения коммитов это добавление к файлам CHANGELOG.md
и CHANGELOG.json
.
Время шло, а репозиторий, хоть и понемногу, но разрастался. Но было сложно определить, был ли связан рост просто с масштабом или дело в чем‑то совершенно другом. Мы добавляли сотни тысяч строк кода и сотни разработчиков с 2021 года, так что можно было привести аргумент, что это просто естественный рост. Однако, когда мы поняли, что превзошли темпы роста одного из крупнейших монорепозиториев Microsoft — Office, мы осознали, что что‑то здесь явно не так!
Пришло время звать на подмогу…
Автор таких фич git как git shallow checkout, git sparse index и всяких других только вернулся в нашу организацию, поработав в Github и подарив эти фичи всему миру.
Он глянул и сразу понял, что что‑то не так с подобным темпом роста. Когда мы запуллили версионированные ветки, те самые, в которых меняется только CHANGELOG.md и CHANGELOG.json, мы получили 125ГБ дополнительных данных git?! НО КАК??
Итак, после очень глубокого погружения в git, оказалось, что некий старый код упаковки, добавленный Linux Torvalds (может, слышали про такого 🤷♂️) на самом деле проверял только последние 16 символов названия файла при подготовке к сжатию перед отправкой diff’ов. Для контекста, обычно git отправляет только diff’ы измененных файлов, но из‑за проблемы с упаковкой, git сравнивал файлы CHANGELOG.md из двух разных пакетов! Stolee хорошо объяснил это тут.
К примеру, если вы изменили repo/packages/foo/CHANGELOG.json
, когда git готовился пушить изменения, он генерировал diff относительно repo/packages/bar/CHANGELOG.json
! Это значит, что во многих случаях раз за разом отправлялся весь файл целиком, что могло иногда составлять десятки мегабайт, и вы догадываетесь, как в репозитории нашего размера это может стать проблемой.
Затем мы попробовали перепаковать наш репозиторий с увеличенным окном командой git repack -adf --window=250
, чтобы Git смог лучше сжать пак‑файлы и уменьшить размер репозитория. Это действительно значительно снизило размер репозитория, но мы можем лучше!
Этот PR https://github.com/git‑for‑windows/git/pull/5171?ref=jonathancreamer.com добавил новый способ упаковки репозитория на основе обхода путей git вместо стандартного обхода коммитов.
Результаты впечатляют…
Вчера я запустил новый git clone на своей машине, чтобы проверить новую версию git в форке git Microsoft (версия git version 2.47.0.vfs.0.2)…
И после выполнения новой команды git repack -adf --path-walk
…
Невероятно. С 178ГБ до 5. 😱
Ещё одна новая опция конфигурации, которая будет добавлена, обеспечит генерацию нужных типов дельт во время выполнения команды git push
…
git config --global pack.usePathWalk true
Это позволит убедиться, что команда git push
использует правильное сжатие.
Любой разработчик на версии git 2.47.0.vfs.0.2 теперь может переупаковать склонированный локально репозиторий, а также использовать новый алгоритм обхода путей при git push
, чтобы остановить рост репозитория.
На Github переупаковка и сборка мусора git происходит периодически, но, опять же, используемый Github тип упаковки не будет корректно рассчитывать дельты файлов CHANGELOG.md и CHANGELOG.json или потенциально любых часто изменяющихся файлов с одинаковыми 16-ю последними символами в названии. К примеру, большие файлы со строками i18n и им подобные.
В Azure DevOps, который мы используем, пока вообще нет такой переупаковки. Поэтому мы также работаем над этим, чтобы уменьшить размер репозитория на серверной стороне.
Эти изменения также будут добавлены в апстрим git! Ура OSS.
Итоги
Если вы работаете в околобольшом монорепозитории и в нем есть файлы CHANGELOG.md или, на самом деле, любой файл с относительно длинным названием (>16 символов), который часто обновляется, вам может быть полезно последить за этой штукой с обходом путей.
Также можете попробовать новую команду git survey
, чтобы просмотреть разную эвристику, к примеру Top Files By Disk Size, Top Directories By Inflated Size, или Top Files By Inflated Size.
Это поможет вам понять, повлияет ли обход путей на размер вашего репозитория или нет.
В целом я очень впечатлен и воодушевлен нашей приверженностью созданию решений, которые помогают нам масштабировать репозитории в Microsoft, а также возможностью передавать эти решения всему миру.
ссылка на оригинал статьи https://habr.com/ru/articles/855436/
Добавить комментарий