Git и зависимости проекта
Никола Паолуччи
Консультант по разработке
Задумайтесь над следующими вопросами.
Как вы обрабатываете зависимости проекта с помощью Git
?
Наш проект состоит из нескольких взаимозависимых репозиториев. Сейчас мы управляем ими с помощью svn:externals
. Как лучше всего обрабатывать их с помощью Git
?
Как разбить очень большой репозиторий на более мелкие компоненты с помощью Git
?
Эти и другие вопросы нам задают чаще всего.
Судя по всему, эти вопросы не дают покоя многим командам разработчиков ПО, использующих Git
, поэтому я постараюсь ответить на них в этой статье.
Очевидно, что зависимости проекта и инфраструктура сборки тесно взаимосвязаны, и даже сотрудники Atlassian не удержались от обсуждения будущего сборок.
Использование нескольких отдельных репозиториев вместо одного общего может вызывать дополнительные трудности. Но это довольно естественный — а порой и обязательный — этап в развитии проекта. Тому есть по меньшей мере две основные причины: увеличение времени сборки и наличие общих зависимостей в проектах.
Общие рекомендации и неоптимальные решения
Вернемся к вопросу о том, как отслеживать зависимости проекта и управлять ими с помощью git
.
Так вот, этого лучше не делать.
Чтобы ответить серьезно, нужно сначала изучить основы и только затем переходить к деталям. Важно понять, что в git или других решениях нет волшебного рецепта
, который избавит вас от проблем с зависимостями проектов.
По достижении проектом определенного размера стоит разбить его на логические компоненты, но не дожидайтесь момента, когда в репозитории накопится более 100 миллионов строк кода. Далее я приведу лишь рекомендации, с помощью которых вы сможете выработать собственный подход.
Связанные материалы
Установка Git
СМ. РЕШЕНИЕ
Изучите Git с помощью Bitbucket Cloud
Первый вариант: подходящий инструмент для сборки или управления зависимостями на замену git
В текущих условиях я рекомендую инструмент управления зависимостями. Он поможет справиться с трудностями роста в крупных проектах, включая большое время сборки.
Разделите модули между отдельными репозиториями и управляйте их взаимными зависимостями с помощью специализированного инструмента. Такое решение найдется почти для каждого стека технологий. Вот несколько примеров:
- Maven (или Gradle), если вы используете Java;
- npm для приложений Node.js;
- Bower, Component.io; и другие продукты, если вы используете Javascript (обновлено);
- Pip и файл requirements.txt, если вы используете Python;
- RubyGems и Bundler, если вы используете Ruby;
- NuGet для платформы .NET;
- Ivy (или какое-либо пользовательское действие в CMake) для C++ (обновлено);
- CocoaPods для приложений Cocoa iOS;
- Composer или Phing для PHP (добавлено).
- В Go инфраструктура сборки и зависимостей частично встроена в язык (при этом многие выбирают более универсальное решение — godep). Вместе с Bitbucket на сервере Git мы используем Maven и Bower. Во время сборки такое ПО извлекает правильные версии зависимостей, которые затем можно включить в основной проект. Некоторые из этих инструментов имеют ограничения и могут работать исходя из неоптимальных допущений, однако даже с учетом этого факта их можно назвать проверенными и жизнеспособными.
Проблемы разделения проекта
Говоря простыми словами, в начале проекта весь код упаковывается в одну сборку. Однако по мере роста сборка может замедляться, в результате чего вам придется воспользоваться функцией кэширования. Для этого применяют управление зависимостями. Так, для проектов на динамическом языке отлично подойдут подмодули (об этом дальше). Мне кажется, что рано или поздно время сборки становится проблемой для большинства разработчиков, а потому вам стоит обзавестись инструментом управления зависимостями.
Разделение компонентов между отдельными репозиториями вызывает ряд сложностей. Перечислю их в произвольном порядке:
- для внесения изменений в компонент нужен релиз;
- реализация подхода отнимает время и может провалиться по глупым причинам;
- этот подход неоправдан при небольших изменениях;
- нужно вручную настраивать новые сборки для каждого компонента;
- возникают проблемы с обнаружением репозиториев;
- нужна рефакторизация, если в репозитории находится не весь исходный код.
- В некоторых конфигурациях (например, в нашей) для обновления API сначала нужно выпустить промежуточный релиз, затем — обновить плагин и снова обновить продукт. Возможно, здесь не хватает пары этапов, но главное — общая идея. Такое решение проблемы далеко от идеального.
Второй вариант: подмодуль git
Если вы не можете или не хотите работать с инструментом для управления зависимостями, можно воспользоваться подмодулями
в git
. Такой вариант может оказаться удобным, особенно при работе с динамическими языками. Однако подмодули не всегда уменьшают время сборки. Я уже давал рекомендации и советы относительно них и рассматривал альтернативные решения. Кроме того, в Интернете к подмодулям иногда относятся скептически.
Точное соответствие между svn:externals и git
Важное примечание. Если вам нужно точно воспроизвести рабочий процесс svn:externals
в git
, используйте подмодули
. При этом настройте подмодули
таким образом, чтобы они отслеживали ветки релизов, не затрагивая случайные коммиты.
Третий вариант: другие инструменты сборки и управления межплатформенными зависимостями
Проекты не всегда бывают полностью однородными, и иногда их нельзя создать и собрать с помощью одного инструмента. К примеру, в некоторых проектах для мобильных устройств одновременно присутствуют зависимости Java и C++ или используются сторонние инструменты для создания ресурсов. В таких сложных ситуациях можно оснастить git
дополнительными функциями. Отличным примером здесь служит репозиторий Android.
Вот другие инструменты сборки, с которыми стоит ознакомиться:
Заключение и дальнейшее чтение
В продолжение темы инфраструктуры сборки (и Maven), рекомендую ознакомиться со следующими статьями, предложенными Чарльзом О'Фарреллом.
- В поисках идеального инструмента сборки
- Решение Maven само по себе неудачно (продолжение от того же автора)
- Рекурсия в Maven считается опасной
В заключение приведу замечательную цитату из последней статьи. И хотя речь идет о Maven, она справедлива и для других инструментов сборки и управления зависимостями.
«Кэш не дает никакого эффекта, кроме ускорения работы. Если удалить его полностью, окружающая система продолжит работать как обычно (пусть и медленнее). Вместе с тем у кэша нет и побочных эффектов. Неважно, что вы делали с ним ранее: один и тот же запрос к кэшу вернет идентичное значение в любой момент времени.
Но Maven совсем не подходит под это описание. Репозитории Maven выполняют функции кэшей, не обладая нужными свойствами. При отправке запроса к такому репозиторию ваши прошлые действия играют большую роль. Репозиторий Maven вернет последние данные, которые вы в него загрузили. А запрос чего-либо пока не загруженного даже может привести к сбою».
Поделитесь этой статьей
Следующая тема
Рекомендуемые статьи
Добавьте эти ресурсы в закладки, чтобы изучить типы команд DevOps или получать регулярные обновления по DevOps в Atlassian.