Транковая разработка
Узнайте о транковой разработке: частые коммиты в одну ветку, короткоживущие ветки и флаги функций для непрерывной доставки.
Обзор
Транковая разработка — это рабочий процесс, при котором каждый разработчик интегрирует изменения в единую общую ветку — транк (обычно main) — как минимум раз в день. Ветки, если и используются, существуют совсем недолго — часы, а не недели. Это рабочий процесс, лежащий в основе настоящей непрерывной интеграции, и он предпочтителен для команд, которые выполняют деплой часто.
Основная идея
Чем дальше ваш код уходит от кода остальных участников, тем сложнее становится интеграция. Стоимость слияния растёт вместе с размером расхождения: ветка, просуществовавшая две недели, накапливает больше конфликтов, и эти конфликты сложнее разрешать, поскольку с обеих сторон изменилось очень многое.
Транковая разработка напрямую решает эту проблему, удерживая разрыв минимальным. Вы интегрируетесь в транк постоянно — как минимум раз в день, — поэтому любой конфликт невелик и обнаруживается, пока изменение ещё свежо в памяти. Нет долгоживущей ветки develop и нет массивных слияний. Транк всегда находится в готовом к релизу состоянии.
Существует два распространённых стиля:
- Коммиты прямо в транк. Небольшие команды фиксируют изменения непосредственно в
main, опираясь на проверки перед отправкой и парное ревью. Это наиболее чистая форма. - Короткоживущие ветки. Большие команды создают ветку для каждого изменения, открывают pull request и выполняют слияние за день-два. Ветка существует ровно столько, сколько нужно для запуска CI и быстрого ревью.
Типичный цикл работы с короткоживущей веткой выглядит так:
git switch main # start from the trunk
git pull # get everyone else's latest work
git switch -c quick-fix # tiny, focused branch
# ...a few hours of work...
git switch main
git pull # pull again — others have merged since you branched
git merge quick-fix # fast, because divergence is small
git push # back on the trunk within the same dayПовторный git pull здесь намеренный: получение изменений перед слиянием удерживает вашу ветку близко к транку, поэтому слияние остаётся тривиальным. Если вы предпочитаете линейную историю, некоторые команды делают rebase короткоживущей ветки поверх main вместо слияния. Подробнее о механике веток и pull request читайте в разделе рабочий процесс с ветками функций.
Флаги функций: безопасная доставка незавершённой работы
Если все ежедневно выполняют слияние в транк, как быть с функцией, разработка которой занимает две недели? Держать ветку живой так долго — значит сводить на нет весь смысл подхода. Ответ — флаг функции: переключатель времени выполнения, определяющий, будет ли новый код действительно запущен. Вы вливаете незавершённый код, но оставляете его выключенным:
const featureFlags = { newCheckout: false };
function checkout() {
if (featureFlags.newCheckout) {
return "new checkout";
}
return "old checkout";
}
console.log(checkout()); // old checkout — flag is off in productionНовый код попадает в продакшн, скрытый за флагом. Когда он готов, вы переключаете newCheckout в true — повторный деплой не требуется. Это разделяет доставку кода и выпуск функции, что и позволяет незавершённой работе безопасно существовать в транке.
Несколько практических правил, не позволяющих флагам превратиться в хаос:
- По умолчанию — выключен. Новый код остаётся скрытым, пока вы намеренно его не включите, зачастую сначала для внутренних пользователей.
- Флаги — временные. Как только функция полностью выпущена, удалите флаг и неработающую ветку
else— устаревшие флаги накапливаются быстро и затрудняют чтение кода. - Тестируйте оба пути. CI должен выполнять код как с включённым, так и с выключенным флагом, поскольку оба варианта попадают в продакшн.
Что этот подход требует
Транковая разработка — быстрая, но не небрежная: она работает только при наличии надёжных вспомогательных практик:
- Надёжный CI: каждый push запускает автоматический набор тестов, потому что сломанный транк блокирует всю команду.
- Небольшие, частые коммиты: крупные изменения разбиваются на безопасные, поэтапные шаги.
- Флаги функций для всего, что невозможно завершить в рамках одной короткоживущей ветки.
- Быстрое ревью кода, часто в виде небольших pull request, которые сливаются за несколько часов.
Если ревью занимает дни, ветки живут дни, и транковой разработкой вы уже не занимаетесь. Вспомогательные практики — не дополнительные опции, они и делают скорость безопасной.
Релизы из транка
Поскольку транк всегда готов к релизу, выпуск релизов прост. Доминируют два паттерна:
-
Релиз с верхушки. Деплоите
mainнапрямую, так часто, как хотите. Каждый релиз помечайте тегом, чтобы точно знать, что было выпущено:git switch main git pull git tag -a v1.4.0 -m "Release 1.4.0" git push origin v1.4.0 -
Создание релизной ветки. Для продуктов с версионированными релизами из транка создаётся короткоживущая релизная ветка, стабилизируется, и тег ставится из неё. Исправления вносятся сначала в транк, а затем cherry-pick-ом переносятся в релизную ветку — но никак не наоборот, чтобы транк оставался единственным источником истины.
Оба варианта поддерживают транк в здоровом состоянии: он всегда содержит актуальный рабочий код, а релизы — это снимки, взятые из него.
Транковая разработка vs Gitflow
Gitflow оптимизирован для контролируемых версионированных релизов со множеством типов веток. Транковая разработка оптимизирована для скорости и непрерывной доставки с фактически одной веткой. Если вы выполняете деплой несколько раз в день, транковая разработка подходит; если вы выпускаете версионированные релизы по расписанию, структура Gitflow может подойти вам лучше.
| Транковая разработка | Gitflow | |
|---|---|---|
| Долгоживущие ветки | Только транк | main и develop |
| Время жизни ветки | Часы или день | Дни или недели |
| Интеграция | Постоянная, ежедневная | Во время релиза |
| Лучше подходит для | Непрерывной доставки | Планового версионированного выпуска |
Когда использовать
Выбирайте транковую разработку, когда вы выполняете деплой часто, располагаете надёжными автоматическими тестами и можете обеспечить быстрое ревью кода. Она даёт преимущества командам, которые ценят короткие циклы обратной связи больше, чем тяжёлые процессы. Если ваши тесты ненадёжны, ревью происходит медленно или вам нужно собирать работу в плановые релизы, рабочий процесс с ветками функций или Gitflow будут менее болезненными. Для обзора всех распространённых моделей см. обзор рабочих процессов Git.