왜 장수명 브랜치가 문제인가

Git Flow처럼 feature, develop, release 브랜치를 오래 유지하는 방식은 규모가 커질수록 병합 지옥을 만든다. 브랜치가 며칠~몇 주 살아 있으면 그동안 메인 라인은 계속 전진하고, 뒤늦게 병합할 때 충돌이 폭증한다. 더 큰 문제는 통합 지연이다. 코드가 실제로 합쳐지기 전까지는 "정말 동작하는가"를 아무도 검증할 수 없다. 병합이 미뤄질수록 위험은 눈덩이처럼 커진다.

Trunk-based 개발의 핵심

Trunk-based 개발(TBD)은 모든 개발자가 하나의 트렁크(main)를 향해 자주 커밋하는 전략이다. 브랜치를 만들더라도 수명을 1~2일 이내로 유지하고, 작은 단위로 자주 병합한다. 통합 비용을 매일 조금씩 지불함으로써, 한 번에 몰아서 겪을 대형 충돌을 원천 차단한다. 핵심 규칙은 세 가지다: 브랜치는 짧게, 커밋은 작게, main은 항상 배포 가능한 상태로.

브랜치 전략 비교

항목Git FlowTrunk-based
브랜치 수명수일~수주수시간~1일
병합 충돌크고 잦음작고 드묾
통합 주기릴리스 시점상시
CI 부하낮음높음(필수)
미완성 기능브랜치 격리피처 플래그

짧은 수명 브랜치 워크플로

브랜치는 하나의 작은 목표만 담고, 리뷰 후 곧바로 스쿼시 병합한다. 오래 붙잡고 있어야 할 만큼 큰 작업이면, 작업 자체를 쪼개는 것이 정답이다.

#!/bin/bash
# 짧은 수명 브랜치 생성 → 작업 → 병합
git switch main && git pull --rebase origin main
git switch -c feat/rate-limit

# 작은 단위로 커밋, 하루 안에 PR
git commit -am "add token bucket limiter"
git push -u origin feat/rate-limit

# 리뷰 통과 후 스쿼시 병합, 브랜치 즉시 삭제
gh pr merge --squash --delete-branch
git switch main && git pull --rebase origin main

미완성 기능은 피처 플래그로

TBD의 최대 난관은 "아직 덜 만든 기능을 어떻게 main에 넣느냐"다. 답은 브랜치 격리가 아니라 피처 플래그다. 코드는 매일 병합하되, 사용자에게 노출되는 시점만 런타임 스위치로 제어한다.

import os

FLAGS = {
    "new_checkout": os.getenv("FF_NEW_CHECKOUT", "off") == "on",
}

def checkout(cart, user):
    if FLAGS["new_checkout"] and user.in_rollout_bucket(10):
        return checkout_v2(cart)   # 10% 점진 노출
    return checkout_v1(cart)       # 기존 경로 유지

덜 완성된 checkout_v2도 플래그가 꺼진 채로 main에 안전하게 존재한다. 릴리스와 배포를 분리하는 것이 핵심이다.

CI가 게이트 역할을 해야 한다

자주 병합하려면 main 보호가 자동화되어야 한다. 모든 PR은 병합 전 테스트를 통과해야 하고, main은 항상 녹색이어야 한다.

name: ci
on:
  pull_request:
    branches: [main]
jobs:
  test:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: pip install -r requirements.txt
      - run: pytest -q --maxfail=1
      - run: ruff check .

여기에 브랜치 보호 규칙(필수 상태 체크, 최신 main 기준 rebase 강제)을 걸어 두면, 깨진 코드가 트렁크에 들어오는 것을 막을 수 있다.

실무 도입 시 주의점

  • 테스트 없는 TBD는 재앙이다. 빠른 병합은 빠른 검증을 전제로 한다. 커버리지와 CI 속도(10분 이내)를 먼저 확보하라.
  • 플래그는 부채다. 전량 노출이 끝난 플래그는 코드에서 제거하는 정리 주기를 두어야 한다. 방치하면 분기 지옥이 된다.
  • 큰 작업은 쪼개라. 하루 안에 병합 못 할 크기면 설계 문제다. 인터페이스부터 병합하고 구현을 뒤따르게 하는 방식이 유효하다.
  • 리뷰를 병목으로 두지 마라. 짧은 PR은 리뷰도 빨라야 한다. 수백 줄짜리 PR이 반복된다면 브랜치 수명 전략이 무너진 신호다.