Пошук уроків, статей та іншого контенту
Налаштуйте розробку навколо основної гілки з короткоживучими гілками, частими інтеграціями та feature flags.
Trunk-Based Development — це підхід до розробки, у якому команда постійно інтегрує зміни в одну основну гілку — зазвичай main.
Замість довгоживучих гілок для великих функцій використовують:
короткоживучі гілки, які існують від кількох годин до одного-двох днів;
невеликі коміти;
часті pull request-и;
автоматичні перевірки перед інтеграцією;
feature flags для прихованого або поступового ввімкнення незавершених функцій.
Основна ідея: код має часто потрапляти в main, але це не означає, що кожна зміна одразу доступна всім користувачам.
У цьому підході main має бути:
стабільною;
такою, що збирається;
перевіреною автоматичними тестами;
готовою до розгортання або вже розгорнутою в середовище.
Розробники регулярно отримують останні зміни з main і не накопичують великі відмінності між своїми гілками та основною гілкою.
Типовий цикл виглядає так:
Отримати актуальний стан main.
Реалізувати невелику частину функціональності.
Запустити локальні перевірки.
Створити pull request.
Дочекатися перевірок CI та code review.
Інтегрувати гілку в main.
Видалити гілку.
Гілка повинна містити невелику, завершену частину роботи. Наприклад:
feature/add-login-button
fix/validate-email
chore/update-dependenciesПеред початком роботи синхронізуйте локальну main:
git switch main
git pull --ff-only origin mainСтворіть нову гілку:
git switch -c feature/add-login-buttonПісля внесення змін перевірте стан репозиторію:
git status
git diffЗробіть невеликий коміт:
git add src/login-button.js
git commit -m "Add login button"Опублікуйте гілку:
git push -u origin feature/add-login-buttonДалі створіть pull request у main. Після схвалення та успішних перевірок гілка інтегрується в основну.
Чим довше існує гілка, тим більше вона віддаляється від main. Це збільшує ймовірність:
конфліктів під час злиття;
дублювання роботи;
несумісності з актуальним кодом;
складного code review;
помилок під час інтеграції.
Коротка гілка обмежує розмір змін і спрощує їх перевірку.
У Trunk-Based Development інтеграція відбувається часто, а не наприкінці великого етапу.
Перед оновленням pull request перевірте, чи змінився main:
git fetch origin
git rebase origin/mainЯкщо після rebase виникли конфлікти:
git statusВиправте конфліктні файли, додайте їх і продовжте операцію:
git add path/to/resolved-file.js
git rebase --continueПісля rebase гілку потрібно повторно відправити на сервер:
git push --force-with-lease--force-with-lease безпечніший за звичайний --force: Git перевіряє, що віддалену гілку не змінив хтось інший.
Частий
rebaseне замінює перевірки. Після оновлення гілки потрібно повторно запускати тести та інші локальні перевірки.
Коміт у цьому підході має бути логічно завершеним. Бажано, щоб він:
змінював одну частину функціональності;
легко пояснювався в одному реченні;
не містив випадкових змін форматування;
проходив тести самостійно або разом із сусідніми комітами pull request-а.
Невдалі приклади:
Update
Fix stuff
ChangesКращі приклади:
Add email format validation
Handle expired session response
Show loading state on login formМаленькі коміти спрощують review, пошук помилки та відкат окремої зміни.
Іноді функціональність ще не готова для користувачів, але її код уже потрібно інтегрувати в main. Для цього використовують feature flags — умовні перемикачі функцій.
Feature flag відокремлює:
доставку коду в основну гілку;
розгортання коду;
доступність функції для користувачів.
Наприклад, новий екран можна додати до main, але показувати його лише коли змінна середовища має значення true.
// Повертає true, якщо функцію явно ввімкнено.
function isNewDashboardEnabled() {
return process.env.NEW_DASHBOARD === "true";
}
function renderDashboard() {
if (isNewDashboardEnabled()) {
return "New dashboard";
}
return "Current dashboard";
}
console.log(renderDashboard());Запуск із вимкненою функцією:
node dashboard.jsРезультат:
Current dashboardЗапуск із увімкненою функцією в macOS або Linux:
NEW_DASHBOARD=true node dashboard.jsРезультат:
New dashboardFeature flags дають змогу:
інтегрувати незавершену роботу;
увімкнути функцію лише для тестувальників;
поступово розгорнути зміни;
швидко вимкнути проблемну функцію без нового релізу.
Feature flag не повинен залишатися в коді назавжди. Для кожного перемикача варто визначити:
зрозумілу назву;
значення за замовчуванням;
відповідального;
умови ввімкнення;
план видалення після стабілізації функції.
Коли функція стала основною, умовний код і сам flag потрібно видалити. Інакше в проєкті накопичується технічний борг і стає важко зрозуміти, яка поведінка є актуальною.
Щоб main залишалася стабільною, у репозиторії зазвичай налаштовують правила захисту:
прямі push-операції до main заборонені або обмежені;
зміни потрапляють через pull request;
перед злиттям мають пройти автоматичні перевірки;
потрібне code review;
незавершений або невдалий CI не дозволяє інтеграцію.
Конкретні правила залежать від платформи та політики команди, але мета одна: не дозволити зламати main необробленою зміною.
Уявімо, що потрібно додати нову форму профілю.
Оновіть main:
git switch main
git pull --ff-only origin mainСтворіть короткоживучу гілку:
git switch -c feature/profile-formДодайте базову структуру форми та feature flag.
Зробіть коміт:
git add .
git commit -m "Add profile form structure"Запустіть тести та статичні перевірки локально.
Відправте гілку:
git push -u origin feature/profile-formСтворіть pull request. У його описі вкажіть:
що змінено;
як перевірити зміни;
чи потрібен feature flag;
які відомі обмеження залишилися.
Якщо main змінилася, оновіть свою гілку:
git fetch origin
git rebase origin/main
git push --force-with-leaseПісля успішного review і CI інтегруйте pull request у main.
Коли функція готова, увімкніть її потрібним користувачам, а після стабілізації видаліть feature flag.
Незавершену функціональність не обов’язково тримати в окремій довгоживучій гілці. Її можна розділити на невеликі сумісні зміни:
додати структуру даних;
додати внутрішню логіку;
додати інтерфейс;
підключити нову поведінку за feature flag;
увімкнути функцію після завершення.
Кожна частина може потрапити в main, не змінюючи поведінку для звичайних користувачів.
Важливо, щоб проміжні зміни не ламали збірку та тести. Якщо код ще не може виконуватися самостійно, його потрібно захистити умовою, зробити сумісним зі старою поведінкою або розбити роботу інакше.
Якщо гілка існує тижнями, це вже суперечить головній ідеї підходу. Краще поділити функціональність на менші частини та інтегрувати їх поступово.
Великий pull request складно якісно перевірити. Розділяйте зміни за логічними кроками, але не створюйте коміти, які не збираються або ламають тести.
mainЯкщо перед злиттям давно не оновлювати гілку, конфлікти можуть з’явитися вже під час інтеграції. Регулярно отримуйте зміни з origin/main.
Trunk-Based Development спирається на швидкий feedback. Якщо команда ігнорує нестабільні тести, main поступово втрачає надійність.
Тимчасовий flag може перетворитися на постійне джерело складності. Записуйте, коли і за яких умов його потрібно видалити.
Коміт із новою функцією, форматуванням десятків файлів і оновленням залежностей важко перевіряти. Зберігайте зміни різних задач окремими.
Пряме додавання до main або злиття pull request-а з невдалим CI руйнує головну гарантію підходу — стабільність основної гілки.
Trunk-Based Development означає:
основна робота ведеться навколо стабільної гілки main;
робочі гілки живуть недовго;
зміни мають бути малими та інтегруватися часто;
main захищається code review і автоматичними перевірками;
незавершені функції ховаються за feature flags;
після стабілізації feature flags потрібно видаляти;
кожен коміт має залишати проєкт у працездатному стані.