메인 콘텐츠로 바로가기

Trunk-based Development 이해하기

개요

Trunk-based Development(TBD)는 모든 개발자가 하나의 메인 브랜치(trunk 또는 main)에서 직접 작업하고, 짧은 생명주기의 피처 브랜치만을 사용하는 소스 코드 관리 방식입니다. 개발자들은 매일 또는 그보다 자주 변경사항을 trunk에 통합하며, 이를 통해 머지 충돌을 최소화하고 지속적 통합(CI)과 지속적 배포(CD)를 실현합니다.

이 방식은 Google, Facebook과 같은 대규모 조직에서 검증되었으며, CI/CD를 위한 필수 전제조건으로 인정받고 있습니다. Trunk-based Development를 활용하면 팀의 배포 속도를 높이고, 코드 통합 비용을 줄이며, 더 빠른 피드백 사이클을 구축할 수 있습니다.


배경

왜 필요한가?

전통적인 브랜치 전략에서는 다음과 같은 문제가 발생합니다:

장기 피처 브랜치의 문제점:

  • 메인 브랜치와 피처 브랜치가 시간이 지날수록 크게 달라짐
  • 대규모 머지 시 복잡한 충돌 발생 (“Merge Hell”)
  • 통합 시점이 늦어지면서 버그 발견도 지연됨
  • 다른 팀원의 작업과 격리되어 협업이 어려워짐

예시: 전통적 워크플로의 문제

개발자 A: feature-payment 브랜치에서 2주간 작업 개발자 B: feature-auth 브랜치에서 3주간 작업 개발자 C: feature-ui 브랜치에서 1주간 작업 → 3개 브랜치가 각각 다른 시점의 main을 기반으로 함 → 동시에 merge 시도 시 대규모 충돌 발생 → 충돌 해결에 수일 소요, 버그 발생 위험 증가

이러한 문제는 특히 다음 상황에서 심각해집니다:

  • 팀 규모가 커질수록 충돌 가능성 증가
  • 릴리스 주기가 짧아질수록 통합 부담 가중
  • 여러 팀이 동시에 작업할수록 조정 비용 증가

등장 이전의 방식

GitFlow (2010년 등장)

GitFlow는 Vincent Driessen이 제안한 브랜치 전략으로, 다음과 같은 구조를 가집니다:

  • master (main): 프로덕션 릴리스용
  • develop: 개발 통합용
  • feature/*: 기능 개발용 (장기)
  • release/*: 릴리스 준비용
  • hotfix/*: 긴급 수정용
master ●─────●─────────●─────● │ │ │ │ release │ ●──●──●───● │ │ │ │ develop ●──●──●──●──●──●──●──●──● │ │ │ │ │ │ feature/A ●──●─────● │ │ │ │ │ │ │ feature/B ●───────────●──●─────●

GitFlow의 한계:

  • 복잡한 브랜치 구조로 학습 곡선이 가파름
  • 여러 장기 브랜치 유지에 따른 오버헤드
  • 빠른 피드백과 배포가 어려움
  • 웹 애플리케이션 시대에는 과도한 복잡성

전통적 Feature Branch 전략

각 기능마다 독립적인 브랜치를 생성하고, 완성 후 merge하는 방식:

# 기능 브랜치 생성 git checkout -b feature/user-dashboard # 2-4주간 작업... git add . git commit -m "Add user dashboard" # 완료 후 merge (이때 이미 main과 크게 달라짐) git checkout main git merge feature/user-dashboard # 충돌 발생 가능성 높음

2010년대 중반부터 CI/CD와 DevOps가 주류가 되면서, 이러한 전통적 방식은 빠른 배포 주기를 따라가기 어려워졌습니다. Trunk-based Development는 이러한 한계를 극복하기 위해 등장했습니다.


동작 원리

핵심 메커니즘

Trunk-based Development의 작동 방식은 다음 원칙을 따릅니다:

1. 단일 진실의 원천 (Single Source of Truth)

trunk(main) 브랜치가 유일한 장기 브랜치입니다. 모든 개발 활동이 이 브랜치를 중심으로 이루어집니다.

trunk ●──●──●──●──●──●──●──●──● │ │ │ │ │ │ │ │ └──┘ └──┘ └──┘ └─┘ 짧은 피처 브랜치들 (수시간~1일)

2. 빈번한 통합 (Frequent Integration)

개발자는 하루에 최소 한 번, 이상적으로는 여러 번 trunk에 통합합니다.

하루 동안의 작업 흐름: 09:00 - trunk에서 pull 10:00 - 작은 변경 commit & push 12:00 - 다른 기능 commit & push 15:00 - 버그 수정 commit & push 17:00 - 테스트 추가 commit & push

3. 짧은 생명주기의 브랜치

피처 브랜치는 최대 1-2일 이내에 trunk로 병합됩니다.

Before (장기 브랜치):

# ❌ 나쁜 예: 장기 브랜치 git checkout -b feature/complete-payment-system # 2주간 작업... # 수백 개의 파일 변경 # merge 시 큰 충돌 발생

After (단기 브랜치):

# ✅ 좋은 예: 작은 단위로 분할 git checkout -b feature/add-payment-button # 2-3시간 작업 git commit -m "Add payment button UI" git push && create PR git checkout -b feature/payment-api-integration # 4시간 작업 git commit -m "Integrate payment API" git push && create PR git checkout -b feature/payment-error-handling # 3시간 작업 git commit -m "Add payment error handling" git push && create PR

4. Feature Flags로 미완성 기능 관리

완성되지 않은 기능도 trunk에 통합하되, Feature Flag로 프로덕션에서 숨깁니다.

// Feature Flag를 사용한 점진적 개발 function PaymentPage() { const { isEnabled } = useFeatureFlag('new-payment-flow'); if (isEnabled) { // 🚧 개발 중인 새로운 결제 플로우 return <NewPaymentFlow />; } // ✅ 기존의 안정적인 결제 플로우 return <LegacyPaymentFlow />; }

이렇게 하면:

  • 새 기능을 trunk에 매일 commit 가능
  • 프로덕션에는 영향 없음 (Flag가 off 상태)
  • 내부 테스트 시에만 Flag를 on으로 활성화
  • 완성 후 Flag를 점진적으로 롤아웃

단계별 워크플로우

소규모 팀 (1-10명): Direct to Trunk

# 1. 최신 코드 가져오기 git checkout main git pull origin main # 2. 직접 main에서 작업 # (매우 작은 변경만) git add src/components/Button.tsx git commit -m "Fix: Button hover color" git push origin main # 3. CI가 자동으로 테스트 & 배포

적용 시나리오:

  • 스타트업의 MVP 개발
  • 5명 이하의 경험 많은 팀
  • 빠른 실험과 피벗이 필요한 경우

중대규모 팀 (10명 이상): Pull Request 워크플로우

# 1. 최신 trunk 가져오기 git checkout main git pull origin main # 2. 짧은 피처 브랜치 생성 git checkout -b fix/login-validation # 3. 작은 단위로 작업 (2-4시간) # src/auth/validation.ts 파일만 수정 git add src/auth/validation.ts git commit -m "Add email format validation" # 4. PR 생성 및 즉시 리뷰 요청 git push origin fix/login-validation # GitHub에서 PR 생성 # 5. CI 자동 실행 # - 유닛 테스트 # - 통합 테스트 # - 린트 & 포맷 체크 # - 빌드 검증 # 6. 리뷰 후 즉시 merge (1-2시간 내) # Auto-merge 또는 수동 merge # 7. 브랜치 삭제 git branch -d fix/login-validation

PR 크기 가이드라인:

  • 변경 라인 수: 50-200줄 권장
  • 리뷰 시간: 15-30분 이내
  • 수명: 당일 merge 원칙

시각적 비교

GitFlow vs Trunk-based Development

[GitFlow - 복잡함] master ●─────────────●─────────────● │ │ │ release │ ●────●───● │ │ │ │ develop ●────●────●────●────●───────● │ │ │ │ │ feature/A ●────●────● │ │ │ │ │ feature/B ●──────────────●────● [Trunk-based - 단순함] main ●─●─●─●─●─●─●─●─●─●─●─● │ │ │ │ │ │ │ │ │ │ │ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ (짧은 브랜치들, 당일 merge)

주요 특징

특징 1: Feature Flags와의 긴밀한 통합

Feature Flags(Feature Toggles)는 Trunk-based Development의 핵심 기술입니다.

Feature Flag의 역할:

  1. 배포와 릴리스의 분리
// 코드는 이미 프로덕션에 배포됨 // 하지만 사용자에게는 보이지 않음 function Dashboard() { const flags = useFeatureFlags(); return ( <div> <h1>Dashboard</h1> {/* 기존 기능 */} <UserStats /> {/* 새 기능 - Flag로 제어 */} {flags.aiRecommendations && ( <AIRecommendations /> )} </div> ); }
  1. 점진적 롤아웃
// 설정 파일 또는 Feature Flag 서비스 { "aiRecommendations": { "enabled": true, "rollout": { "percentage": 10, // 10% 사용자에게만 활성화 "userGroups": ["beta-testers", "internal"] } } }
  1. 긴급 롤백
// 문제 발생 시 즉시 Flag를 끔 // 코드 재배포 불필요! await featureFlagService.disable('aiRecommendations');

실제 구현 예시: React + LaunchDarkly

// feature-flags.ts import { useFlags } from 'launchdarkly-react-client-sdk'; export function useNewCheckoutFlow() { const flags = useFlags(); return flags.newCheckoutFlow ?? false; } // CheckoutPage.tsx function CheckoutPage() { const isNewFlowEnabled = useNewCheckoutFlow(); if (isNewFlowEnabled) { return <NewCheckoutFlow />; } return <LegacyCheckoutFlow />; } // 테스트 코드 describe('CheckoutPage', () => { it('shows new flow when flag is enabled', () => { const { render } = setupWithFlags({ newCheckoutFlow: true }); expect(screen.getByText('New Checkout')).toBeInTheDocument(); }); it('shows legacy flow when flag is disabled', () => { const { render } = setupWithFlags({ newCheckoutFlow: false }); expect(screen.getByText('Legacy Checkout')).toBeInTheDocument(); }); });

Feature Flag 관리 모범 사례:

// ✅ 좋은 예: 명확한 네이밍과 만료 날짜 const FLAGS = { NEW_DASHBOARD: { key: 'new-dashboard', description: '새로운 대시보드 UI', createdAt: '2025-01-01', removeAfter: '2025-03-01', // 2개월 후 제거 예정 owner: 'frontend-team' } }; // ❌ 나쁜 예: 모호한 이름, 관리 정보 없음 const FLAGS = { FLAG_1: 'f1', NEW_FEATURE: 'nf' };

Flag 정리 프로세스:

  1. Flag 생성 시 제거 날짜 설정
  2. 월 1회 Flag 정리 회의
  3. 완전히 롤아웃된 기능의 Flag 제거
  4. 사용하지 않는 Flag 식별 및 제거
# Flag 정리 예시 # 1. 100% 롤아웃 완료 → Flag 제거 - if (flags.newDashboard) { - return <NewDashboard />; - } - return <OldDashboard />; + return <NewDashboard />; # 2. 더 이상 사용하지 않는 Flag → 코드 및 설정 제거

특징 2: CI/CD의 필수 전제조건

Trunk-based Development는 CI/CD와 불가분의 관계입니다.

자동화된 테스트 파이프라인:

# .github/workflows/ci.yml name: Continuous Integration on: push: branches: [main] pull_request: branches: [main] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 # 1. 의존성 설치 - name: Install dependencies run: npm ci # 2. 린트 & 타입 체크 (빠른 피드백) - name: Lint run: npm run lint - name: Type check run: npm run type-check # 3. 유닛 테스트 (빠름, 5-10분) - name: Unit tests run: npm run test:unit # 4. 통합 테스트 (중간, 10-20분) - name: Integration tests run: npm run test:integration # 5. E2E 테스트 (느림, 20-40분) - name: E2E tests run: npm run test:e2e # 6. 빌드 검증 - name: Build run: npm run build # 7. 모든 테스트 통과 시 자동 배포 - name: Deploy to staging if: github.ref == 'refs/heads/main' run: npm run deploy:staging

테스트 전략:

[피라미드 구조] /\ E2E Tests (10%) / \ - 주요 사용자 시나리오 / \ - 느리지만 실제 환경 검증 /------\ / \ Integration Tests (30%) / \ - API 통합 / \- 데이터베이스 연동 /--------------\ / \ Unit Tests (60%) / \- 빠른 피드백 /--------------------\- 높은 커버리지

코드 예시: 테스트 작성

// ✅ 좋은 예: 빠른 유닛 테스트 describe('calculateDiscount', () => { it('applies 10% discount for orders over $100', () => { const result = calculateDiscount({ total: 150 }); expect(result).toBe(135); }); it('applies no discount for orders under $100', () => { const result = calculateDiscount({ total: 50 }); expect(result).toBe(50); }); }); // 통합 테스트 describe('PaymentAPI', () => { it('processes payment successfully', async () => { const payment = await paymentAPI.process({ amount: 100, currency: 'USD' }); expect(payment.status).toBe('completed'); }); }); // E2E 테스트 describe('Checkout Flow', () => { it('completes full checkout process', async () => { await page.goto('/products/1'); await page.click('button:has-text("Add to Cart")'); await page.click('a:has-text("Checkout")'); await page.fill('[name="email"]', 'test@example.com'); await page.click('button:has-text("Pay")'); await expect(page.locator('.success-message')).toBeVisible(); }); });

특징 3: 작은 배치 크기 (Small Batch Size)

배치 크기별 위험도:

[대형 배치 - 위험함] ┌────────────────────────────────────┐ │ 2주간 작업한 대형 PR │ │ - 50개 파일 변경 │ │ - 2,000줄 추가/수정 │ │ - 리뷰 시간: 4-6시간 │ │ - 버그 위험: 높음 │ │ - 롤백 시 큰 영향 │ └────────────────────────────────────┘ [소형 배치 - 안전함] ┌──────────┐ ┌──────────┐ ┌──────────┐ │ PR #1 │ │ PR #2 │ │ PR #3 │ │ 3개 파일 │ │ 2개 파일 │ │ 4개 파일 │ │ 80줄 │ │ 50줄 │ │ 120줄 │ │ 리뷰: 15분│ │ 리뷰: 10분│ │ 리뷰: 20분│ └──────────┘ └──────────┘ └──────────┘

실제 작업 분할 예시:

[❌ 잘못된 방식] feature/complete-user-management - 사용자 CRUD API - 사용자 목록 UI - 사용자 상세 페이지 - 권한 관리 시스템 - 감사 로그 총 작업 시간: 2주 [✅ 올바른 방식] 1. feature/user-api-create (4시간) - POST /api/users API 추가 - 단위 테스트 작성 2. feature/user-list-ui (3시간) - 사용자 목록 컴포넌트 - Feature Flag로 숨김 3. feature/user-detail-page (4시간) - 사용자 상세 페이지 - 기존 목록과 연결 4. feature/user-permissions (6시간) - 권한 체크 로직 - 미들웨어 추가 5. feature/audit-logging (3시간) - 감사 로그 기록 - 로그 조회 API

실제 사용 사례

사례 1: Google의 Monorepo

규모:

  • 35,000명 이상의 개발자
  • 단일 monorepo
  • 매일 수만 건의 commit

특징:

하나의 거대한 trunk ├── google3/ │ ├── ads/ │ ├── search/ │ ├── maps/ │ ├── youtube/ │ └── cloud/ └── 모든 프로젝트가 동일한 trunk에서 작업

작동 방식:

  • 모든 개발자가 main에 직접 commit
  • 자동화된 테스트 시스템 (Continuous Build)
  • Presubmit 체크로 코드 품질 보장
  • 문제 발생 시 자동 롤백

사례 2: Facebook의 빠른 배포

배포 주기:

  • 하루에 여러 번 프로덕션 배포
  • “Move Fast” 문화 반영

기술 스택:

// Feature Flag 시스템: Gatekeeper function NewsFeed() { const showNewAlgorithm = useGatekeeper('news_feed_v2'); if (showNewAlgorithm) { return <NewsFeedV2 />; } return <NewsFeedV1 />; } // 점진적 롤아웃 // 1% → 10% → 50% → 100%

사례 3: Netflix의 Chaos Engineering과 TBD

도전 과제:

  • 마이크로서비스 아키텍처 (500+ 서비스)
  • 높은 안정성 요구사항

해결 방법:

# Spinnaker 배포 파이프라인 stages: - name: Canary Deploy (5%) duration: 1h metrics: - errorRate < 0.1% - latency < 100ms - name: Gradual Rollout (50%) duration: 2h - name: Full Deploy (100%) condition: all_metrics_pass

Feature Flag 활용:

// A/B 테스트 public Recommendation getRecommendation(User user) { if (featureFlag.isEnabled("new_recommendation_algo", user)) { return newAlgorithm.recommend(user); } return legacyAlgorithm.recommend(user); }

사례 4: 소규모 스타트업의 MVP 개발

시나리오:

  • 5명의 개발 팀
  • 빠른 피벗 필요
  • 제한된 리소스

구현:

# 매우 단순한 워크플로우 git pull origin main # 기능 개발 (2-3시간) git add . git commit -m "Add user profile page" git push origin main # CI가 자동으로 테스트 & 배포

장점:

  • 프로세스 오버헤드 최소화
  • 빠른 실험과 학습
  • 작은 팀에서 효율적

사례 5: 대규모 엔터프라이즈 전환 사례

Before (GitFlow):

Release Cycle: 분기별 (3개월) Branches: 50+ 장기 피처 브랜치 Integration: 릴리스 1개월 전 시작 Bugs: 통합 단계에서 대량 발견

After (Trunk-based):

Release Cycle: 주간 (1주) Branches: 10-15개 단기 브랜치 (동시) Integration: 매일 Bugs: 즉시 발견 및 수정

전환 과정:

  1. 팀 교육 (1주)
  2. CI/CD 파이프라인 구축 (2주)
  3. Feature Flag 시스템 도입 (1주)
  4. 점진적 전환 (2개월)

결과:

  • 배포 빈도: 분기 1회 → 주 1회 (12배 증가)
  • 리드 타임: 3개월 → 1주 (90% 감소)
  • 버그 발견 시간: 평균 2주 → 1일 (93% 감소)

장점과 한계

장점

✅ 머지 충돌 최소화

이유:

  • 작은 변경을 자주 통합하므로 코드 베이스가 크게 달라지지 않음
  • 충돌이 발생해도 범위가 작아 해결이 쉬움
[장기 브랜치] Main: A─────────────B │ │ Feature: A──●──●──●──●──C (큰 충돌 가능성) [Trunk-based] Main: A─●─●─●─●─●─●─B │ │ │ │ │ │ │ └─┘ └─┘ └─┘ └─┘ (작은 충돌만 발생)

✅ 빠른 피드백

[전통적 방식] 코드 작성 → 2주 대기 → 리뷰 → 1주 수정 → 통합 → 버그 발견 총 소요: 4주 [Trunk-based] 코드 작성 → 30분 대기 → 리뷰 → 1시간 수정 → 통합 → 즉시 피드백 총 소요: 2-3시간

✅ 지속적 통합 강제

// 매일 통합하므로 자연스럽게 작은 단위로 개발 // ❌ 나쁜 예 function implementPaymentSystem() { // 2주간 작업... // 1,000줄의 코드 } // ✅ 좋은 예 function addPaymentButton() { // 2시간 작업, 50줄 } function connectPaymentAPI() { // 3시간 작업, 80줄 } function handlePaymentErrors() { // 2시간 작업, 60줄 }

✅ 배포 빈도 증가

데이터:

  • DORA 메트릭스에 따르면, Elite performers는:
    • 하루에 여러 번 배포
    • Trunk-based Development 사용 비율: 85%
  • 배포 빈도가 높을수록:
    • 리드 타임 감소
    • 장애 복구 시간 감소
    • 변경 실패율 감소

✅ 팀 협업 향상

[전통적 방식] 개발자 A: feature/payment에서 작업 (2주) 개발자 B: feature/auth에서 작업 (3주) → 서로의 작업을 모름 → 통합 시점에 충돌 발견 [Trunk-based] 개발자 A: 매일 main에 commit 개발자 B: 매일 main을 pull하여 A의 변경사항 확인 → 지속적 의사소통 → 충돌을 미리 발견하고 조율

한계

⚠️ 높은 자동화 요구사항

필수 인프라:

# 최소 요구사항 CI/CD: - 자동 테스트: 유닛, 통합, E2E - 자동 배포: Staging, Production - 자동 롤백: 문제 감지 시 Monitoring: - 에러 추적 - 성능 모니터링 - 사용자 행동 분석 Feature Flags: - Flag 관리 시스템 - 점진적 롤아웃 - 긴급 차단 기능

문제:

  • 초기 구축 비용이 높음 (2-4주)
  • 유지보수 필요
  • 팀의 기술적 성숙도 필요

⚠️ 팀 규율 필수

요구사항:

  • 작은 단위로 작업하는 습관
  • 빈번한 commit과 push
  • 즉각적인 코드 리뷰
  • 테스트 작성 문화
[실패 사례] ❌ 개발자가 큰 변경을 한꺼번에 commit ❌ 리뷰가 지연되어 브랜치가 장기화 ❌ 테스트 없이 commit하여 빌드 실패 ❌ Feature Flag를 제거하지 않아 기술 부채 누적

⚠️ Feature Flag 관리 복잡성

문제점:

// ❌ Flag 지옥 (Feature Flag Hell) function Component() { const flags = useFeatureFlags(); if (flags.newUI && flags.experimentalFeature) { if (flags.betaMode || flags.premiumUser) { return <VersionA />; } return <VersionB />; } else if (flags.newUI) { return <VersionC />; } return <VersionD />; } // 테스트 조합이 기하급수적으로 증가 // 2^n개의 경우의 수

해결책:

  • Flag 수명 관리
  • 정기적인 Flag 정리
  • Flag별 책임자 지정
  • 최대 수명 설정 (예: 3개월)

⚠️ 적합하지 않은 경우

1. 여러 버전 동시 유지 필요

Linux Kernel: v6.1 LTS (2024년까지 지원) v6.6 LTS (2026년까지 지원) v6.7 (현재 개발) → 각 버전별로 독립적인 브랜치 필요 → Trunk-based는 부적합

2. 엄격한 규제 산업

의료 소프트웨어, 금융 시스템: - 모든 변경에 대한 승인 필요 - 변경 이력의 명확한 분리 - 감사 추적 (Audit Trail) → GitFlow가 더 적합할 수 있음

3. 팀의 기술 수준이 낮은 경우

주니어 개발자 위주의 팀: - 작은 단위로 나누기 어려움 - 테스트 작성 경험 부족 - CI/CD 이해도 낮음 → 단계적 전환 필요 (GitFlow → GitHub Flow → TBD)

트레이드오프

측면GitFlowTrunk-based
학습 곡선복잡함단순함
초기 설정낮음높음 (CI/CD 필수)
배포 빈도낮음 (월/분기)높음 (일/시간)
머지 충돌잦고 복잡함드물고 간단함
롤백어려움쉬움 (Flag 끄기)
적합한 팀주니어 위주시니어 위주
적합한 규모중소형모든 규모

선택 가이드:

Trunk-based를 선택하세요: ✅ CI/CD를 구축할 의지와 자원이 있음 ✅ 팀이 작은 단위로 작업할 수 있음 ✅ 빠른 배포가 중요함 ✅ 단일 프로덕션 버전 유지 GitFlow를 선택하세요: ✅ 여러 버전을 동시에 유지해야 함 ✅ 릴리스 일정이 미리 정해짐 (분기별 등) ✅ 엄격한 승인 프로세스가 필요함 ✅ 팀의 기술적 성숙도가 낮음

관련 개념

GitHub Flow

특징:

  • GitFlow보다 단순, TBD보다는 유연
  • main 브랜치는 항상 배포 가능
  • 피처 브랜치를 사용하지만 짧게 유지

워크플로우:

# 1. main에서 브랜치 생성 git checkout -b feature/add-user-search # 2. 작업 및 commit (며칠~1주) git commit -m "Add search functionality" # 3. PR 생성 및 리뷰 # 4. main에 merge 후 즉시 배포 git checkout main git merge feature/add-user-search # 자동 배포 # 5. 브랜치 삭제 git branch -d feature/add-user-search

vs Trunk-based:

GitHub Flow: - 피처 브랜치: 며칠~1주 - PR 리뷰 필수 - merge 후 배포 Trunk-based (소규모): - 피처 브랜치: 수시간~1일 - PR 옵션 (직접 commit도 가능) - 매일 여러 번 배포

GitLab Flow

특징:

  • 환경별 브랜치 추가 (production, staging 등)
  • GitHub Flow + 환경 관리
main ──────●──────●──────● │ │ │ staging ●──────●──────● │ │ production ●──────●

워크플로우:

# 1. feature 개발 git checkout -b feature/new-api git commit -m "Add new API endpoint" # 2. main으로 merge git checkout main git merge feature/new-api # 3. staging 배포 git checkout staging git merge main # 배포 to staging # 4. 검증 후 production 배포 git checkout production git merge staging # 배포 to production

GitFlow (상세 비교)

브랜치 구조:

master ●─────────●─────────● │ │ │ release │ ●────●─────────● │ │ develop ●────●────●────●────● │ │ │ │ feature/A ●────●────● │ │ │ feature/B ●──────────────●

vs Trunk-based 비교:

요소GitFlowTrunk-based
브랜치 수5종류 (main, develop, feature, release, hotfix)1종류 (main)
장기 브랜치2개 (main, develop)1개 (main)
통합 주기릴리스 시점 (분기별)매일
릴리스release 브랜치 생성main에서 직접
핫픽스hotfix 브랜치 생성main에서 수정 후 배포

전환 시나리오:

[Phase 1: GitFlow → GitHub Flow] - develop 브랜치 제거 - main만 사용 - 피처 브랜치 수명 단축 (2주 → 1주) [Phase 2: GitHub Flow → Trunk-based] - 피처 브랜치 더 짧게 (1주 → 1-2일) - Feature Flag 도입 - CI/CD 자동화 강화 [Phase 3: Pure Trunk-based] - 작은 팀은 직접 main에 commit - Feature Flag로 모든 미완성 기능 제어

더 알아보기

심화 학습

1. Branch by Abstraction

  • 큰 리팩토링을 작은 단위로 나누는 기법
  • Feature Flag와 함께 사용
// Step 1: 추상화 계층 추가 interface PaymentGateway { processPayment(amount: number): Promise<Result>; } // Step 2: 구현체 전환 (Feature Flag로 제어) const gateway: PaymentGateway = flags.newGateway ? new StripeGateway() : new LegacyGateway(); // Step 3: 점진적으로 새 구현으로 전환 // Step 4: 레거시 제거

2. Continuous Deployment

  • main에 merge되면 자동으로 프로덕션 배포
  • 신뢰할 수 있는 테스트 필수
# CD 파이프라인 예시 on: push: branches: [main] jobs: deploy: steps: - run: npm test - run: npm run build - run: deploy to production - run: smoke tests - if: failure() run: automatic rollback

3. 팀 토폴로지와 TBD

  • Stream-aligned teams
  • Platform teams
  • Complicated-subsystem teams

실습

튜토리얼: 실제로 TBD 적용하기

  1. 기초 실습 프로젝트 
  2. Feature Flag 실습 
  3. CI/CD 파이프라인 구축 

관련 자료

책:

  • “Continuous Delivery” by Jez Humble & David Farley
  • “Accelerate” by Nicole Forsgren, Jez Humble & Gene Kim
  • “The DevOps Handbook” by Gene Kim et al.

웹사이트:

도구:

  • Feature Flags: LaunchDarkly, Unleash, Flagsmith
  • CI/CD: GitHub Actions, GitLab CI, CircleCI
  • Monitoring: Datadog, New Relic, Sentry

결론

Trunk-based Development는 단순히 브랜치 전략이 아니라 팀의 문화와 프로세스를 변화시키는 접근 방식입니다. 빠른 피드백, 지속적 통합, 높은 배포 빈도를 실현할 수 있지만, 이를 위해서는 탄탄한 자동화 인프라와 팀의 높은 규율이 필요합니다.

핵심 요약:

  • 모든 개발자가 하나의 trunk(main) 브랜치에서 작업
  • 짧은 생명주기의 피처 브랜치 (최대 1-2일)
  • Feature Flag로 미완성 기능 제어
  • CI/CD의 필수 전제조건
  • 작은 배치 크기로 위험 감소

팀의 상황에 맞게 점진적으로 도입하고, 지속적으로 개선해나가는 것이 성공의 열쇠입니다.


문서 버전: 1.0 최종 수정일: 2025-12-22 작성자: Claude with Technical Writing Skill 참고 자료: trunkbaseddevelopment.com, Atlassian, LaunchDarkly, Google Engineering Practices

댓글

developjik
All content is licensed under CC BY-NC-SA 4.0 unless otherwise noted.