
Git Flow vs Trunk Based: 대기업과 스타트업의 차이
안전제일 Git Flow와 속도제일 Trunk Based. 우리 팀은 브랜치를 몇 개 만들어야 할까?

안전제일 Git Flow와 속도제일 Trunk Based. 우리 팀은 브랜치를 몇 개 만들어야 할까?
내 서버는 왜 걸핏하면 뻗을까? OS가 한정된 메모리를 쪼개 쓰는 처절한 사투. 단편화(Fragmentation)와의 전쟁.

미로를 탈출하는 두 가지 방법. 넓게 퍼져나갈 것인가(BFS), 한 우물만 팔 것인가(DFS). 최단 경로는 누가 찾을까?

이름부터 빠릅니다. 피벗(Pivot)을 기준으로 나누고 또 나누는 분할 정복 알고리즘. 왜 최악엔 느린데도 가장 많이 쓰일까요?

매번 3-Way Handshake 하느라 지쳤나요? 한 번 맺은 인연(TCP 연결)을 소중히 유지하는 법. HTTP 최적화의 기본.

첫 협업 프로젝트 첫날, 시니어가 물었습니다:
"우리 팀은 Git Flow 쓸 거야.
develop에서 브랜치 따서 작업해."
저: "Git Flow가 뭐예요?"
시니어: (한숨) "Git 안 써봤어?"
저: "썼는데요... 그냥 git add, git commit, git push만..."
그때 이해했다. Git을 "쓴다"와 "잘 쓴다"는 완전히 다른 세계라는 걸. 마치 자전거를 탈 줄 안다고 해서 도심 교통을 다 이해하는 게 아닌 것처럼, 저는 Git의 기본 명령어만 알고 있었을 뿐 팀 협업의 철학은 전혀 몰랐습니다.
다른 프로젝트에 참여했습니다. 스타트업이었죠.
CTO: "우리는 Trunk Based Development 해. main에 바로 푸시해."
저: "엥? 브랜치 안 따요? 위험하지 않아요?"
CTO: "테스트 자동화 되어있고, 하루에 100번 배포해. 브랜치 관리가 더 느려."
같은 Git인데 철학이 정반대. 첫 프로젝트에서는 브랜치를 5가지나 쓰더니, 두 번째 프로젝트는 브랜치가 하나뿐. 이게 다 같은 버전 관리 시스템을 쓰는 건데 접근법이 완전히 달랐습니다. 처음엔 혼란스러웠지만, 이게 제가 브랜치 전략을 깊이 공부하게 된 계기였습니다.
master, develop, feature, release, hotfix... 머리 아파main만 쓴다고? 충돌 안 나?main에 직접 푸시하면 production이 터지는 거 아냐?무엇보다 "우리 팀은 뭘 써야 하지?"라는 질문에 답을 찾을 수가 없었습니다. 구글 검색해도 "상황에 따라 다르다"는 애매한 답변만 잔뜩...
시니어의 비유가 모든 걸 명확하게 만들어줬습니다:
"규모와 위험도가 다르구나! 결국 이거였다."Git Flow = 보잉 747 (대형 여객기):
- 조종사 2명, 승무원 10명, 승객 400명
- 이륙 전 체크리스트 200개
- 연료 확인, 기체 점검, 관제탑 허가...
- 안전제일, 하지만 출발까지 2시간
- 하지만 한 번 이륙하면 400명을 안전하게 운송
Trunk Based = 전동 스쿠터:
- 혼자 타고 바로 출발
- 충전만 되어 있으면 1분 안에 도로로
- 빠름, 하지만 사고 나면 바로 다침
- 헬멧(테스트 자동화) 필수!
- 목적지 바꾸기도 쉽고, 실수해도 영향 범위가 작음
보잉 747은 느리지만 안전합니다. 400명의 생명을 책임지니까요. 반면 전동 스쿠터는 빠르지만 위험합니다. 하지만 혼자 타니까 실수해도 나만 다치죠. 이 비유가 와닿았다. Git 브랜치 전략은 기술 선택이 아니라 위험 관리 전략이었던 겁니다.
master (production)
↓
develop
↓
feature/login
feature/payment
↓
release/v1.0
↓
hotfix/critical-bug
master (or main): 실제 배포 버전
v1.0.0, v1.0.1)develop: 개발 메인 브랜치
feature/*: 기능 개발
develop에서 분기develop으로 mergefeature/user-login, feature/payment-systemrelease/*: 배포 준비
develop에서 분기master와 develop 양쪽에 mergehotfix/*: 긴급 버그 수정
master에서 분기master와 develop 양쪽에 merge제가 로그인 기능을 만든다면:
# 1. develop에서 feature 브랜치 생성
git checkout develop
git pull origin develop
git checkout -b feature/login
# 2. 작업 (1주일)
git commit -m "Add login UI"
git commit -m "Add authentication logic"
git commit -m "Add error handling"
git commit -m "Add unit tests"
# 3. develop에 merge
git checkout develop
git merge feature/login
git push origin develop
git branch -d feature/login
# 4. 배포 준비 (QA 단계)
git checkout -b release/v1.0 develop
# QA가 버그 찾으면 여기서 수정
git commit -m "Fix login button color"
git commit -m "Fix validation message"
# 5. 배포
git checkout master
git merge release/v1.0
git tag v1.0.0
git push origin master --tags
# 6. develop에도 반영 (QA에서 수정한 버그픽스 포함)
git checkout develop
git merge release/v1.0
git push origin develop
소요 시간: 2주~1개월
이 과정을 처음 봤을 때 "너무 복잡한 거 아냐?"라고 생각했습니다. 하지만 금융권 프로젝트에 투입되고 나서야 이해했습니다. 한 번의 실수가 수천 명의 금전적 피해로 이어질 수 있는 환경에서는 이 정도 검증 단계가 필요하더군요.
안정성: 여러 단계 검증
동시 개발: 10명이 동시에 다른 기능 개발 가능
버전 관리: v1.0, v2.0 명확히 구분
Hotfix 용이: production 버그 즉시 수정
복잡함: 신입이 이해하기 어려움
느림: 기능 하나에 2주 이상 소요
Merge Hell: 브랜치 많으면 충돌 지옥
과도한 절차: 작은 버그도 2주 기다림
제가 정리해본다면, Git Flow는 "절대 실수하면 안 되는 환경"을 위한 전략입니다.
main (= trunk)
├─ short-lived branch (1일 이하)
├─ short-lived branch
└─ short-lived branch
핵심: 브랜치 최소화, 빠른 merge
# 1. main에서 직접 작업 또는 짧은 브랜치
git checkout main
git pull
git checkout -b fix-button # 옵션
# 2. 작업 (몇 시간)
git commit -m "Fix button color"
git push origin fix-button
# 3. main에 즉시 merge (또는 PR 승인 후 즉시)
git checkout main
git merge fix-button
git push
git branch -d fix-button
# 또는 main에 직접 push (더 과감한 팀)
git checkout main
git add .
git commit -m "Fix button"
git push
소요 시간: 몇 시간~1일
처음 이 방식을 봤을 때 "위험하지 않나?"라고 생각했습니다. main에 직접 푸시? production이 터지는 거 아냐? 하지만 CTO가 보여준 대시보드를 보고 입이 떡 벌어졌죠. 하루에 정말 100번 배포하고 있었습니다. 그것도 에러율 0.1% 이하로.
작은 커밋: 큰 기능도 매일 작은 조각으로 쪼개서 merge
Feature Flag: 미완성 기능도 merge (단, 숨김 처리)
빠른 피드백: CI/CD가 자동으로 테스트
// 미완성 기능도 main에 merge 가능
const PaymentPage = () => {
const { featureFlags } = useFeatureFlags();
if (featureFlags.newPayment) {
return <NewPaymentUI />; // 개발 중 (내부 테스터만 봄)
} else {
return <OldPaymentUI />; // 현재 사용 (일반 사용자가 봄)
}
};
// 환경변수로 제어
// .env.production
FEATURE_NEW_PAYMENT=false // 일반 사용자는 false
// .env.development
FEATURE_NEW_PAYMENT=true // 개발자는 true
배포 시 featureFlags.newPayment = false로 숨김. 완성되면 true로 바꾸기만 하면 됩니다. 심지어 점진적 롤아웃도 가능합니다:
// 10%의 사용자에게만 새 기능 보여주기
if (featureFlags.newPayment && user.id % 10 === 0) {
return <NewPaymentUI />;
}
이 패턴을 받아들였을 때, 세상이 달라 보였습니다. "기능 완성 = 코드 merge"라는 고정관념이 깨지더군요.
속도: 하루에 100번 배포 가능
단순함: 브랜치 하나뿐
충돌 최소화: 자주 merge → 큰 충돌 없음
진짜 CI: Continuous Integration의 본래 의미
위험함: 버그가 바로 production
테스트 필수: 자동화 없으면 폭망
문화 필요: 팀 전체가 동의해야 함
실력 필요: 큰 기능을 작게 쪼개는 능력
제가 다녔던 스타트업에서 실제로 전환을 경험했습니다.
기능 개발: 1주
Code Review: 2일
QA: 1주
배포 대기: 1주 (다음 release 주기까지)
총 3주 후 사용자 피드백
문제점:
실제로 있었던 일입니다. 제가 만든 "소셜 로그인" 기능을 3주 동안 개발했는데, 막상 사용자 테스트를 해보니 "그냥 이메일 로그인이 더 편해요"라는 피드백. 3주가 증발했습니다.
Day 1: 기본 UI merge (Feature Flag로 숨김 처리)
Day 2: 로직 추가 merge (내부 테스터에게만 공개)
Day 3: 테스트 통과, 10% 사용자에게 공개
Day 4: 사용자 피드백 수집 (실시간 모니터링)
Day 5: 피드백 반영, 100% 공개 또는 롤백
효과:
같은 "소셜 로그인" 기능을 Trunk Based로 다시 만들었을 때, Day 3에 사용자 피드백을 받았고 "버튼 위치가 이상해요"라는 걸 바로 파악해서 Day 4에 수정했습니다. Git Flow였으면 3주 후에야 알았을 것입니다.
# .github/workflows/ci.yml
name: CI/CD Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install dependencies
run: npm install
- name: Run linter
run: npm run lint
- name: Run unit tests
run: npm test
- name: Run integration tests
run: npm run test:integration
- name: Check code coverage
run: npm run coverage
# 테스트 실패 시 merge 불가
- name: Block if failed
if: failure()
run: |
echo "Tests failed! Cannot merge."
exit 1
deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Deploy to production
run: |
echo "Deploying to production..."
# AWS, Vercel, Netlify 등 배포 스크립트
규칙: 테스트 실패 시 merge 금지! 예외 없음!
한 번 테스트를 건너뛰고 main에 push한 적이 있습니다:
git push --no-verify # ❌ 위험! pre-commit hook 무시
이유: "급해서... 테스트는 로컬에서 돌렸는데 다 통과했어..."
결과:
진짜 원인: 로컬에서는 통과했지만 production 환경 변수가 달랐음. CI/CD에서는 실패했을 텐데 건너뛰었던 거죠.
교훈:
--no-verify는 팀원들에 대한 배신이 사건 이후로 팀에서 규칙을 만들었습니다: "--no-verify 쓰면 커피 한 턴". 농담처럼 들리지만 진짜로 시행했고, 덕분에 다시는 이런 사고가 없었습니다.
| 팀 규모 | 추천 전략 | 이유 |
|---|---|---|
| 1~3명 | Trunk Based | 브랜치 관리 오버헤드 불필요. 서로 뭐 하는지 다 알고 있음 |
| 4~10명 | Trunk Based + PR | 코드 리뷰는 하되 빠르게 merge (1일 이내) |
| 10~30명 | GitHub Flow | main + feature 브랜치, 단순화된 Git Flow |
| 30명 이상 | Git Flow | 여러 팀 동시 작업, 버전 관리 필수 |
| 금융/의료 | Git Flow | 안전 최우선. 한 번 실수하면 법적 문제 |
제가 요즘 쓰는 방식입니다:
main (항상 배포 가능 상태)
├─ feature/login (PR 1~3일)
├─ feature/payment (PR 1~3일)
└─ hotfix/bug (Direct merge 또는 즉시 PR)
규칙:
main = 항상 배포 가능: 언제든 배포 버튼 누를 수 있는 상태실제 워크플로우:
# 1. 기능 브랜치 생성 (월요일 오전)
git checkout -b feature/dark-mode
# 2. 작업하면서 계속 커밋
git commit -m "Add dark mode toggle button"
git commit -m "Add dark mode styles"
# 3. PR 생성 (화요일 오전)
git push origin feature/dark-mode
# GitHub에서 PR 생성
# 4. 코드 리뷰 (화요일 오후)
# 동료: "LGTM! 👍"
# 5. Merge (화요일 오후)
# Squash and merge 또는 Merge commit
# 6. 자동 배포 (화요일 저녁)
# CI/CD가 자동으로 production에 배포
장점:
CEO: "경쟁사가 어제 출시했는데 우리는?"
개발자: "QA 중입니다. 다음 주 release 브랜치에서..."
CEO: "다음 주? 지금 당장 필요한데?"
개발자: "절차가..."
CEO: "😡"
실제로 제가 첫 스타트업에서 겪은 일입니다. 경쟁사가 "라이브 채팅" 기능을 출시했는데, 우리는 이미 만들어놨지만 release 주기 때문에 2주를 기다려야 했죠. 결국 고객 10명을 경쟁사에 뺏겼습니다.
교훈: 스타트업에 Git Flow는 과함. 속도가 생명인 환경에서는 Trunk Based 또는 GitHub Flow.
# 금요일 저녁 6시
git add .
git commit -m "Quick fix"
git push # 테스트 없이 main에 push
# 금요일 저녁 6시 5분
"사이트 안 돼요!"
"결제가 안 되는데요?"
"로그인 버튼이 사라졌어요!"
제 동료가 겪은 일입니다. 금요일 저녁에 "작은 수정"이라고 테스트 없이 푸시했다가... 주말 내내 출근해서 롤백하고 수정했죠.
교훈: 자동화 없으면 Git Flow가 안전. "빠른 배포"와 "무책임한 배포"는 다름.
Week 1: feature/big-refactor 시작
Week 2: 계속 작업 (main은 30개 커밋 앞서감)
Week 3: 드디어 완성!
Week 3: Merge 시도 → 충돌 200개
Week 3: 충돌 해결하다가 2일 소요
Week 3: 다시 테스트 → 실패 50개
Week 4: 포기하고 다시 작성
제가 직접 겪은 지옥입니다. "큰 리팩토링"을 한 번에 하려다가 3주 동안 브랜치를 따로 관리했고, merge 할 때 폭망했습니다.
교훈:
올바른 방법:
Day 1: 폴더 구조 변경 (merge)
Day 2: import 경로 수정 (merge)
Day 3: 함수명 변경 (merge)
Day 4: 로직 최적화 (merge)
✅ 배포 주기가 길다 (월 1회 이상 간격) ✅ 여러 버전 동시 유지 (v1 지원 + v2 개발) ✅ 대규모 팀 (30명 이상) ✅ 안전이 최우선 (금융, 의료, 인프라) ✅ 패키지 소프트웨어 (고객이 직접 설치) ✅ 레거시 시스템 (변경 영향도 큼)
✅ 하루에 여러 번 배포 ✅ 빠른 실험, 빠른 수정 (A/B 테스트 많이 함) ✅ CI/CD 자동화 완벽 (테스트 커버리지 80% 이상) ✅ 작은 팀 (10명 이하) ✅ SaaS 서비스 (언제든 업데이트 가능) ✅ 팀 문화가 성숙함 (상호 신뢰, 책임감)
✅ 위 둘의 중간 (대부분의 팀)
✅ 코드 리뷰 문화 (PR 필수)
✅ 하루일주일 단위 배포
✅ 스타트업중견 기업 (10~30명)
✅ 속도와 안정성 둘 다 중요
✅ 현실적 선택 (완벽한 자동화 어려움)
Git Flow vs Trunk Based는 기술의 차이가 아닌 철학의 차이입니다.
회사 초기 (Git Flow): "왜 이렇게 느려? 답답해..." 지금 (GitHub Flow): "딱 적당한 속도네."
정답은 없습니다. 우리 팀에 맞는 걸 선택하면 됩니다.제가 여러 회사를 거치며 배운 교훈:
다만 한 가지는 확실합니다:
"브랜치 전략 없이 Git 쓰는 건 운전면허 없이 운전하는 것과 같다."
첫 프로젝트에서 "Git Flow가 뭐예요?"라고 물었던 제가 부끄럽지만, 그 경험 덕분에 지금은 팀 상황에 맞는 브랜치 전략을 설계할 수 있게 되었습니다. 여러분도 우리 팀에 맞는 전략을 찾아가시길 바랍니다.