Claude Code에 작업을 맡기다 보면 '커밋 포함 사고(commit巻き込み事故)'가 자주 발생합니다. '이 파일만 커밋해 달라'고 요청했는데, 작업 트리에 남아있던 다른 태스크의 변경까지 함께 커밋되는 경험을 해보신 적 없으신가요?
저는 Claude Code 설정을 버전 관리하는 제 리포지토리에서 여러 세션을 동시에 운영하고 있습니다. 에이전트가 git add -A와 같은 명령어를 실행하면, 다른 세션이 편집 중인 파일까지 가차 없이 staging area에 올라갑니다. 특히 세션을 마무리하며 하는 '정리 커밋(まとめcommit)' 과정에서 무관한 변경까지 쓸어 담아버리는 사고가 끊이지 않았습니다.
사람의 '주의력'이라는 diff 확인 방식으로는, 병렬 작업이 늘어날수록 방어 체계가 무너집니다. 본 글에서는 이러한 포함 사고를 시스템적으로 막는 '3계층 Hook 설계(git-commit-scoped)'를 소개합니다.
기존의 pre-commit 후크는 '현재 staging area에 무엇이 있는지'만 알 수 있습니다. 하지만 정말 검증하고 싶은 것은 'staging area의 내용물이 이번에 커밋해야 할 것과 일치하는가'입니다. 이 '커밋해야 할 내용물'이라는 정보 자체가 어디에도 없기 때문에, 후크는 가만히 있을 수밖에 없습니다.
그래서 발상 자체를 바꿔서, 에이전트에게 '커밋할 파일 목록'을 사전에 선언하도록 합니다. 선언과 실제 상태의 대조(突合)라면 기계적으로 검증할 수 있습니다.
에이전트는 커밋 전에 대상 경로(path)를 선언합니다. pre-commit 후크는 이 선언된 내용물과 staging area를 대조하여, 부족하거나 초과하는 부분이 있으면 즉시 차단합니다. '모르는 사이에 섞여 들어온 파일'은 여기서 걸러집니다.
나아가 git commit -m "..." -- <대상경로>와 같이 pathspec을 지정한 커밋을 표준 절차로 만듭니다. pathspec이 붙은 커밋은 staging area의 상태에 의존하지 않고, 지정된 경로만 커밋합니다. 다른 세션에서 stage된 변경이 있었다 하더라도 구조적으로 혼입할 수 없습니다. pathspec 오타는 1층의 선언 대조에서 감지될 수 있으므로, 2층에서 상호 보완됩니다.
동일 리포지토리에서 여러 세션이 병렬로 운영되면, 고정된 경로에 대한 선언 상태가 서로 덮어쓰게 됩니다(환경 변수 오염). 그래서 세션 식별자를 우선 키(primary key)로 사용하여 선언 상태를 분리했습니다. 이로써 세션 A의 선언이 세션 B의 커밋 검증 과정에 혼입되는 것을 막을 수 있습니다.
검증 본체의 Python 구현(간략 버전)은 여기입니다.
#!/usr/bin/env python3
"""선언과 staged를 대조하는 pre-commit 후크 (간략 버전)"""
import os
...
에이전트 측의 절차는 간단합니다.
# 1. 선언하기
export COMMIT_DECLARED_PATHS="src/validator.py\ndocs/usage.md"
...
처음 구현할 때는 Bash를 사용했지만, 운영하면서 문제가 발견되었습니다.
- 파일명을 쉘 인자로 전달하기 때문에, 공백이나 특수 문자를 포함하는 경로에서 따옴표 오류(quoting accident)가 발생합니다 (그대로 주입면이 됩니다).
- 로직이 여러 파일에 분산되어 수정할 때마다 영향 범위를 추적하기 어렵습니다.
그래서 검증을 Python 하나로 통합하고, 데이터는 커맨드 라인 인자가 아닌 **환경 변수(environment variable)**로 전달하도록 변경했습니다. 쉘 파싱 과정을 거치지 않기 때문에, 따옴표 중첩이나 단어 분할과 같은 종류의 버그가 구조적으로 사라집니다. 실제로 여러 LLM에게 코드 리뷰를 시켜 약 20건의 지적 사항을 수용했으며, 리다이렉트 지정 오류나 빈 목록 방어(empty list guard) 누락 등도 보완하여 안정적으로 운영하고 있습니다.
또한, 에이전트가 이 절차를 따르도록 하기 위해 스킬 문서 측면에서도 'git-commit-scoped 표준'으로 일괄 전환했습니다. 후크(강제)와 절차(유도)라는 두 바퀴가 갖춰져야 비로소 운영 체계로 정착합니다.
3가지 핵심 포인트를 요약합니다.
1단계・선언 검증: 커밋 의도의 선언과 staged의 대조를 통해 '혼입'을 감지 -
2단계・pathspec commit: staging area에 의존하지 않는 커밋으로 혼입을 구조적으로 불가능하게 함 -
3단계・WT_SESSION 분리: 병렬 세션 간 상태 오염을 격리
가장 중요한 포인트는, '무관한 변경까지 포함하는 사고'를, 사고가 일어나기 전 단계인 커밋 실행 시점에서 봉쇄했다는 점입니다. 인간의 주의력이 아닌 시스템으로 방지합니다—AI 에이전트와 안전하게 협업하기 위한 기반 지식으로 꼭 참고해 주시기 바랍니다.
본 기사는 개인 Zenn에서도 공개하고 있습니다.