Привет Хабр! Предлагаю вашему вниманию перевод статьи История создания виртуальной файловой системы Git .
Продолжение следует… Виртуальная файловая система Git (GVFS) была создана для решения двух основных проблем:
- Скачивайте только те файлы, которые нужны пользователю
- Локальные команды Git не должны учитывать весь рабочий каталог ( рабочий каталог ), а только те файлы, с которыми работает пользователь
Чтобы клонировать этот репозиторий, вам необходимо скачать файл упаковки ( пакетный файл ) имеет размер 100 ГБ, что займет несколько часов.
Если вам удалось его клонировать, все локальные команды git, такие как checkout (3 часа), status (8 минут) и commit (30 минут), выполнялись бы слишком долго из-за линейной зависимости от количества файлов.
Несмотря на все эти трудности, мы решили перенести весь код Windows на git. При этом мы постарались оставить git практически нетронутым, поскольку популярность git и количество общедоступной информации о нем были одной из основных причин миграции.
Следует отметить, что мы рассмотрели огромное количество альтернативных решений, прежде чем решили создать GVFS. Подробнее о том, как работает GVFS, мы опишем в следующих статьях, а сейчас сосредоточимся на рассмотренных нами вариантах и на том, почему была создана виртуальная файловая система.
Фон
Почему монолитный репозиторий?
Давайте сразу разберемся с самым простым вопросом: зачем кому-то нужен репозиторий такого размера? Просто ограничьте размер своих репозиториев, и все будет в порядке! Верно? Не все так просто.Уже написано Есть много статей о преимуществах монолитных репозиториев.
Несколько крупных команд Microsoft уже пытались разделить свой код на множество небольших репозиториев и в итоге пришли к выводу, что монолитный репозиторий лучше.
Разбить большой объем кода непросто, и это не решение всех проблем.
Это решило бы проблему масштабирования в каждом отдельном репозитории, но в то же время усложнило бы внесение изменений в несколько репозиториев одновременно, и как следствие выпуск конечного продукта стал бы более трудоемким.
Оказывается, за исключением проблемы масштабирования, процесс разработки в монолитном репозитории выглядит гораздо проще.
VSTS (система группы Visual Studio)
Набор инструментов VSTS состоит из нескольких связанных сервисов.Поэтому мы решили, что, разместив каждый из них в отдельном git-репозитории, мы сразу избавимся от проблемы масштабирования, а заодно создадим физические границы между разными частями кода.
На практике эти границы ни к чему хорошему не привели.
Во-первых, нам всё равно приходилось менять код в нескольких репозиториях одновременно.
Много времени было потрачено на управление зависимостями и поддержание правильной последовательности коммитов и пул-реквестов, что в свою очередь привело к созданию огромного количества сложных и нестабильных утилит. Во-вторых, наш процесс выпуска стал значительно сложнее.
Параллельно с выпуском новой версии VSTS каждые три недели мы выпускаем коробочную версию TeamFoundation Server каждые три месяца.
Для корректной работы TFS все службы VSTS должны быть установлены на одном компьютере, то есть все службы должны понимать, от каких версий других служб они зависят. Объединение сервисов, которые разрабатывались совершенно независимо за последние три месяца, оказалось непростой задачей.
В конце концов мы поняли, что с монолитным репозиторием нам будет гораздо проще работать.
В результате все службы зависели от одной и той же версии всех остальных служб.
Внесение изменений в один из сервисов требовало обновления всех сервисов, которые от него зависели.
Так что немного больше работы в начале сэкономило нам много времени на релизах.
Конечно, это означало, что отныне нам пришлось быть более осторожными при создании новых и управлении существующими зависимостями.
Окна
Примерно по тем же причинам команда Windows решила перейти на Git. Код Windows состоит из нескольких компонентов, которые теоретически можно разделить на несколько репозиториев.Однако при таком подходе было две проблемы.
Во-первых, даже несмотря на то, что большинство репозиториев были небольшими, для одного из репозиториев (OneCore), размер которого составлял около 100 ГБ, нам все равно пришлось бы решать проблему масштабируемости.
Во-вторых, такой подход никоим образом не облегчит внесение изменений в несколько репозиториев одновременно.
Философия дизайна
Наша философия выбора инструментов разработки заключается в том, что эти инструменты должны помочь нам правильно организовать наш код. Если вы считаете, что ваша команда будет более эффективно работать с несколькими меньшими репозиториями, инструменты разработки должны помочь вам в этом.Если вы чувствуете, что команде будет эффективнее работать с монолитным репозиторием, ваши инструменты не должны вам в этом мешать.
Рассматриваются альтернативные варианты
Итак, за последние несколько лет мы потратили много времени, пытаясь заставить Git работать с большими репозиториями.Перечислим некоторые рассмотренные нами варианты решения этой проблемы.
Подмодули Git
Сначала мы попробовали использовать подмодули.Git позволяет вам указать ( ссылка ) любой репозиторий как часть другого репозитория, что позволяет для каждого коммита в родительском репозитории указывать коммиты в субрепозиториях, от которых зависит этот родительский коммит, и где именно в рабочем каталоге родительского репозитория эти коммиты должны быть размещены.
Выглядит идеальным решением для разделения большого репозитория на несколько маленьких.
И мы потратили несколько месяцев на работу над утилитой командной строки для работы с подмодулями.
Основной сценарий использования подмодулей — использование кода из одного репозитория в другом.
В каком-то смысле подмодули — это те же пакеты npm и NuGet, т. е.
библиотека или компонент, не зависящие от родителя.
Любые изменения сначала вносятся на уровне подмодуля (ведь это независимая библиотека со своим независимым процессом разработки, тестирования и выпуска), а затем родительский репозиторий переключается на использование этой новой версии.
Мы решили, что можем воспользоваться этой идеей, разбив наш большой репозиторий на несколько маленьких, а затем объединив их обратно в один суперрепозиторий.
Мы даже создали утилиту, которая позволит вам выполнять «git status» и коммитить код во всех репозиториях одновременно.
В конце концов мы отказались от этой идеи.
Во-первых, стало понятно, что таким образом мы только усложняли жизнь разработчику: каждый коммит теперь становился двумя и более коммитами одновременно, поскольку необходимо было обновлять как родительский, так и каждый из затронутых репозиториев подмодулей.
Во-вторых, в Git нет атомарного механизма для одновременной фиксации в нескольких репозиториях.
Можно было бы, конечно, назначить один из серверов ответственным за транзакционность коммитов, но в итоге все опять сводится к проблеме масштабируемости.
И в-третьих, большинство разработчиков не хотят быть экспертами в системах контроля версий; они предпочли бы, чтобы доступные инструменты сделали это за них.
Для работы с git разработчику необходимо научиться работать с направленным ациклическим графом (DAG, Directed Acyclic Graph), что уже непросто, но здесь мы просим его работать одновременно с несколькими слабосвязанными направленными ациклическими графами.
а также следить за порядком оформления/фиксации/отправки в них.
Это слишком много.
Несколько репозиториев, собранных вместе
Если с субмодулями не получилось, то может получится склеить несколько репозиториев? Похожий подход использовался android в repo.py и мы тоже решили его попробовать.Но ничего хорошего из этого не вышло.
Работать внутри одного репозитория стало проще, но процесс внесения изменений в несколько репозиториев одновременно стал значительно сложнее.
А поскольку коммиты в разных репозиториях теперь совершенно не связаны друг с другом, непонятно, какие коммиты из разных репозиториев следует выбирать для конкретной версии продукта.
Для этого потребуется другая система контроля версий поверх Git.
Запасное место ( заменяет ) Гит
В Git есть концепция резервных хранилищ объектов ( альтернативное хранилище объектов ).Каждый раз, когда git ищет коммит, дерево или блоб, он начинает поиск в папке .
git\objects, затем проверяет файлы пакета в папке .
git\objects\pack и, наконец, если это указано в настройках git, выполняет поиск.
в репозиториях резервных объектов.
Мы решили попробовать использовать сетевые папки в качестве хранилища резервных копий, чтобы избежать копирования огромного количества больших двоичных объектов с сервера при каждом клонировании и выборке.
Такой подход более-менее решил проблему количества копируемых файлов из репозитория, но не проблему размера рабочего каталога и индекса.
Очередная неудачная попытка использовать функционал Git для других целей.
Репозитории резервных копий были созданы в Git, чтобы избежать дублирования клонирования объектов.
При повторном клонировании того же репозитория вы можете использовать хранилище объектов первого клона.
Предполагается, что все объекты и пак-файлы расположены локально, доступ к ним мгновенный, дополнительный кэш не нужен.
К сожалению, это не работает, если хранилище резервных копий находится на другом компьютере в сети.
Поверхностное клонирование ( мелкие клоны )
В Git есть возможность ограничить количество коммитов, которые можно клонировать.К сожалению, этого ограничения недостаточно для работы с огромными репозиториями вроде Windows, поскольку каждый коммит вместе с его деревьями и блобами занимает до 80 ГБ.
Более того, в большинстве случаев для нормальной работы нам не нужно всё содержимое коммитов.
Кроме того, поверхностное клонирование не решает проблему большого количества файлов в рабочем каталоге.
Частичный ( редкий ) проверить
Когда вы оформляете заказ, Git по умолчанию помещает все файлы из этого коммита в ваш рабочий каталог.Однако в файле .
git\info\sparse-checkout вы можете ограничить список файлов и папок, которые можно разместить в рабочем каталоге.
Мы возлагали большие надежды на этот подход, поскольку большинство разработчиков работают только с небольшим набором файлов.
Как оказывается, у частичных есть свои недостатки:
- Частичные извлечения не применяются к индексу, а только к рабочему каталогу.
Даже если вы ограничите размер рабочего каталога 50 тысячами файлов, индекс все равно будет включать все 3 миллиона файлов;
- Частичная проверка является статической.
Если вы включили каталог А , а кто-то позже добавил зависимость от каталога Б , ваша сборка будет сломана, пока вы не включите Б к списку каталогов для частичной выписки;
- Частичные извлечения не применяются к файлам, загруженным во время операций клонирования и выборки, поэтому даже если ваши извлечения не имеют ничего общего с 95% файлов, вам все равно придется их загружать;
- UX ( Пользовательский опыт ) частичные кассы использовать неудобно
Хранилище для больших файлов ( LFS, хранилище больших файлов )
Каждый раз, когда мы изменяем большой файл, его копия создается в истории изменений Git. Чтобы сэкономить место, Git-LFS заменяет эти большие BLOB-файлы их указателями, а сами файлы помещаются в отдельное хранилище.Поэтому при клонировании вы загружаете только указатели на файлы, а затем LFS загружает только те файлы, которые вы извлекаете.
Было непросто заставить LFS работать с репозиторием Windows. В итоге нам это удалось, что позволило существенно уменьшить общий размер репозитория.
Но мы до сих пор не решили проблему большого количества файлов и размера индекса.
Мне тоже пришлось отказаться от этого подхода.
Виртуальная файловая система ( Виртуальная файловая система )
Вот к каким выводам мы пришли после всех вышеописанных экспериментов:- Монолитный репозиторий — наш единственный путь
- Большинству разработчиков для работы требуется лишь небольшое подмножество файлов в репозитории.
Но им важно иметь возможность вносить изменения в любую часть этого репозитория.
- Мы хотели бы использовать существующий клиент git, не внося в него огромное количество изменений.
- Загрузка только необходимого минимума BLOB-файлов.
Для большинства разработчиков это означает около 50-100 тысяч файлов и истории их изменений.
Большая часть репозитория никогда не будет скопирована.
- Немного подправив, вы можете заставить git учитывать только те файлы, с которыми работает разработчик.
Таким образом, такие операции, как git status и gitcheckout, будут выполняться намного быстрее, чем если бы они выполнялись со всеми 3 миллионами файлов.
- С помощью частичного извлечения мы можем размещать в рабочем каталоге только используемые файлы.
И что еще более важно, каждая проверка будет ограничена только файлами, необходимыми разработчику.
- Все используемые нами инструменты разработки продолжат работать без изменений, файловая система позаботится о том, чтобы запрошенные файлы всегда были доступны.
- Спроектировать файловую систему непросто.
- Производительность должна быть на высоте.
Нам можно простить небольшую задержку при первом доступе к файлу, но повторный доступ к тому же файлу должен быть практически мгновенным.
- Задержки при доступе к файлам можно и нужно уменьшить за счет предварительной загрузки.
Обычно большое количество мелких объектов приводит к наибольшим задержкам.
Примером может служить огромное количество очень маленьких объектов дерева git.
- Нам еще предстоит выяснить, как заставить git работать с виртуальной файловой системой.
Как мне избежать обхода git всех 3,5 миллионов файлов, если git выглядит так, будто все эти файлы на самом деле находятся на диске? Хорошо ли работают команды git с настройками частичной проверки? Возможно ли, что git обойдет слишком много файлов blob?
-
Гитаризм Для Linux — Почему Бы И Нет?
19 Oct, 24 -
С Днем Рождения, Википедия!
19 Oct, 24 -
Google Voice Тестируется В Европе
19 Oct, 24 -
Stm32H7 — Настройка Часов Без Hal
19 Oct, 24 -
Крупнейшая Афера В Истории Виртуальных Миров
19 Oct, 24 -
Ничего Лишнего, Просто Фотографии.
19 Oct, 24