Стратегии ветвления git

05.01.2022

Стратегия ветвления (branch strategy, git workflow) - организация разработки проекта ПО с помощью системы управления версиями (в данном случае git), определяющая правила ветвления, интеграции и доставки кода.

При разработке кода командой разработчиков, каждый выполняет свои задачи и пишет определенный код, параллельно с другими. Стратегия ветвления позволяет сформулировать правила эффективного обмена кодом без сбоев (с минимизацией) в работе.

В статье рассмотрено 4 основные стратегии ветвления, на основании приведенных в статье источников. Краткий обзор на сколько это возможно чтобы отразить фундаментальные правила каждой стратегии для общего понимания. Для детального изучения необходимо обратиться к ссылкам.

Дополнительно можно ознакомится с кратким описанием стратегий здесь и тут, подробнее там.

Git flow

Git flow - стратегия ветвления при которой, существуют фиксированные ветки, от которых порождаются дополнительные (долгоживущие) где и производится вся разработка. По завершении работы с дополнительными ветками они вливаются в фиксированные и удаляются.

Git-flow может подойти командам, которые разрабатывают ПО с жестким версионированием (например месячные или квартальные релизы, прим. George Stocker) или занимаются поддержкой нескольких версий приложения параллельно.

Vincent Driessen

Схематичное представление Git flow (источник)
Схематичное представление Git flow (источник)

Git flow была представлена в блоге Vincent Driessen в 2010 году (перевод на хабре). В 2020 году George Stocker на своем блоге опубликовал статью с критикой (перевод на хабре) идеализации git flow.

Ветки:

  • master - стабильная ветка, готовая к развертыванию кода, но если внезапно в этой ветке есть ошибки, которые необходимо исправить тогда от этой ветки создаются ветки:
    • hotfix-* - ветки исправления, по завершении сливаются с master
  • develop - развивающаяся/разрабатываемая ветка, по окончании разработки очередной версии вливается в master. От develop могут происходить следующие ветки:
    • feature-* - ветки новых функции, по завершении сливается с develop
    • release-* - релизные ветки, создаются при необходимости нового релиза. Причины создания таких веток могут носить косметический характер. По завершении подготовки ветки к релизу, создается тег и ветка вливается в develop

Github flow

Github flow - стратегия ветвления используемая в компании GitHub, где существует лишь одна фиксированная ветка master, которая в любой момент готова к развертыванию (deployable branch). Все остальные (тематические) ветки создаются от master и вливаются в нее же.

Github flow подразумевает короткий срок жизни тематических веток, частые релизы, дисциплинированность команды разработки, готовой при каждом pull request принять участие в обсуждении. Подходит для SaaS.

Оригинал можно прочитать в гайде github (перевод на хабре) и в статье на блоге Scott Chacon (перевод на хабре).

Схематичное представление Github flow (источник)
Схематичное представление Github flow (источник)

Этапы работы:

  1. создание новой ветки (с понятным названием) от master или fork с последующим создание ветки от master
  2. push новых коммитов
  3. открытие pull request для обсуждения
  4. обсуждение
  5. тестирование
  6. если при тестировании не было выявлено проблем, а в ходе обсуждения было получено одобрение внесенных изменений тогда происходит вливание этой ветки в master, иначе необходимо внести правки в тематическую ветку и продолжить обсуждение/тестирование
  7. удаление ветки (вся история уже перенесена в master)
Особое внимание хочется уделить пункту 6. В приведенных выше источниках есть некоторая неточность по этому поводу.

В одном говорится что перед сливанием тематической ветки с master необходимо проверить ветку в боевом окружении (хотя в оригинале этот пункт отсутсвует), об этом говорит статья Deploying at GitHub от Jake Douglas (упоминание которой можно найти здесь).

В другом источнике (оригинал или перевод) этот момент явно не сказан, но видимо подразумевается, так как при отсутсвии реального тестирования в реальном окружении ветка master перестает быть стабильной и готовой к развертыванию в любой момент что противоречит Github flow. Но комментарий к переводу вносит некоторую ясность.

Gitlab flow

Gitlab flow - стратегия ветвления предложенная компанией Gitlab (ссылка на краткое описание, ссылка на полное описание, а еще перевод здесь и тут).

Gitlab flow ориентирована на проекты разного рода (SaaS, с жестким версионированием, поставку кода клиентам и другое). Движение кода между ветками осуществляется только вперед (сверху вниз).

Gitlab flow так же как и Github flow нацелен на стабилизацию ветки master и выделение от нее тематических короткоживущих веток. Однако, master не является конечной веткой для доставки ПО/кода клиентам, master в контексте Gitlab flow является веткой свободной для вливания тематических веток, от которой код пойдет дальше (по пути релиза/доставки клиентам).

Gitlab flow разделяет проекты условно на:

  • SaaS с CI/CD конвейером, когда пользователи проекта используют результат работы кода в виде сервиса, а доступ к исходному коду не нужен
  • релизные для внешних клиентов, когда пользователи проекта используют исходный код непосредственно
В случае SaaS код из master продвигается в следующие ветки, в каждой из которых настроена своя среда для тестирования:
  • staging - опциональная ветка, первый рубеж тестирования
  • pre-production - опциональная ветка, второй рубеж тестирования
  • production - обязательная ветка, из которой происходит деплой проекта
Движение кода по веткам: feature-master-pre-production-production

Схематичное представление ветвления для разных сред Gitlab flow (источник)
Схематичное представление ветвления для разных сред Gitlab flow (источник)

Для поставки внешним клиентам Gitlab Flow предусматривает релизные ветки от master, именуемые как version-type, например при использовании семантического версионирования указывается мажорная и минорная версии с постфиксом, например 2.3-stable. При вливании нового комита с релизную ветку создается тег с указанием конкретной версии.

Cозданная релизная ветка может развиваться своим путем, принимая от master обновления, но обновления релизной ветки не попадут в master.

Допускается вместо ветки master иметь ветку stable обозначающую стабильную версию ПО.

Движение кода по веткам: feature-master-version-type

Схематичное представление релизных веток Gitlab flow (источник)
Схематичное представление релизных веток Gitlab flow (источник)

Trunk Based Development

Trunk Based Development (TBD) - стратегия ветвления, которая предполагает наличие основной (стабильной, готовой к деплою/релизу) ветки master или trunk, ответвления от которой живут до двух дней в количестве <=3 и вливаются в master не реже одного раза в 24 часа, либо вообще отсутствуют - все комиты поступают в master.

Trunk Based Development:
  • воплощает идею CI (непрерывной интеграции) сокращая временную дистанцию кода каждого разработчика до минимума
  • заставляет максимально декомпозировать задачи
  • предполагает хороший климат в команде разработчиков - когда возможно парное программирование или программирование у одного монитора
  • своевременный/синхронный code review и continuous-review вынуждающий каждого разработчика быть в курсе изменений (коллективное владение кодом)

Более детально можно ознакомится на сайте trunkbaseddevelopment.com, краткий обзор и рекомендации от google, интересная статья про пуш в мастер, статья про то почему не нужны ветки для фич.

Схематичное представление Trunk Based Development (источник)
Схематичное представление Trunk Based Development (источник)

Идея пушить в master кажется не совсем разумной, но у этой стратегии есть несколько вариантов, что придает ей смысл:

  • при наличии малого количества разработчиков (<=2) пушить можно сразу в master при успешном локальном тестировании изменений на стороне разработчиков
  • тематическое ветвление все-же возможно для больших команд (>2 разработчиков), тестирование проходит на тематических ветках, а процесс слияния с master не исключает pull request
  • релизные ветки тоже могут быть, срок жизни такой же как у тематических, но можно обойтись и без релизных веток - создавать релизы прямо из master
Для следования правилам Trunk Based Development есть вспомогательные методики:
  • branch by abstraction (ветвление через абстракцию) для оборачивания какого-то функционала в абстракцию в течении одной ветки, и дальнейшая замена реализации этой абстракции в течении одной или нескольких веток. Почитать здесь и тут
  • feature flags (переключатели функций) для того чтобы протолкнуть еще незавершенные функции в master но не дать ими пользоваться, либо для включения/выключения функций в real-time либо для других целей. Это простые if'ы условия для которых, берутся из какой-то базы данных переключателей. Почитать здесь, тут, там, и пример возможно неверного подхода к feature flags

Итог

Git flow критикуется за идиализацию, и имеет проблемы с мержем при длительной жизни веток (что логично). Trunk Based Development критикуется за поверхностное восприятие как "коммит в master" (что не совсем верно) и привносит дополнительную методику feature flags (хотя может использоваться не только в TBD) что влечет вопросы касательно тестов.

Github flow и Trunk Based Development имеют значительные сходства.

Github flow с точки зрения Gitlab flow (это можно увидеть из статьи на gitlab.com) является неполноценной.

Как видно из описания, каждая стратегия преследует свои цели, имеет достоинства и недостатки и нацелена на определенные проекты/команды разработки и каждая из них имеет применение.

На последок цитата Vincent Driessen (автор статьи "Удачная модель ветвления для Git" популяризующей Git flow) на критику :

В заключение хочу напомнить вам, что панацеи не существует. Учитывайте свои условия, контекст и думайте своей головой!

Vincent Driessen