Rain Lag

한 가지 질문 브랜치 전략: 기능을 작고 배포 가능하게 유지하는 작은 Git 습관

“브랜치마다 딱 한 가지 질문만 다룬다”는 간단한 규칙이 어떻게 Git 워크플로를 작고, 안전하며, 언제든 배포 가능한 변경들의 흐름으로 바꿔줄 수 있는지 이야기합니다.

한 가지 질문 브랜치 전략: 기능을 작고 배포 가능하게 유지하는 작은 Git 습관

소프트웨어 팀이 실패하는 이유는 대부분 코드를 써서가 아닙니다. 코드를 안전하게 배포하지 못해서입니다.

브랜치는 어느새 범위가 비대해지고, PR은 장편 소설이 되며, 머지는 악몽이 됩니다. 모두가 “다음엔 더 작게 나눠서 할게요”라고 말하지만, 실제로는 잘 지켜지지 않습니다.

이걸 바꿀 수 있는 의외로 작은 습관이 있습니다. 바로 한 가지 질문 브랜치(one-question branch) 전략입니다.

이제는 “기능(feature)”이나 “티켓(ticket)” 기준이 아니라, 질문(question) 기준으로 생각합니다.

각 브랜치는 정확히 한 가지 질문에만 답한다.

이 단 하나의 제약만 지켜도, 변경 사항은 더 작아지고, 리뷰는 빨라지며, 배포는 더 안전해지고, Git 히스토리는 정말로 ‘이야기’를 들려주게 됩니다.

이 글에서는 이 한 가지 질문 규칙을 어떻게 적용하는지, 브랜치를 짧고 작게 유지하는 법, 기능 플래그(feature flag)를 활용하는 방법, 그리고 디버깅과 협업을 쉽게 만드는 깔끔한 Git 히스토리를 유지하는 방법을 살펴보겠습니다.


한 가지 질문 브랜치 전략이란?

대부분의 브랜치는 이렇게 시작합니다.

  • feature/user-profile-page
  • bugfix/payment-timeout

이것도 나쁘진 않지만, 너무 포괄적입니다. 실제로 실행 가능한 작업 단위는 더 작고, 더 구체적인 경우가 많습니다. 한 가지 질문 전략은 이 “구체성”을 브랜치 이름에 드러내도록 강제합니다.

좋은 “한 가지 질문” 브랜치 예시는 이런 식입니다.

  • feat/can-users-edit-avatar질문: 사용자가 프로필 아바타를 수정할 수 있는가?
  • bug/fix-payment-timeout-on-slow-network질문: 느린 네트워크에서도 결제가 정상 동작하는가?
  • chore/add-logging-to-order-processing질문: 주문 처리 실패를 디버깅할 만큼 로그가 충분한가?

각 브랜치는 하나의 명확한 질문이나 사용자 니즈에만 초점을 맞춥니다. 작업을 하다가 다른 질문에 답하고 있다는 느낌이 들면, 그건 다음을 해야 한다는 신호입니다.

  • 작업을 다른 브랜치로 분리하거나,
  • 지금 질문에 대한 답을 마무리하고 머지한 뒤, 새로 시작하거나.

이 제약은 작지만, 결과는 크게 바뀝니다.

  • 브랜치는 자연스럽게 작아지고,
  • 작업은 항상 배포 가능한 상태에 더 가깝게 유지되며,
  • 리뷰는 이해하기 훨씬 쉬워집니다.

항상 깨끗하고 안정적인 main에서 시작하기

한 가지 질문 전략은 이 기본 규칙을 잘 지킬 때 가장 효과적입니다.

main에서 직접 개발하지 말고, 항상 브랜치를 따로 만들어 작업하라.

이게 중요한 이유는 다음과 같습니다.

  • main은 항상 안정적이고 배포 가능한 상태로 유지됩니다.
  • 실험적이거나 위험한 변경은 별도의 feature 브랜치에서만 이뤄집니다.
  • 무엇이 프로덕션 준비가 되었고, 무엇이 진행 중인지가 명확해집니다.

일반적인 흐름은 이렇게 됩니다.

git checkout main git pull origin main # 브랜치 이름은 이 브랜치가 답하려는 질문을 기준으로 짓는다 git checkout -b feat/can-users-edit-avatar

이 분리는 팀을 보호합니다. 누군가가 반쯤 구현된 아이디어를 실수로 배포하게 되는 일을 줄이고, 롤백도 단순해집니다.


브랜치를 짧게 유지하고, 자주 동기화하기

오래 살아남는(long-lived) 브랜치가 바로 충돌과 머지 지옥의 시작입니다.

대신, 짧게 살아가는(short-lived) feature 브랜치를 목표로 하세요.

  • 몇 시간에서 길어야 며칠 정도, 몇 주 단위가 아니라
  • 하나의 질문에 답하기에 충분한, 작고 수직으로 잘린(vertical slice) 작업 단위

괴로운 드리프트를 피하려면, main과 자주 동기화해야 합니다.

git checkout main git pull origin main git checkout feat/can-users-edit-avatar git rebase main # 팀 문화에 따라 merge를 사용해도 무방

이렇게 자주 동기화하면:

  • 다른 사람의 변경 사항으로 브랜치를 최신 상태로 유지할 수 있고,
  • 머지 충돌의 크기와 복잡도가 줄어들며,
  • 항상 배포에 아주 가까운 상태로 작업을 유지할 수 있습니다.

짧게 유지되고 자주 동기화되는 브랜치는 괴물로 변할 틈이 없습니다.


작고, 배포 가능한 Pull Request 만들기

한 가지 질문 브랜치 전략의 핵심 목표는 **작고, 배포 가능한 Pull Request(PR)**를 만드는 것입니다.

배포 가능한 PR은 다음을 만족해야 합니다.

  • 브랜치 이름에 담긴 질문에 답을 합니다.
  • 한 번에 리뷰할 수 있을 정도여야 합니다. (이왕이면 실질적인 변경 기준으로 400라인 내외)
  • 명확한 성공 기준이 있어야 합니다. (예: “사용자가 아바타를 업로드하고 크롭할 수 있다”)

작은 PR의 장점은 명확합니다.

  • 리뷰가 빠르다: 인지 부하가 적고, 실수를 찾기 쉬움
  • 품질이 좋아진다: 리뷰어가 의도를 파악하기 쉽고, 설계 문제를 발견하기 쉬움
  • 배포가 안전하다: 롤백 시 되돌리는 범위가 작고, 변화가 잘 정의되어 있음

만약 PR 설명에 “그리고(and)”라는 단어를 여러 번 쓸 수밖에 없다면:

“아바타 업로드를 구현하고 그리고 프로필 레이아웃을 수정하고 그리고 인증 로직을 리팩터링합니다”

아마도 이미 한 가지 이상의 질문을 다루고 있다는 의미일 가능성이 큽니다.


기능 플래그(Feature Flag)로 일찍, 자주 머지하기

어떤 질문은 하루 안에 답을 내기 어렵기도 하고, 백엔드는 준비됐는데 UI는 아직 준비가 안 됐을 수도 있습니다.

그래도 브랜치는 작게 유지하고, 자주 머지하는 것이 좋습니다. 이때 **기능 플래그(feature flag, toggle)**가 빛을 발합니다.

기능 플래그는:

  • 완성되지 않은 작업도 main에 머지할 수 있게 해 주고,
  • 위험한 동작은 준비될 때까지 프로덕션에서 비활성화해 둘 수 있으며,
  • 사용자에게 피해를 주지 않으면서 trunk-based 개발이나 trunk 친화적인 개발을 가능하게 합니다.

예시 패턴:

// pseudo-code if (isFeatureEnabled('user-avatar-edit')) { showAvatarEditUI(); }

기능 플래그를 사용하면 다음과 같이 나눌 수 있습니다.

  • 백엔드를 하나의 브랜치에서 구현하고
  • UI를 다른 브랜치에서 추가하며
  • 둘을 연결하는 작업을 또 다른 브랜치에서 수행합니다.

각 브랜치는 여전히 한 가지 질문에만 답하지만, 모두 기능 플래그 뒤에 머지됩니다. 모든 준비가 끝났을 때, 플래그를 켜면 됩니다.

이렇게 하면 브랜치는 짧게 유지되고, main 브랜치는 계속해서 배포 가능한 상태로 유지됩니다.


커밋은 자주 하되, 각 커밋이 이야기를 하게 만들기

브랜치는 고수준의 이야기를 들려줍니다. (“사용자가 아바타를 수정할 수 있는가?”)

커밋은 그 이야기를 **챕터(chapter)**별로 쪼개 들려줍니다.

두 가지 가이드를 기억하세요.

  1. 커밋은 자주 하세요. 완벽해질 때까지 기다리지 마세요.
  2. 명확하고 묘사적인 커밋 메시지를 쓰되, 단순히 ‘무엇을 했는지’보다 **왜 했는지(why)**에 초점을 맞추세요.

나쁜 커밋 메시지 예시:

  • fix stuff
  • wip
  • changes

더 나은 커밋 메시지 예시:

  • 사용자 아바타 이미지 경로를 저장할 Avatar 필드 추가
  • 아바타 저장 전 이미지 크기와 타입 검증 추가
  • 프로필 폼에 아바타 미리보기와 에러 메시지 표시

6개월 후 누군가 버그를 디버깅할 때, 커밋 메시지는 다음 질문에 답할 수 있어야 합니다.

  • 왜 이 변경이 필요했는가?
  • 이 커밋은 어떤 문제를 해결하려 했는가?

한 가지 질문 브랜치는 큰 맥락을 제공하고, 좋은 커밋은 디테일을 제공합니다.


읽기 쉬운 Git 히스토리 유지하기

깔끔한 히스토리는 ‘예쁘게 보이기’ 위한 게 아니라, 디버깅과 협업을 쉽게 하기 위한 것입니다.

일관된 브랜치 전략과 머지 방식은 다음을 도와줍니다.

  • 언제, 왜 동작이 바뀌었는지 추적하기
  • 회귀(regression)를 효과적으로 git bisect로 찾아내기
  • 새 팀원이 더 빨리 온보딩되도록 돕기

실천 가능한 습관 몇 가지를 정리해 보면:

  1. 일관된 브랜치 네이밍을 사용하세요.

    • 기능: feat/...
    • 버그 수정: bug/...
    • 기타 잡무/환경 작업: chore/...
  2. 거대한 머지 커밋을 피하세요.

    • 자주 동기화해서 머지를 작게 유지합니다.
    • 팀에서 합의했다면 rebase를 사용해 히스토리를 선형(linear)이고 읽기 쉽게 유지합니다.
  3. 필요할 때는 Squash 머지를 활용하세요.

    • 시끄럽고 실험적인 커밋들을, 브랜치가 준비되었을 때 하나의 의미 있는 단위로 스쿼시합니다.
    • 결과적으로 “질문 하나당 한 커밋” 혹은 작은, 응집력 있는 커밋 묶음이 생깁니다.
  4. 브랜치와 커밋을 이슈/티켓과 연결하세요.

    • 브랜치 이름이나 커밋 메시지에 이슈 ID를 포함합니다.
    • 예: feat/1234-can-users-edit-avatar

이렇게 하면, git log를 읽는 경험이 “시스템이 무엇을 언제 배웠는지”를 보여주는 명확한 내러티브를 읽는 것처럼 느껴집니다.


모두 합쳐 보기: 예시 워크플로

실제 현장에서 한 가지 질문 브랜치 워크플로가 어떻게 보이는지 예를 들어 보면:

  1. 질문으로 시작한다.
    “사용자가 프로필 아바타를 업로드하고 수정할 수 있는가?”

  2. main에서 브랜치를 만든다.
    git checkout -b feat/can-users-edit-avatar

  3. 작고 관련 있는 커밋들로 구현을 진행한다.
    각 커밋은 그 질문에 대한 답에 한 걸음씩 다가가야 합니다.

  4. 정기적으로 main과 동기화한다.
    뒤처지지 않도록 rebase 또는 merge를 사용합니다.

  5. 아직 완전하지 않다면 기능 플래그를 사용한다.
    user-avatar-edit 플래그 뒤에서 백엔드나 부분적인 UI를 먼저 머지합니다.

  6. 작고, 포커스된 PR을 연다.
    PR 설명에는 이 브랜치가 어떤 질문에 어떻게 답하는지, 어떻게 테스트하면 되는지를 적습니다.

  7. 배포하고 정리한다.
    머지되면 브랜치를 삭제합니다. 준비가 되면 기능 플래그를 켭니다.

그리고 다음 질문으로 넘어갑니다.


결론: 한 번에 한 가지 질문

복잡한 Git 의식을 도입할 필요는 없습니다. 필요한 것은 일관성과 적절한 제약입니다.

한 가지 질문 브랜치 전략은 이 두 가지를 모두 제공합니다.

  • 브랜치마다 한 가지 질문만 다루면 범위가 자연스럽게 작고 명확해집니다.
  • 짧게 유지되고 자주 동기화되는 브랜치는 머지 악몽을 예방합니다.
  • 작고 배포 가능한 PR은 리뷰 속도를 높이고 리스크를 줄입니다.
  • 기능 플래그는 미완성 기능을 노출하지 않고도 일찍, 자주 머지할 수 있게 해 줍니다.
  • 명확한 커밋과 일관된 워크플로는 신뢰할 수 있는 Git 히스토리를 만듭니다.

이 작은 습관 하나만 잘 지켜도, 팀의 작업물은 미완성 기능의 뒤엉킨 덩어리에서 벗어나, 작고 안전하며 언제든 배포 가능한 ‘답들’의 흐름이 됩니다. 한 번에 한 가지 질문씩.

한 가지 질문 브랜치 전략: 기능을 작고 배포 가능하게 유지하는 작은 Git 습관 | Rain Lag