세 개의 커밋으로 쓰는 이야기: 지저분한 코딩 시간을 또렷한 진전으로 바꾸는 법
집중 코딩 세션마다 단 세 개의 의도적인 커밋을 ‘작은 이야기’로 사용해 작업에 구조를 주고, Git 히스토리를 읽기 좋게 만들며, 모든 작업 블록을 눈에 보이는 진행 상황으로 바꾸는 방법을 소개합니다.
소개
“딱 한 시간만 코딩해야지” 하고 자리에 앉습니다. 세 시간이 지나 보니 파일 열 개를 고쳤고, 세 가지 접근을 번갈아 시도했고, 전혀 상관없는 버그 하나를 고쳤고, Git 히스토리는 wip, oops, fix stuff 같은 커밋들로 가득합니다.
코드는 어찌어찌 돌아가지만, 무엇이 어떻게 진전됐는지 보이질 않습니다. 되짚어 보기도 괴롭고, 미래의 나(혹은 팀원)는 왜 이런 식으로 바뀌었는지 전혀 알 수 없을 겁니다.
여기 더 나은 패턴이 있습니다. 바로 **‘세 개의 커밋으로 쓰는 이야기(three‑commit story)’**입니다.
이건 아주 단순한 연습법이지만, 흐릿한 목표를 작고 추적 가능한 진전 단위로 바꿔 줍니다. 한 번의 집중 세션마다 의도적인 커밋 세 개만 쓰는 방식이죠. 이 패턴은 다음에 도움을 줍니다.
- 쓸데없이 넓어지고 산만해지는 코딩 세션을 피하게 해 줍니다.
- Git 히스토리를 읽기 쉽고 리뷰하기 좋게 유지합니다.
- 매 작업 블록을 의미 있고 문서화된 “이야기”로 만들어 줍니다.
이제 구체적으로 어떻게 동작하는지 살펴보겠습니다.
Three‑Commit Story란 무엇인가?
Three‑commit story는 한 번의 집중 코딩 세션(보통 30–120분) 안에 끝낼 수 있는, 작고 자급자족하는(스스로 완결된) 진전 단위입니다.
이 방식에는 세 가지 특징이 있습니다.
- 작은 범위 – 하나의 명확한 개선만 다룹니다. (예: “상품 목록에 검색 기능 추가”, “페이지네이션 버그 수정”, “이메일 전송 로직을 서비스로 분리”)
- 의도적인 세 개의 커밋 – 작업을 세 단계로 나누고, 각 단계를 커밋 하나로 기록합니다.
- 읽기 좋은 내러티브 – 이 세 커밋이 합쳐져 “무엇을 왜 했는지”를 설명하는 하나의 이야기입니다.
“검색 기능 구현”이라는 큰 일감으로 접근하는 대신, 이렇게 접근합니다.
- 계획 & 스캐폴딩(Scaffold): 구조, 테스트, 플레이스홀더를 마련합니다.
- 구현(Implementation): 실제로 동작하게 만듭니다.
- 정리 & 리팩터(Refactor): 다듬고 단순화하고 문서화합니다.
각 단계가 커밋 하나가 되고, Git 히스토리에는 짧고 이해하기 쉬운 이야기 하나가 남습니다.
세 개의 의도적인 커밋
Three‑commit story는 아주 단순한 템플릿을 따릅니다. 각 단계에 붙이는 라벨은 바꿔도 되지만, 흐름은 그대로 유지됩니다.
1. Plan / Scaffold 커밋
목표: 기능을 전부 구현하지는 않고, 기반을 준비하는 단계입니다.
대표적인 변경 사항:
- 원하는 동작을 표현하는 테스트를 추가하거나 수정
- 새 파일, 클래스, 함수 등을 플레이스홀더 형태로 추가
- 실제 로직이 들어갈 자리에 TODO 코멘트나 스텁(stub) 추가
- 기본 라우팅이나 설정을 연결해 두기
예시 커밋 메시지:
feat: scaffold product search endpoint - add /products/search route - define ProductSearchRequest and response DTO - add failing integration test for search by name
왜 중요한가:
- 무엇을 만들지 사전에 분명히 하도록 강제합니다.
- 테스트, 타입, 계약(contracts) 등 명확한 목표물을 제공합니다.
- 설계·세팅 단계와 실제 구현 단계를 분리해 줍니다.
2. Implementation 커밋
목표: 실제로 동작하게 만들기. 핵심 로직이 들어오는 단계입니다.
대표적인 변경 사항:
- 앞에서 만들어 둔 스텁 메서드를 실제로 구현
- 테스트를 통과시키기
- 필수 에러 처리와 정상 흐름(happy path) 구현
예시 커밋 메시지:
feat: implement product search by name - query products by name (case-insensitive) - support partial matches with LIKE - ensure existing filters still apply
왜 중요한가:
- “살이 붙는” 핵심 변경이 한 군데에 모입니다.
- 의도가 분명해 리뷰와 디버깅이 쉬워집니다.
- 무언가 깨졌다면, 가장 먼저 이 커밋을 의심하면 됩니다.
3. Cleanup / Refactor 커밋
목표: 방금 만든 것을 다듬고 안정화하는 단계입니다.
대표적인 변경 사항:
- 가독성과 유지보수성을 높이기 위한 리팩터링
- 중복 코드나 사용되지 않는 코드 제거
- 이름과 구조 개선
- 관련 문서나 주석 업데이트
예시 커밋 메시지:
refactor: simplify product search query - extract query builder to ProductSearchSpecification - rename params for clarity - add comments for search behavior
왜 중요한가:
- 동작을 바꾸지 않는 리팩터를 다른 변경과 분리할 수 있습니다.
- diff가 작고 의미 있게 유지됩니다.
- 정리 단계가 커밋 한 칸을 이미 예약해 둔 상태이므로, 대충 넘어가지 않게 도와줍니다.
이렇게 세션을 마치면, 스캐폴딩 → 구현 → 정제라는 세 막으로 이뤄진 하나의 이야기가 남습니다.
명확하고 액션 중심적인 커밋 메시지 쓰기
Three‑commit story는 각 커밋 메시지가 짧고 구체적이며, “무엇을 했다”가 잘 드러날수록 효과가 좋습니다.
간단한 구조는 다음과 같습니다.
- 요약 라인 (약 72자 이내)
- 선택적인 본문 – 각각의 줄이나 불릿으로 무엇을 그리고 왜 했는지 설명
예시:
feat: add optimistic locking to order updates - prevent double-submit from overwriting changes - surface concurrency error to the UI
fix: handle empty query string in product search - return 400 instead of 500 on invalid query - add regression test for empty search
가이드라인:
- 항상 동사로 시작합니다:
add,fix,remove,refactor,document,rename등 - 구체적으로 씁니다:
misc changes보다는implement product search pagination처럼 - 본문은 특히 직관적이지 않은 결정들에 대해 왜 그렇게 했는지 적는 용도로 사용합니다.
이렇게 하면 Git 히스토리가 “작고 명확한 행동들의 연속”처럼 읽히게 됩니다.
의도를 드러내는 일관된 접두사(prefix) 사용하기
일관된 접두사를 쓰면 히스토리를 훑어볼 때 패턴이 눈에 잘 들어옵니다. 흔히 쓰는 예시는 다음과 같습니다.
feat:– 새로운 기능 또는 동작 추가fix:– 버그 수정 또는 결함 해결refactor:– 동작은 그대로인 코드 구조 변경docs:– 문서 관련 변경만 있을 때test:– 테스트 코드 관련 변경chore:– 도구, 설정, 기타 유지보수 작업
Three‑commit story에서는 이런 패턴으로 보일 수 있습니다.
feat: scaffold product searchfeat: implement product search by namerefactor: simplify product search query
버그 수정의 경우는 이렇게 될 수도 있습니다.
test: add regression test for pagination bugfix: correct page offset calculationrefactor: extract pagination logic into helper
이런 접두사는 다음에 도움이 됩니다.
- 커밋 유형별로 쉽게 필터링할 수 있습니다.
- 리뷰어가 각 변경의 목적을 빠르게 파악할 수 있습니다.
- 자동화 도구가 의미 있는 변경 로그(changelog)를 생성하는 데 유용한 신호가 됩니다.
Git 히스토리를 문서로 다루기
Three‑commit story를 꾸준히 쓰기 시작하면, Git 히스토리는 잡동사니 서랍이 아니라 쓸 만한 문서가 됩니다.
얻을 수 있는 이점은 다음과 같습니다.
코드 리뷰가 쉬워짐
리뷰어는:
- 커밋 하나씩 순서대로 이야기를 따라갈 수 있습니다.
- 설계 → 구현 → 정리 단계를 분리해서 볼 수 있습니다.
- 더 작고 집중된 diff에 대해 코멘트할 수 있습니다.
디버깅 속도가 빨라짐
버그가 생겼을 때:
git blame으로 한 줄을 추적하면, 의미 있는 커밋 메시지가 나옵니다.- 그 주변의 three‑commit story를 같이 살펴볼 수 있습니다.
- 무엇이 바뀌었는지만이 아니라, 왜 그렇게 바뀌었는지를 이해할 수 있습니다.
지식 공유가 명확해짐
새 팀원은 히스토리를 읽으면서 시스템이 어떻게 진화했는지 배울 수 있습니다.
- “아, 이때 낙관적 락(optimistic locking)을 추가했구나.”
- “우리는 동작을 바꾸지 않는 리팩터를 이렇게 진행하는구나.”
각 three‑commit story는 프로젝트 문서의 한 작은 챕터가 됩니다.
커밋 히스토리를 자동화의 연료로 만들기
잘 구조화된 커밋 히스토리는 사람에게만 좋은 게 아니라, 자동화 관점에서도 매우 유용한 데이터입니다.
일관된 접두사와 명확한 메시지를 같이 쓰면, GitHub Actions, GitLab CI 같은 파이프라인 도구에서 다음과 같은 일을 할 수 있습니다.
feat:와fix:커밋을 모아서 changelog 생성docs:나 특정feat:커밋을 기준으로 API 문서 자동 빌드- 커밋 히스토리로부터 자동으로 릴리스 노트 초안 만들기
예를 들어, 릴리스 파이프라인이 다음과 같이 동작할 수 있습니다.
- 마지막 태그 이후의 커밋을 스캔합니다.
- 커밋을 유형별(
feat,fix,refactor)로 그룹화합니다. - 다음 릴리스를 위한 마크다운 형식의 changelog 섹션을 생성합니다.
이렇게 되면, 꾸준히 쌓은 three‑commit story가 프로젝트의 커뮤니케이션과 릴리스 프로세스에 그대로 연결됩니다.
Three‑Commit Story를 습관으로 만들기
습관은 단순하고 반복 가능할수록 잘 유지됩니다. 이 패턴을 습관으로 만드는 방법을 살펴봅니다.
1. 아주 작은 범위에서 시작하기
코딩을 시작하기 전에 스스로에게 물어보세요.
지금 한 번의 집중 세션 안에 끝낼 수 있는 진전 단위가 무엇일까?
크다고 느껴지면 더 잘게 쪼개세요. 부담 없이 끝낼 수 있는 크기를 목표로 합니다.
2. 세 개의 커밋 이름을 먼저 정해 두기
시작 전에 대략 이렇게 적어 둡니다.
feat: scaffold user password resetfeat: implement password reset email flowrefactor: tidy password reset handlers
이렇게 해 두면 작은 로드맵이 생기고, 작업 범위가 새어나가는 것을 막아 줍니다.
3. 단계를 섞지 않도록 의식적으로 버티기
구현 단계에서 리팩터 아이디어가 떠오를 겁니다. 그럴 때 바로 손대기보다는:
- TODO 코멘트를 남겨 두거나
- 간단히 메모에 적어 두었다가
- 세 번째 “정리 커밋”에서 처리합니다.
이렇게 하면 각 커밋이 더 집중되고, 리뷰하기 쉬워집니다.
4. 규칙이 아니라 도구라고 생각하기
이건 기술이지 종교가 아닙니다. 때로는:
- 테스트를 고치기 위한 네 번째 커밋이 필요할 수도 있고
- 아주 사소한 변경이라 커밋 하나로 끝나는 일이 있을 수도 있습니다.
Three‑commit story는 엄격한 규칙이 아니라, 방향을 잡아 주는 패턴입니다. 목표는 명료함과 진행 상황의 가시성이지, 완벽한 형태를 지키는 것이 아닙니다.
마무리
코딩 세션이 지저분해지는 이유는 목표가 흐릿하고, 여러 종류의 변경이 한데 섞여 버리기 때문입니다. Three‑commit story는 여기에 아주 단순한 구조를 제공합니다.
- 변경 사항을 계획하고 스캐폴딩합니다.
- 원하는 동작을 구현합니다.
- 마지막으로 정리하고 리팩터합니다.
여기에 명확하고 액션 중심적인 커밋 메시지, 일관된 접두사를 더하면, 각 코딩 세션이 Git 히스토리 속의 작고 잘 쓰인 이야기 하나가 됩니다.
시간이 지날수록 다음과 같은 변화를 느끼게 될 것입니다.
- 브랜치가 덜 혼란스러워집니다.
- 코드 리뷰가 더 빠르고 명확해집니다.
- 디버깅과 신규 인력 온보딩이 쉬워집니다.
- Git 히스토리가 살아 있는 문서 역할을 합니다.
다음 코딩 세션에서 한 번 시도해 보세요. 아주 작은 목표를 하나 정하고, 세 개의 커밋을 대략 스케치해 둔 뒤, 이 구조대로 작업해 보는 겁니다. 작은 이야기 하나씩 쌓다 보면, 뒤죽박죽이던 진전이 선명하고 눈에 보이는 모멘텀으로 바뀌어 있을 것입니다.