HooneyLog
© 2026 Seunghoon Shin. All rights reserved.
모든 게시글
Backend
2026. 6. 17.•
0

Git flow를 버리고 trunk 기반 개발로: 배포가 느려서 시작한 전환기

Seunghoon Shin
작성자 Seunghoon Shin풀스택 개발자

TL;DR

  • Git flow의 develop/release/feature 계층이 소규모 팀에 과했고, 정기 배포 주기 탓에 리드타임이 길었습니다.
  • trunk 기반 개발로 바꾸면서 짧은 브랜치 + 하루 안에 머지되는 작은 PR, 그리고 직접 만든 가벼운 피처 플래그를 도입했습니다.
  • 배포는 체감상 확연히 빨라졌고 소규모 팀에 잘 맞았습니다. 다만 trunk가 모든 상황의 정답은 아닙니다.

Git flow가 우리에게는 무거웠습니다

결론부터 말하면, 우리 팀에 Git flow는 과한 전략이었습니다.

Git flow는 2010년 Vincent Driessen이 정리한 브랜치 모델입니다. main, develop, feature/*, release/*, hotfix/*로 역할을 나눠 릴리스 관리를 체계화합니다. 잘 만든 모델이고, 한때 사실상 표준처럼 쓰였습니다.

문제는 우리 상황이 그 모델이 가정한 상황과 달랐다는 점입니다. 흥미롭게도 Driessen 본인도 2020년에 글 상단에 노트를 덧붙였습니다. "웹 앱처럼 지속적으로 배포하고 롤백하지 않으며 여러 버전을 동시에 유지하지 않는 소프트웨어라면, git-flow 대신 훨씬 단순한 워크플로를 쓰라"는 취지였습니다. 우리가 만드는 게 정확히 그런 웹 앱이었습니다.

구체적으로 두 가지가 아팠습니다.

  • 배포가 느렸습니다. release 브랜치를 따고 정기 배포 주기에 맞춰 내보내다 보니, 다 만든 기능이 며칠씩 develop에 고여 있었습니다. 리드타임(코드 작성 → 실제 배포)이 길어졌습니다.
  • 브랜치 계층이 과했습니다. 소규모 팀인데도 develop과 release를 따로 관리하느라, 정작 코드보다 브랜치를 신경 쓰는 시간이 늘었습니다.

trunk 기반으로 바꾸며 새로 들인 것

trunk 기반 개발(trunk-based development)은 단순합니다. 모두가 하나의 trunk(main)를 공유하고, 짧게 산 브랜치를 자주 머지합니다. DORA 연구에서도 짧은 브랜치(보통 하루 미만)와 최소 하루 한 번 이상의 머지를 권장하고, 엘리트 퍼포머가 trunk 기반을 채택할 확률이 그렇지 않은 팀의 2.3배라고 보고합니다.

다만 브랜치 복잡도를 줄인 대가로, 다른 두 가지를 새로 들여야 했습니다.

1. 짧은 브랜치와 빠른 리뷰

가장 먼저 바꾼 건 PR 크기와 리뷰 속도였습니다. 브랜치를 길게 끌면 trunk 기반의 장점이 사라지고 오히려 머지 충돌만 커집니다. 그래서 규칙을 단순하게 잡았습니다.

  • PR은 하루 안에 머지되는 크기로 쪼갠다.
  • 리뷰는 쌓아두지 않고 그날 안에 돌린다.

작은 PR은 리뷰어의 부담도 작아서, 리뷰가 빨라지고 머지가 빨라지는 선순환이 생겼습니다.

2. 직접 만든 가벼운 피처 플래그

여기서 자연스럽게 질문이 생깁니다. "기능이 아직 안 끝났는데 main에 머지하면, 미완성 코드가 배포되는 것 아닌가?"

이걸 푸는 게 피처 플래그입니다. 미완성 기능을 플래그 뒤에 숨겨두고, 코드는 trunk에 들어가되 사용자에게는 노출되지 않게 합니다. LaunchDarkly·Unleash 같은 전문 도구도 있지만, 우리는 규모에 맞게 환경변수 기반으로 직접 만들었습니다.

// flags.ts — 환경변수로 켜고 끄는 가장 단순한 플래그 const FLAGS = { newCheckout: process.env.NEXT_PUBLIC_FLAG_NEW_CHECKOUT === 'true', } as const; export function isEnabled(flag: keyof typeof FLAGS): boolean { return FLAGS[flag]; }
// 사용하는 쪽 — 미완성 기능을 플래그 뒤에 숨긴다 import { isEnabled } from '@/lib/flags'; export function Checkout() { if (isEnabled('newCheckout')) { return <NewCheckout />; // 아직 개발 중, 플래그 꺼두면 안 보임 } return <LegacyCheckout />; }

별도 SaaS 없이도 "trunk에는 머지하되, 노출은 환경변수로 통제한다"는 핵심은 충분히 굴러갔습니다. 기능이 완성되면 플래그를 켜고, 안정화되면 분기 코드를 지우는 흐름입니다.

결과: 무엇이 달라졌나

전환 후 배포가 체감상 확연히 빨라졌습니다. 다 만든 기능이 release 브랜치를 기다리지 않고 그날그날 trunk로 들어가니, 리드타임이 짧아졌습니다. 브랜치를 신경 쓰는 정신적 비용도 줄었습니다. 소규모 팀에는 잘 맞는 선택이었고, 대체로 만족합니다.

물론 공짜는 아니었습니다. 플래그를 켜고 끄는 책임이 생기고, 다 쓴 플래그를 제때 지우지 않으면 코드에 분기가 쌓입니다. "도입보다 정리가 중요하다"는 걸 전환하고 나서 배웠습니다.

그래서, 언제 trunk가 맞을까

trunk 기반은 자주 배포하는 웹 앱, 그리고 브랜치 계층을 관리할 여력보다 빠른 흐름이 중요한 소규모 팀에 특히 잘 맞습니다. 반대로 긴 QA 사이클이나 여러 버전을 동시에 유지·지원해야 하는 제품이라면, Git flow의 release 계층이 여전히 의미가 있을 수 있습니다. Driessen이 2020년에 남긴 노트도 결국 "맥락에 맞게 고르라"는 이야기였습니다.

독자를 위한 TIP

  • 브랜치 전략부터 바꾸지 말고, PR을 먼저 작게 만드세요. 작은 PR과 빠른 리뷰가 trunk 기반의 전제 조건입니다.
  • 피처 플래그는 거창하게 시작할 필요 없습니다. 환경변수 분기로 시작해도 충분합니다. 대신 다 쓴 플래그를 지우는 규칙을 함께 정하세요.
  • 팀 규모와 배포 주기를 먼저 보세요. trunk는 만능이 아니라, 자주 배포하는 환경에서 빛납니다.

참고

  • Vincent Driessen, "A successful Git branching model" (2010, 2020 노트 포함) — https://nvie.com/posts/a-successful-git-branching-model/
  • DORA, Trunk-based development — https://dora.dev/capabilities/trunk-based-development/
← 이전 글NestJS vs Spring Boot: 스레드 모델과 I/O로 알아보는 아키텍처의 차이