awesome-everything EN
↑ Обратно к восхождению

Инженерная практика

Короткоживущие ветки против gitflow

Суть Trunk-based — это короткоживущие ветки (три или меньше, живут меньше дня, без фазы интеграции), а не отсутствие веток. Gitflow хорош для плановых релизов, но насаждает разрыв при непрерывной доставке. Крупные рефакторинги живут в trunk через branch by abstraction.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на middle-высоте — в небе
◷ 16 min

Команда читает «trunk-based development» и слышит «коммить прямо в main, без веток, без PR». Они отключают защиту веток. За неделю trunk краснеет дважды в день, незапрошенное изменение утекает с кредами, и они заключают, что trunk-based «не масштабируется». Они выбросили не то. Trunk-based никогда не был про удаление веток — он про то, чтобы держать их настолько короткоживущими, чтобы они не накапливали разрыв. Ветка живёт час, за зелёным гейтом и ревью, а потом её нет.

Что на самом деле задаёт «короткоживущая»

Определение trunk-based от DORA конкретно, а не «по ощущениям». Держите три или меньше активных веток в репозитории в любой момент. Ветки должны жить не более одного дня до слияния в trunk — часто всего несколько часов. Нет заморозок кода и нет фаз интеграции. Каждая ветка — это одно малое, узкое изменение, которое открывает PR, проходит быстрый CI-гейт, получает быстрое ревью и мёржится в тот же день. Ветка — это зона ожидания для ревью и гейтинга, а не место, где работа живёт.

Иногда это запускают как чистый «коммит в trunk» (вообще без веток, частое в малых co-located командах с парным программированием), а чаще как «короткоживущие feature-ветки» (версия, которую использует большинство, потому что она сохраняет код-ревью и PR-гейт). Обе — trunk-based. Разделительная черта не «ветка или не ветка» — это время жизни. Ветка, живущая часы, — trunk-based; ветка feature/*, живущая две недели, — это долгоживущая ветка, ради устранения которой существует практика, как бы вы ни называли свой workflow.

Почему gitflow оптимизирован под противоположный мир

Gitflow даёт вам постоянные ветки main и develop, плюс ветки feature/*, release/* и hotfix/* с формальными фазами: фичи интегрируются в develop, ветка release стабилизируется, затем мёржится в main и тегается. Это связная модель — для мира, под который она была спроектирована: «коробочный», версионированный софт с плановыми релизами, несколько поддерживаемых в поле версий и без непрерывного развёртывания. В том мире явная фаза стабилизации и параллельные релизные линии оправдывают себя.

Для непрерывно развёртываемого веб-сервиса gitflow институционализирует ровно тот разрыв, о котором предупреждал прошлый урок. Долгоживущие ветки feature/* накапливают расхождение; продвижение develop-в-release-в-main — это встроенная фаза интеграции; «готовые» фичи лежат в develop и гниют, пока ждут следующего релизного поезда. Вы наследуете big-bang слияния и заморозки кода по дизайну. Исследование DORA явно отмечает фазы интеграции и заморозки кода как анти-паттерны для производительности доставки — gitflow делает их несущими.

ИзмерениеGitflowGitHub flowTrunk-based
Долгоживущие веткиmain + develop (+ release)только mainтолько trunk
Жизнь feature-веткиДни–неделиДо слияния PR (варьируется)Часы, < 1 дня
Фаза интеграцииЯвная (release-ветка)НетНет
Под что построенВерсионированные плановые релизыВеб-приложения, непрерывный деплойНепрерывный деплой в масштабе
РелизПродвинуть develop → release → mainРазвернуть слитый mainТег/ветка от trunk в точке релиза

Релизить без долгоживущих веток

Возражение: «если есть только trunk, откуда берутся релизы, и как мне пропатчить старую версию?» У trunk-based есть конкретный ответ — ветка для релиза, а не для фичи. Когда вы нарезаете релиз, вы создаёте короткоживущую ветку release/x.y от trunk на этом коммите. Повседневная разработка на ней никогда не идёт. Если нужен критический фикс, вы чините его сначала на trunk (чтобы следующий релиз тоже его имел) и cherry-pick-аете единственный коммит на release-ветку. Release-ветка — это read-mostly снимок, а не параллельная линия разработки, так что она никогда не накапливает разрыв. Команды на непрерывном деплое часто пропускают даже это и просто тегают trunk.

Для больших изменений, которые действительно нельзя выкатить за день — замена ORM, смена платёжного провайдера — инструмент trunk-based — это branch by abstraction, а не долгоживущая ветка. Вы вводите слой абстракции над тем, что заменяете, инкрементально строите новую реализацию за ним на trunk (каждый шаг мёржится ежедневно, тёмный, пока не готов), переключаете абстракцию на новую реализацию, затем удаляете старую и саму абстракцию. Большой рефакторинг всё это время живёт на trunk как последовательность малых зелёных коммитов — никогда как трёхнедельная ветка.

Почему это работает

Ловушка именования реальна: ветка feature/* в gitflow-репозитории и короткоживущая ветка в trunk-based репозитории могут выглядеть в git идентично. Разница невидима в ветке и видна только в её времени жизни и дисциплине вокруг. «Мы используем feature-ветки» не говорит вам ничего о том, trunk-based вы или нет — «наши ветки мёржатся или удаляются за день» говорит всё.

Выбери лучший вариант

Вы заменяете ORM в непрерывно развёртываемом сервисе. Миграция займёт шесть недель. Как сделать это по trunk-based?

Викторина

Где проходит настоящая разделительная черта между trunk-based и workflow с долгоживущими ветками?

Викторина

Как в trunk-based development обрабатывается критический фикс к уже выпущенной версии?

Расставь шаги по порядку

Упорядочьте миграцию branch by abstraction на trunk:

  1. 1 Ввести слой абстракции над компонентом, который заменяете
  2. 2 Строить новую реализацию за абстракцией малыми ежедневно-сливаемыми коммитами, тёмной
  3. 3 Переключить абстракцию на новую реализацию
  4. 4 Проверить в проде, затем удалить старую реализацию
  5. 5 Убрать ставший лишним слой абстракции
Вспомните перед уходом
  1. 01
    Команда отключила всю защиту веток, потому что прочла, что trunk-based означает «без веток». Что они недопоняли, и что trunk-based на самом деле задаёт?
  2. 02
    Если есть только trunk, как вы нарезаете релизы и делаете шестинедельный рефакторинг без долгоживущей ветки?
Итог

Trunk-based development запрещает долгоживущие ветки, а не сами ветки — DORA задаёт три или меньше активных веток, время жизни менее дня и отсутствие фаз интеграции или заморозок кода. Коммитите вы прямо в trunk или используете короткоживущие feature-ветки с PR — отличающая переменная это время жизни, а не наличие ветки. Структура gitflow main/develop/release/hotfix связна для «коробочного», планового, мульти-версионного софта, но для непрерывно развёртываемого сервиса институционализирует тот самый разрыв, big-bang слияния и фазы интеграции, ради устранения которых существует trunk-based. Релизы приходят из короткоживущих веток, нарезанных от trunk, с фиксами, сделанными на trunk первыми и cherry-pick-ну­тыми вниз, чтобы release-ветка никогда не становилась параллельной линией разработки. А изменения, слишком большие для выката за день, используют branch by abstraction — слой абстракции, новую реализацию за ним малыми ежедневными коммитами, переключение, затем зачистку — так что даже шестинедельный рефакторинг живёт на trunk как малые зелёные шаги вместо долгоживущей ветки.

Связанные уроки
Продолжить восхождение ↑Feature-флаги отвязывают деплой от релиза
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources4
expand
  1. 01
  2. 02
  3. 03
  4. 04

Trademarks belong to their respective owners. Editorial reference only.