AI 엔지니어링

멀티프로젝트 Claude Code 설정 운영기 2편 - gitignore한 CLAUDE.local.md를 git add -f로 강제 추적한 이유

Kir93 2026. 8. 18. 07:37
728x90
반응형

회사 repo에 CLAUDE.md 한 장을 올려두고 팀이 같이 쓰기 시작하면, 얼마 안 가 그 파일이 이상해진다. "이 프로젝트는 pnpm을 쓴다"처럼 모두가 알아야 할 규칙과, "나는 설명을 짧게 받고 싶다"처럼 순전히 내 취향인 지시가 한 파일에 뒤섞인다. 후자를 PR로 올리기는 민망하고, 안 올리자니 매번 로컬에서 고쳐 두고 커밋에서 손으로 빼야 한다. 이 글은 그 분리선을 CLAUDE.local.md로 그으려다 오히려 .gitignore와 한바탕 싸우고 git add -f로 끝난 작업기다. Claude Code로 여러 repo를 오가며 일하는 사람이라면 같은 지점에서 한 번쯤 멈칫했을 것이다.

 

이 시리즈 1편에서는 중앙 설정 repo로 여러 프로젝트에 공통 설정을 동기화하는 방식을 다뤘다. 그런데 동기화가 되는 순간 곧바로 다음 문제가 온다. 내려받은 공통 설정 위에, 각자가·각 프로젝트가 손댈 자리를 어떻게 열어 줄 것인가.

규칙 하나에 두 종류가 산다

먼저 용어 하나. CLAUDE.md는 Claude Code가 세션을 시작할 때 자동으로 읽어 들이는 프로젝트 메모리 파일이다. 여기 적은 규칙은 그 repo에서 일하는 모두에게, 매 세션 적용된다(작성 시점 2026년 5월 기준). 그래서 이 파일은 사실상 "AI에게 주는 팀 컨벤션 문서"다.

문제는 여기 두 종류의 문장이 섞인다는 것이다. 하나는 팀이 공유해야 하는 것 — 패키지 매니저, 커밋 규약, 브랜치 전략, 에이전트가 건드리면 안 되는 디렉터리. 다른 하나는 나만의 override — 응답을 짧게 받고 싶다거나, 특정 라이브러리를 내 방식대로 쓰고 싶다는 개인 취향. 앞의 것은 커밋해야 하고, 뒤의 것은 커밋하면 남에게 강요가 된다. 한 파일에 있으면 이 둘을 매번 눈으로 갈라내야 한다.

CLAUDE.local.md는 이미 있다 — 단, "gitignore된 것"이라는 전제로

다행히 Claude Code는 이 문제에 답을 갖고 있다. CLAUDE.local.md라는 프로젝트 로컬 메모리 파일이다. CLAUDE.md와 함께 세션에 로드되지만, 이름 그대로 "로컬"용 — 공식 문서도 로컬 sandbox URL이나 개인 테스트 노트처럼 팀과 공유할 필요 없는 것들을 넣으라고 안내한다. 그리고 Claude Code는 이 파일을 기본적으로 .gitignore에 넣는다.

나도 그 전제를 그대로 받아들였다. optional override로 CLAUDE.local.md를 도입하고, .gitignore에 등록하고, "개인 override는 여기"라고 팀에 안내 문서까지 붙였다. 깔끔해 보였다. 며칠 동안은.

'local'은 git 상태가 아니라 파일 이름일 뿐이었다

가정이 깨진 건 파일에 실제로 쌓인 내용을 보고 나서다. CLAUDE.local.md에 들어간 건 개인 취향만이 아니었다.

주력 클라이언트 웹앱에서는 팀 공통 행동 규칙이 들어갔다. 에이전트가 지켜야 할 절차와 금지 사항 같은 것들. 데이터 도구 웹앱에서는 그 repo에서만 참인 프로젝트 사실 — 디렉터리 구조, 도메인 용어의 정의 — 이 들어갔다. 둘 다 명백히 팀이 공유해야 하는 것이었다. "로컬"이 아니라 "이 프로젝트 전용"일 뿐이었다.

그런데 .gitignore가 막고 있었으니, 새로 clone 한 팀원 환경에는 이 파일이 통째로 없었다. 나는 잘 돌아가는데 옆자리는 같은 지시를 못 받는 상태. 이름에 붙은 'local' 때문에 반사적으로 gitignore 했는데, 정작 내용의 상당수는 로컬이 아니었던 것이다.

여기서 헷갈리기 쉬운 두 경계를 분리해야 한다. Claude Code가 무엇을 읽느냐(로드 경계)git이 무엇을 추적하느냐(추적 경계)는 완전히 다른 문제다. Claude Code는 CLAUDE.mdCLAUDE.local.md든 있으면 다 읽어 하나의 컨텍스트로 합친다. 그 파일이 커밋되는지 아닌지는 Claude Code가 신경 쓰지 않는다. 그건 순전히 내가 git에게 시키기 나름이다.

git add -f는 .gitignore를 이긴다

해결은 간단했다. 다만 두 갈래였다.

갈래 (a): .gitignore에서 CLAUDE.local.md 줄을 지운다. 그러면 파일은 평범하게 추적된다. 대신 그 repo에서 자연스럽게 생기는 다른 *.local 성격의 스크래치 파일들까지 추적 후보로 노출된다. 기본 방어선을 통째로 허무는 셈이다.

갈래 (b): 기본 무시는 유지한 채, 공유하기로 정한 그 파일 하나만 강제로 편입한다. git add -f가 정확히 이걸 한다.

나는 (b)를 골랐다. 추적을 "명시적 opt-in"으로 남기고 싶었기 때문이다. 무엇을 팀과 공유하기로 결정했는지가 커밋 히스토리에 또렷이 남는다.

# ① CLAUDE.local.md가 기본으로 무시되고 있는지 먼저 확인
git check-ignore -v CLAUDE.local.md
#   .gitignore:12:CLAUDE.local.md    CLAUDE.local.md   ← 지금은 무시되는 중

# ② 기본 방어선(무시)은 그대로 두고, 이 파일만 강제로 추적에 편입
git add -f CLAUDE.local.md
git commit -m "chore: share project-scoped Claude rules"

# ③ 한 번 추적되면 이후 수정은 .gitignore와 무관하게 정상 동작한다
#    git status에 뜨고, git diff에도 잡힌다

가장 흔한 함정은 ①을 건너뛰는 것이다. 파일이 이미 무시되는 상태에서 그냥 git add(‑f 없이)를 하면 git은 아무 경고 없이 조용히 넘어간다. 커밋은 성공하는데 그 파일만 쏙 빠져서, 팀원 clone에서 "왜 이 규칙이 안 먹지?"로 돌아온다. 되돌리고 싶을 땐 반대로 git rm --cached CLAUDE.local.md — 추적만 해제하고 로컬 파일은 남긴다.

트레이드오프도 정직하게 적어 둔다. 이 패턴을 쓰면 새 팀원이 ".gitignore에 있는 파일이 왜 git에는 들어 있지?"라며 잠깐 갸웃한다. 그래서 나는 CLAUDE.md 상단에 한 줄로 이유를 남겨 둔다. "CLAUDE.local.md는 프로젝트 전용 override라 무시 기본값을 유지한 채 git add -f로 공유한다"라고.

그래서 분리선은 gitignore가 아니라 세 개의 자리였다

여러 프로젝트에 차례로 적용하면서 진짜 경계가 드러났다. 파일이 tracked냐 아니냐가 아니라, 누구의 것이고 어디까지 참이냐였다. 그걸 세 자리로 나눴다.

첫째, 사용자 전역 ~/.claude/CLAUDE.md. 응답 길이나 말투 선호 같은 진짜 개인 취향. 어느 repo에도 들어가지 않는다.

둘째, CLAUDE.md. 팀 공식 룰. 안정적이고 모두에게 적용되며, 기본으로 git 추적된다. 얇게 유지하는 게 핵심이다.

셋째, CLAUDE.local.md. 그 repo에서만 참이지만 팀은 공유해야 하는 프로젝트별 override. 자주 바뀐다. git add -f로 추적한다.

이 3 분할이 왜 필요한지는 사내 웹 앱 한 곳에서 분명해졌다. 거기 CLAUDE.local.md에는 개인 디자인 표준에 가까운 내용이 있었다. 여기서 잠깐 멈칫했다. 파일을 통째로 git add -f 하면 내 취향까지 팀에 강요된다. 그래서 그 파일을 다시 갈랐다. 팀이 따를 표준만 override에 남기고, 순수한 내 취향은 전역 ~/.claude/CLAUDE.md로 올렸다. git add -f는 파일 단위 결정이라, 그 안에서 무엇이 진짜 공유 대상인지는 여전히 내가 판단해야 한다.

실제 파일이 어떻게 갈라지는지 예로 보이면 이렇다. CLAUDE.md는 얇고 안정적으로:

# 프로젝트 규칙
- 패키지 매니저는 pnpm을 쓴다. npm/yarn 명령을 만들지 않는다.
- 커밋 메시지는 Conventional Commits를 따른다.
- 테스트를 지우거나 우회해 초록불을 만들지 않는다.

 

 

CLAUDE.local.md는 그 repo에서만 참인 것들로

# 이 repo에서만 참인 것
- 라우팅은 app/ 아래 파일 기반이고, 페이지 진입점은 app/(main)/ 아래에 있다.
- "<도메인 용어>"는 이 서비스에서 <A>가 <B>에게 …을 확정하는 절차를 뜻한다.
- 에이전트는 db/migrations 를 직접 수정하지 않는다. 생성 스크립트만 실행한다.

 

 

정리하면, CLAUDE.local.md의 'local'은 git 상태가 아니라 파일 이름일 뿐이다. Claude Code는 세 파일을 모두 읽어 하나의 콘텍스트로 합치지만, 그중 무엇을 커밋할지는 이름이 아니라 내가 정한다. 팀이 공유해야 하는 override라면 .gitignore 기본값은 유지한 채 git add -f로 명시적으로 편입하고, 진짜 개인 취향은 ~/.claude로 올려 repo 밖에 둔다.

지금 당신 repo에서 git check-ignore CLAUDE.local.md를 쳐 보라. 그 안에 팀이 clone 하면 사라질 공유 규칙이 들어 있다면, 그건 로컬 파일이 아니라 아직 공유되지 못한 팀 콘텍스트다.

참고

  • Claude Code 공식 문서 — 메모리: How Claude remembers your project. CLAUDE.md/CLAUDE.local.md의 로드 규칙과 로컬 메모리의 .gitignore 기본 동작 근거(인용 시점 2026년 5월)

2026.07.23 - [AI 엔지니어링] - 멀티프로젝트 Claude Code 설정 운영기 1편 - 여러 프로젝트 .claude/를 한 저장소가 소유하게 만들기

반응형