Skip to content

깃 브랜치 전략

dictionary-app·dictionary-api와 이 문서 사이트(dictionary-guide) 세 저장소가 함께 쓰는 브랜치 전략이다. 기본 원칙은 같고, 원칙을 강제하는 방법만 저장소마다 조금씩 다르다.

  1. master는 통합 브랜치다 — 여기에 직접 커밋(일반 커밋, --amend, cherry-pick, revert 포함)하지 않는다. 반영 경로는 (1) 작업 브랜치를 병합하는 것과 (2) GitHub PR을 병합하는 것 둘뿐이다.
  2. 배포는 deploy 브랜치를 따로 두고 이 브랜치에 push될 때만 트리거한다 — master push가 배포로 이어지지 않게 해서, 평소 작업과 “지금 배포한다”는 결정을 분리한다.
  3. 기능 추가/버그 수정/문서 정리 등 목적이 있는 모든 작업은 master에서 작업 브랜치를 분기해서 진행한 뒤 master로 병합한다. 병합하는 실행 안에서 새로 만든 브랜치는 병합 후 지우고, 그 전부터 있던 브랜치는 지울지 사용자가 판단한다.
  4. 작업 브랜치는 오직 master로만 병합한다 — deploy를 포함해 다른 브랜치로 직접 병합하는 것은 금지한다. deploy에는 항상 master를 거친 변경만 들어가야 한다.
  5. 병합은 항상 git merge --no-ff로 실행한다 — fast-forward가 가능해도 항상 병합 커밋(부모 2개)을 남기도록 강제한다. git log --graph만 봐도 어떤 브랜치가 언제 병합됐는지 드러나고, git branch --merged로 병합 여부를 판별하기도 쉬워진다. git rebase는 쓰지 않는다.
  1. <type>/<설명> 형식이다(예: feature/guest-login, docs/branch-guide). 날짜 토큰은 넣지 않는다.
  2. <type>은 커밋 타입(Conventional Commits)과 의미가 대응하되, feat는 feature로 풀어 쓰고 긴급 수정은 hotfix를 쓴다.
  3. <설명>은 소문자 케밥 케이스로, 핵심 변경 내용을 2~4단어로 요약한다.

타입 목록과 장기 유지 브랜치 전용 타입(release·env)은 형상관리 브랜치 규칙 참고.

같은 “master 직접 커밋 금지 + --no-ff 병합” 원칙을 저장소마다 아래 장치로 강제한다.

장치 dictionary-app dictionary-api dictionary-guide
Claude Code 훅 (AI의 명령 차단) ✅ ✅ ✅
git pre-commit 훅 (사람의 커밋 차단) — (포맷·빌드 검사만) ✅ — (git 훅 없음)
Git 스킬 (절차 안에서 확인) ✅ ✅ ✅
  1. Claude Code 훅 — 세 저장소 모두 .claude/hooks/block-master-direct-commit.sh를 PreToolUse(Bash) 훅으로 등록한다. 현재 브랜치가 master일 때 AI가 커밋 계열 명령(commit/cherry-pick/revert/rebase)을 실행하거나 master 위에서 deploy를 병합하려 하면, 명령이 실행되기 전에 막는다. 작업 브랜치 병합이나 status/log/push 같은 명령은 막지 않는다. 검사 로직은 같은 폴더의 check-master-guard.cjs(node)에 있고, 세 저장소가 같은 파일을 쓴다.
  2. git 훅 — dictionary-api는 pre-commit 훅이 .git/MERGE_HEAD 존재 여부로 “지금 이 커밋이 병합 중인가”를 판별해, 병합이 아닌데 현재 브랜치가 master면 커밋 자체를 차단한다. AI뿐 아니라 사람이 직접 커밋하는 것도 막는다. 자세한 스크립트는 깃훅 가이드 참고.
  3. Git 스킬 — /git-commit·/git-publish는 실행 중에 현재 브랜치를 확인해, master에는 직접 커밋하지 않고(/git-publish는 작업 브랜치를 자동으로 만든다) deploy에서는 중단한다.
  1. master → deploy 병합 시점은 사람이 판단한다 — 정해진 주기 없이, “지금 배포한다”고 결정한 시점에만 진행한다. 판단이 끝나면 실제 병합·push는 /git-deploy 스킬로 AI에게 맡길 수 있다.
  2. 이 병합도 --no-ff로 실행해 병합 이력을 남긴다.
  3. 병합 방향은 항상 master → deploy 하나뿐이다 — deploy에서 master로 역방향 병합하지 않는다. 직접 실행할 때의 명령은 다음과 같다.
    Terminal window
    git switch deploy
    git merge --no-ff master
    git push origin deploy

지금의 브랜치 전략에는 Pull Request(PR)와 코드 리뷰 단계가 없다. 작업 브랜치를 원격에 올려 PR로 병합하는 대신, 로컬에서 master로 --no-ff 병합한 뒤 바로 push한다. 이는 현재 프로젝트가 혼자 개발하는 개인 프로젝트이기 때문에, 개인이 쓰기에 가장 가벼운 형태로 구성한 결과다.

  1. 리뷰할 사람이 없다. 혼자 작업하면 PR을 열어도 작성자가 스스로 승인하게 된다. 리뷰 없이 PR만 거치면 브랜치 push → PR 생성 → 병합 버튼이라는 절차만 늘고, 코드 품질에 주는 효과는 없다.
  2. PR이 주는 이점 중 필요한 것은 이미 다른 방식으로 얻고 있다.
    • 작업 단위 기록: 작업 브랜치를 --no-ff로 병합해 병합 커밋이 남으므로, PR 없이도 git log --graph에서 어떤 작업이 언제 들어왔는지 보인다.
    • master 보호: 브랜치 보호 규칙 대신 master 직접 커밋을 막는 훅과 스킬 문서로 실수를 막는다(위 실제 강제 방법 참고).
    • 배포 통제: master에 병합해도 바로 배포되지 않고, 사람이 판단한 시점에만 deploy로 병합한다.
  3. AI에게 맡기는 원격 쓰기를 최소로 한다. AI의 원격 push는 /git-publish(master)와 /git-deploy(deploy) 두 스킬로만 허용하고, gh pr create·gh pr merge 같은 PR 조작은 금지한다. PR을 절차에 넣으면 AI가 다뤄야 하는 원격 쓰기 작업이 늘어난다.
flowchart LR
  subgraph personal["현재 (개인 프로젝트)"]
    direction LR
    p1["작업 브랜치"] -- "로컬에서 --no-ff 병합<br/>(/git-publish)" --> p2["master"]
    p2 -- "push" --> p3["origin/master"]
  end
  subgraph team["여러 명이 작업할 때 (예시)"]
    direction LR
    t1["작업 브랜치"] -- "push" --> t2["origin/작업 브랜치"]
    t2 -- "PR 생성" --> t3{"코드 리뷰 승인<br/>+ CI 통과?"}
    t3 -- "예 (merge commit 방식으로 병합)" --> t4["origin/master"]
    t3 -- "아니오" --> t1
  end
  1. master를 GitHub 브랜치 보호 규칙으로 막는다. 직접 push를 금지하고, PR 병합만 허용하며, 승인 리뷰 수와 필수 CI 검사(빌드 등)를 지정한다. 로컬 훅이나 스킬 문서만으로는 다른 사람의 push를 막을 수 없다.
  2. 병합 경로를 PR 하나로 바꾼다. 작업 브랜치를 원격에 push하고 PR로 병합한다. --no-ff 원칙을 유지하려면 GitHub 저장소 설정에서 PR 병합 방식을 merge commit으로 두고, squash·rebase 병합은 끈다.
  3. 코드 리뷰 기준을 정한다. 필요한 승인 수, 리뷰어 지정 방법(CODEOWNERS 등), 리뷰에서 확인할 항목을 정한다.
  4. PR마다 CI를 돌린다. 지금은 deploy push 때만 워크플로우가 돈다. PR에서도 빌드·린트가 실행되도록 워크플로우를 추가한다.
  5. Git 스킬과 AI 규칙을 고친다. /git-publish는 로컬 병합 + master push 대신 “작업 브랜치 push + PR 생성”까지만 하도록 바꾸고, 그에 맞게 AI의 원격 쓰기 허용 범위(gh pr create 허용 여부 등)를 다시 정한다.
  6. 배포 권한과 시점을 정한다. 누가 언제 deploy로 병합하는지 정하고, 필요하면 deploy도 보호 규칙으로 막는다.