커밋 전에 잠깐 멈추기: 지저분한 코드가 Git에 들어가기 전에 막아 주는 90초 의식
작은 원자 커밋, 90초짜리 사전 커밋 습관, 그리고 자동화된 pre-commit 체크를 조합해 팀의 코드 품질과 Git 이력을 극적으로 개선하는 방법.
커밋 전에 잠깐 멈추기: 지저분한 코드가 Git에 들어가기 전에 막아 주는 90초 의식
현대 개발은 매우 빠르게 움직입니다. 기능 브랜치, Pull Request, 지속적 배포(Continuous Deployment)까지 — 모든 것이 코드를 최대한 빨리 배포하도록 설계되어 있습니다. 하지만 속도만 있고 규율이 없으면 익숙한 혼돈이 찾아옵니다.
- 지저분한 커밋 히스토리
main브랜치에서 깨지는 테스트- "급한 수정"이 연쇄적으로 이어져 결국 서비스 장애로 번지는 상황
이 혼돈을 크게 줄여 줄 아주 작은 습관이 하나 있습니다. 바로 사전 커밋(pre-commit) 멈춤입니다.
git commit을 하기 전에 90초 정도 잠깐 멈추고, 체크리스트와 자동화 도구를 곁들여 변경사항을 점검하는 간단한 의식입니다. 이 과정을 거치면 깨진 코드나 허술한 코드가 애초에 저장소에 들어가지 못합니다.
이건 당신을 느리게 만들기 위한 장치가 아닙니다. 매 커밋의 가치를 높이기 위한 장치입니다.
사전 커밋 멈춤이란 무엇인가?
**사전 커밋 멈춤(pre-commit pause)**은 git commit을 실행하기 바로 직전에 일부러 하는 짧은 의식입니다. 보통 90초 정도면 충분합니다. 이 시간 동안 당신은 다음을 수행합니다.
- 이번에 커밋하려는 변경을 훑어본다
- 간단한 체크리스트를 머릿속(또는 문서로) 돌려 본다
- 필요하다면 자동화된 체크를 실행하거나, Git pre-commit 훅에 맡긴다
- 커밋이 작고, 원자적이며, 설명이 명확한지 확인한다
목표는 깊은 코드 리뷰가 아닙니다. 핵심은 **이성 검증(sanity check)**입니다.
“이 커밋은 안전한가? 범위가 명확한가? 나중에 읽을 사람이(미래의 나를 포함해) 이해할 수 있을 만큼 깔끔한가?”
이 습관에 사전 커밋 체크리스트와, 포매팅·린팅·테스트를 돌려 주는 Git pre-commit 훅을 결합하면, 공유 저장소에 변경사항이 닿기 전에 가볍지만 강력한 품질 게이트가 만들어집니다.
왜 굳이 이 과정을 거쳐야 할까? 건너뛰었을 때의 비용
이 과정을 한 번쯤은 건너뛰고 싶어집니다. 별일 없을 것 같기도 합니다. 하지만 조금만 시야를 넓혀 보면:
- 디버그 로그, 주석 처리된 코드 블록, 미완성 코드가 그대로 커밋에 포함됩니다.
- 사소한 포매팅/린트 에러가 CI를 깨뜨려 팀 전체의 작업을 막습니다.
- 테스트를 공유 브랜치에 푸시한 다음에야 깨진다는 걸 알게 되어, 롤백과 핫픽스가 난무합니다.
- 커밋 메시지는
fix,oops,really fix,wip,final final actually working같은 묘비명으로 가득 찹니다.
각각은 대단한 문제처럼 보이지 않을 수 있지만, 합쳐지면 팀 속도를 늦추고 코드베이스에 대한 신뢰를 갉아먹습니다.
사전 커밋 멈춤은 이런 상황을 막기 위한 아주 작고, 체계적인 방어막입니다.
원칙 1: 작고, 원자적인(Atomic) 커밋
사전 커밋 멈춤은 하나의 질문으로 시작합니다.
“이 커밋은 하나의 논리적 변경만 담고 있는가?”
**원자 커밋(atomic commit)**은 딱 한 가지 일을 합니다.
- 새 함수를 추가한다
- 특정 버그를 수정한다
- 한 모듈을 리팩터링한다
- 의존성을 업데이트한다
반대로, 다음과 같은 일은 하지 않습니다.
- 버그를 고치면서, 관계없는 코드를 리팩터링하고, 문서까지 한 번에 수정
- 포매팅 변경과 동작(behavior) 변경을 한 커밋에 섞기
- "지나가다 보니" 눈에 밟힌 코드들을 여기저기서 정리해 한데 묶기
원자 커밋이 중요한 이유
- 리뷰가 쉬워집니다: 한 번에 하나의 변경만 이해하면 되기 때문입니다.
- 디버깅이 단순해집니다:
git bisect나git blame이 훨씬 유용해집니다. - 롤백이 안전해집니다: 특정 변경만 되돌려도 부작용이 최소화됩니다.
원자성을 위한 빠른 체크리스트
커밋 전에 스스로에게 물어 보세요.
- 이 변경을 “그리고(and)”나 “또한(also)” 없이 한 문장으로 설명할 수 있는가?
- 이 커밋만 되돌려도 코드베이스가 여전히 일관된 상태를 유지하는가?
- 무심코 끼워 넣은 관계없는 변경(예: 이름 일괄 변경, 포매팅 정리 등)이 없는가?
하나라도 아니오라면, 변경을 여러 개의 작은 커밋으로 나누는 걸 고려해 보세요.
원칙 2: 무엇보다 왜를 설명하는 커밋 메시지
대부분의 커밋 메시지는 너무 모호해서 큰 도움이 되지 않습니다.
update codefix bugchanges
“뭔가 바뀌었다”는 사실만 말해 주고, 왜 그런 변경을 했는지는 알려 주지 않습니다.
미래에 이 커밋을 읽을 사람(미래의 나 포함)은 이런 질문을 하게 됩니다.
- 어떤 문제를 해결하려고 한 것인가?
- 왜 이 접근 방식을 선택했는가?
- 이 동작은 의도된 것인가, 부작용인가?
더 나은 커밋 메시지 공식
커밋 메시지를 **“작은 변경을 위한 짧은 서사”**라고 생각해 보세요.
간단한 패턴은 다음과 같습니다.
<명령형으로 쓰는 짧은 요약 한 줄> (선택) 본문에는 다음을 설명: - 변경의 이유(Why) - 고려한 트레이드오프나 주의사항 - 관련 티켓/이슈 링크
예시:
할인 주문의 잘못된 세금 계산 수정 이전에는 세금이 할인 적용 전 상품의 정가 기준으로 계산되어 과금이 과도하게 되는 문제가 있었습니다. 이번 변경에서는 할인 적용 후 금액에 세금을 계산하도록 수정하여 문서화된 정책과 법적 요구사항을 충족하도록 했습니다.
사용자 서비스에서 ORM 모델 의존성 제거 리팩터링 영속성 로직을 분리하기 위해 리포지토리 레이어를 도입했습니다. 이를 통해 다음 분기에 예정된 새로운 데이터베이스 공급자 교체가 더 쉬워질 것입니다.
사전 커밋 멈춤 시간에 스스로에게 물어 보세요.
- 1년 뒤에 이 커밋 메시지와 diff만 보고도 이해할 수 있을까?
그렇지 않다면, 20–30초만 더 들여 메시지를 다듬어 보세요. 그 시간은 나중에 여러 번 이자를 붙여서 돌아옵니다.
원칙 3: 사전 커밋 체크리스트 (수동 + 자동)
사전 커밋 체크리스트는 이 90초짜리 의식을 반복 가능한 습관으로 만들어 줍니다. 머릿속에 넣어 두어도 되고, 포스트잇에 적어 모니터에 붙여도 되고, IDE나 팀 문서에 넣어도 됩니다.
예시 수동 체크리스트 (사람이 직접 보는 항목)
커밋 전에 빠르게 다음을 확인합니다.
- diff 검토
- 디버그 출력,
TODO, 커밋하고 싶지 않은 주석 처리 코드가 남아 있지 않은가? - 커밋할 의도가 없었던 파일(예:
.env, 임시 스크립트)이 포함되어 있지 않은가?
- 디버그 출력,
- 범위 점검
- 이 커밋은 하나의 논리적 변경으로 제한되어 있는가?
- 리팩터링과 동작 변경을 한 커밋에 섞지 않았는가?
- 동작 확인
- 관련 테스트를 돌렸거나, 최소한 로컬에서 스모크 테스트는 해 보았는가?
- 내 환경에서 빌드 및 실행이 되는가?
- 문서화 필요 여부
- 새 동작이나 변경 사항을 문서나 변경 로그(changelog)에 남겨야 하는가?
- 커밋 메시지 작성/검증
- 이 변경이 왜 존재하는지 분명하게 설명하고 있는가?
이 정도만 훑어 봐도 놀랄 만큼 많은 "아차" 순간을 사전에 잡아낼 수 있습니다.
Git pre-commit 훅으로 체크리스트 자동화하기
모든 걸 직접 할 필요는 없습니다. Git pre-commit 훅을 사용하면 다음을 자동으로 실행할 수 있습니다.
- 린터(예:
flake8,eslint) - 포매터(예:
black,prettier) - import 정렬 도구(예:
isort) - 작고 빠른 서브셋 테스트
- 기본 규칙 위반 시 커밋 차단(예: 코드 내 시크릿 검출, 린트 실패 등)
이때 pre-commit 같은 도구가 특히 유용합니다.
원칙 4: pre-commit과 pre-commit.ci 활용하기
pre-commit은 Python에 국한되지 않고 여러 언어의 pre-commit 훅을 관리·실행해 주는 프레임워크입니다.
동작 방식(개요)
- 저장소에
.pre-commit-config.yaml파일을 만들고, 어떤 훅을 돌릴지 정의합니다. - 개발자는 로컬에
pre-commit을 설치한 뒤, 한 번만pre-commit install을 실행합니다. - 그 이후로는 커밋할 때마다
pre-commit이 스테이지된 파일에 대해 설정된 훅을 자동으로 실행합니다.
예시: Python 프로젝트용 pre-commit 설정
repos: - repo: https://github.com/psf/black rev: 24.4.2 hooks: - id: black - repo: https://github.com/pycqa/flake8 rev: 7.1.0 hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-prettier rev: v4.0.0-alpha.8 hooks: - id: prettier files: '\\.(js|ts|jsx|tsx|json)$'
이 설정이 있으면, 매 커밋마다 자동으로 다음이 수행됩니다.
- Python 코드는
black으로 포매팅 - Python 코드를
flake8으로 린트 - JavaScript/TypeScript/JSON 파일은
prettier로 포매팅
어느 훅이든 실패하면, 문제를 고칠 때까지 커밋이 차단됩니다.
pre-commit.ci: 클라우드에서 돌리는 체크
pre-commit.ci는 다음을 제공하는 호스티드 서비스입니다.
- Pull Request마다
pre-commit훅을 CI에서 실행 - 자동으로 고칠 수 있는 문제는 수정한 뒤 브랜치에 푸시
- 로컬에 훅을 설치하지 않은 기여자라도 동일한 체크를 받도록 보장
로컬 pre-commit 훅과 pre-commit.ci를 함께 쓰면 일관된 안전망이 생깁니다.
- 사전 커밋 멈춤 동안 로컬에서 먼저 문제를 잡습니다.
- 혹시 빠뜨렸거나 외부 기여자로부터 온 변경은 CI에서 추가로 걸러 줍니다.
모두 합치면: 현실적인 90초 플로우
실제로 사전 커밋 멈춤이 어떻게 보이는지, 한 번 흐름을 따라가 봅시다.
-
변경 사항 스테이징
git add <files> -
diff 검토 (30–40초)
git diff --cached- 디버그 출력이나 주석 처리 코드 제거
- 필요하다면 관련 없는 변경은 언스테이징
-
동작에 대한 sanity check (20–30초)
- 관련 있는 작은 테스트를 돌리거나, 방금 수정한 기능을 직접 한 번 실행
-
pre-commit실행 (자동, 보통 30초 이내)git commit- 훅이 포매팅·린팅을 수행
- 실패가 나면 안내에 따라 수정 후 다시 시도
-
명확한 커밋 메시지 작성 (10–20초)
- 한 줄 요약 + (필요하다면) 짧은 “왜” 설명
총 소요 시간: 약 90초. 실제로는 이보다 더 짧을 때도 많습니다.
대신 얻게 되는 것:
- 훨씬 깨끗한 커밋 히스토리
- 덜 깨지는 빌드
- 머지와 배포에 대한 높은 신뢰도
결론: 90초짜리 규율
코드 품질은 멋진 알고리즘이나 화려한 아키텍처만으로 결정되지 않습니다. 작고, 꾸준한 습관에서 비롯됩니다. 사전 커밋 멈춤은 그중에서도 가장 간단하면서 임팩트가 큰 습관입니다.
- 매 커밋 전에 약 90초만 멈춰서 점검하세요.
- 커밋을 작고 원자적으로, 한 번에 하나의 논리적 변경만 담으세요.
- 무엇이 아니라 왜를 설명하는 커밋 메시지를 쓰세요.
- 사전 커밋 체크리스트와 자동화된 훅으로 문제를 초기에 잡으세요.
- 팀 전체에
pre-commit과pre-commit.ci같은 도구를 도입해 이 과정을 힘들이지 않고 유지하세요.
코드 품질을 높이기 위해 거대한 프로세스 개편이 필요한 것은 아닙니다. 하루에도 수십 번 반복되는 작고 믿을 수 있는 의식 하나면 충분합니다.
다음 커밋부터 시작해 보세요. 90초만 투자해서, 멈추고, 살펴보고, 의도를 담아 커밋하세요.
당신의 미래의 자신과 팀 동료들은, 언젠가 Git 히스토리를 읽으며 분명히 고마워하게 될 것입니다.