Git이 볼 수 없는 것은 커밋할 수 없습니다: 에이전트의 부산물을 저장소에서 분리하기
요약
코딩 에이전트 작업 시 발생하는 부산물(계획, 노트, 스크립트 등)이 Git 저장소에 실수로 커밋되는 문제를 방지하기 위한 워크스페이스 구조 설계 방법을 제안합니다. 저장소 외부 디렉토리에 파일을 배치하여 구조적으로 Git 추적을 차단하는 전략을 다룹니다.
핵심 포인트
- .gitignore는 실수로 인한 커밋을 완벽히 보장하지 못함
- 에이전트 부산물을 저장소 상위 디렉토리로 분리하여 구조적 보호
- notes/와 scratch/ 디렉토리를 활용한 데이터 성격별 관리
- CLAUDE.md를 활용해 저장소 외부 지침을 에이전트에게 전달
코딩 에이전트(coding agents)와 작업하다 보면 부산물(exhaust)이 발생합니다. 코드가 수정되기도 전에 작성된 계획들, 채택되지 않은 라이브러리에 대한 조사 노트, 단 한 번 특정 사항을 검증하기 위해 만든 스크립트, 그리고 제가 일하는 방식을 에이전트에게 알려주는 지침들 같은 것들 말이죠.
이 중 그 어떤 것도 저장소(repo)에 속해서는 안 되지만, 모두가 저장소 바로 옆에 머물기를 원합니다.
한동안 저는 평소 하던 방식대로 처리했습니다. .gitignore 항목을 추가하고 좋은 의도를 갖는 것이었죠.
문제는 .gitignore가 약속일 뿐 보증은 아니라는 점입니다. 빠르게 작업하다 보면 실수로 git add -f를 한 번 실행할 수 있습니다. 너무 광범위한 패턴 변경으로 인해 부수 효과로 디렉터리의 무시(ignore) 설정이 해제될 수도 있습니다. 혹은 리팩터링(refactor) 중에 에이전트가 "친절하게도" 무시 파일을 정리해 버릴 수도 있는데, 이는 언어 모델(language model)에 트리(tree)에 대한 쓰기 권한을 주었을 때 실제로 발생하는 일입니다.
이 중 어떤 것이든 여러분의 개인적인 노트를 히스토리(history)에 포함시킬 수 있습니다. 일단 그 히스토리가 공유된 원격(remote) 저장소에 도달하면, 이를 정리하기 위해서는 커밋(commit)을 다시 작성하고, 해당 커밋을 가져간(pull) 모든 사람과 조율해야 하며, 민감한 정보가 있다면 이를 교체(rotate)해야 할 수도 있습니다.
그래서 저는 그 약속을 신뢰하는 것을 그만두었습니다. 이제 제 노트는 저장소 루트(repo root)의 한 단계 상위 디렉터리에 위치하며, 작업 트리(worktree) 외부로 완전히 분리되어 있습니다:
myapp-workspace/ ← 작업 공간(workspace), Git 저장소 외부
├── CLAUDE.md ← 개인용 에이전트 지침
├── notes/ ← 계획, 조사, 세션 노트
...
notes/와 scratch/에 있는 파일들은 저장소에서 작동하는 명령에 의해 실수로 스테이징(staged)될 수 없습니다. 이 보호 조치는 누군가가 무시 규칙을 기억하는 것에 의존하지 않습니다. 파일들이 구조적으로 Git이 추적하는 대상 외부에 있기 때문입니다.
무엇을 어디에 둘 것인가
작업 공간(workspace)은 저장소를 감싸는 일반적인, 추적되지 않는(untracked) 폴더입니다.
notes/에는 계획, 조사, 세션 요약과 같이 지속적인 모든 것을 담습니다. scratch/는 에이전트의 출력물과 일회성 실험들을 위한 쓰레기통 역할을 합니다. 보관할 가치가 있는 것은 notes/로 승격되거나 저장소 자체의 문서로 들어갑니다. 저장소 그 자체만이 배포(ship)되는 유일한 것입니다.
CLAUDE.md는 에이전트(agent)가 레이아웃을 잘 활용할 수 있게 만드는 요소입니다. Claude Code는 실행되는 위치의 상위 디렉토리(ancestor directories)로부터 지침 파일(instruction files)을 로드하므로, 워크스페이스(workspace) 레벨의 CLAUDE.md는 저장소의 워크트리(worktree) 외부에 머물면서도 저장소 내부의 세션에 의해 읽힙니다.
제 파일은 레이아웃을 설명하고 한 가지 중요한 규칙을 추가합니다: 저장소 내부에 커밋된 그 어떤 것에서도 ../notes나 ../scratch를 절대 참조하지 마십시오. 이 파일들은 직접 스테이징(staged)될 수는 없지만, 에이전트가 여전히 그 내용을 복사하거나 인용할 수 있습니다. 이 지침은 그 경계를 명시적으로 만듭니다.
외부 파일이 저장소 내부의 커밋된 CLAUDE.md를 대체하는 것은 아닙니다. 이들은 서로 다른 대상에게 서비스를 제공합니다: 워크스페이스 파일은 래퍼(wrapper)에 특화된 개인적 선호도와 규칙을 담고 있는 반면, 선택적인 내부 파일은 코드와 함께 이동하고 팀과 공유되어야 하는 아키텍처(architecture), 컨벤션(conventions), 그리고 주의사항(gotchas)을 담을 수 있습니다. Claude는 두 파일 모두를 읽습니다. Repoyard는 오직 외부 파일만 생성하며, 내부 파일은 프로젝트와 그 팀의 소유입니다.
접미사(suffix)가 외부에 붙는 이유
워크스페이스의 이름은 myapp-workspace인 반면, 저장소는 myapp이라는 깔끔한 이름을 유지합니다. 처음에는 반대로 시도해 보았으나, 결과적으로 모두 중요해진 세 가지 이유 때문에 다시 되돌렸습니다:
- 터미널 탭은 보통 가장 안쪽 폴더를 보여줍니다. 내부에 깔끔한 이름을 두면, 탭에
workspace의 변형 대신myapp이 표시됩니다. - 도구들은 저장소 디렉토리로부터 이름을 유도합니다. Docker Compose 프로젝트 이름,
npm init기본값 및 유사한 관례들이 깔끔하게 유지됩니다. - 저장소 디렉토리가 GitHub 저장소 이름과 일치하므로, 새로운 워크스페이스 내부에서
git clone을 실행하면 별도의 커스텀 타겟 인자 없이도 레이아웃이 재현됩니다.
래퍼가 접미사를 갖는 이유는 래퍼가 특이한 부분이기 때문입니다. 저장소는 다른 모든 도구가 기대하는 이름을 유지합니다.
도구
저는 이 컨벤션을 스캐폴딩(scaffolds)하는 작은 CLI를 작성했습니다: repoyard. 이 도구는 의존성이 전혀 없으며, Node 20 이상을 요구하고, 세 가지 명령어를 제공합니다:
npx repoyard create myapp # greenfield: 워크스페이스 + 내부의 새로운 Git 저장소 생성
npx repoyard adopt # 기존 저장소를 감싸기 (wrap)
npx repoyard doctor # 컨벤션(convention)에 따라 워크스페이스 점검
대부분의 프로젝트는 이미 존재하기 때문에, adopt가 아마 여러분이 가장 자주 사용하게 될 명령어일 것입니다.
깨끗한 저장소의 루트(root)에서 실행하면, 형제(sibling) 워크스페이스를 생성하고, 동일 파일 시스템 내의 이름 변경(rename)을 통해 저장소를 내부로 이동시킨 뒤, 워크스페이스 파일들을 스캐폴딩(scaffold)합니다. 만약 어떤 과정이라도 실패하면, 이동 작업을 자동으로 롤백(roll back)합니다. 완료되면 새로운 위치로 이동하기 위한 cd 명령어를 출력합니다.
대화형(interactively)으로 실행하면 화살표 키 메뉴를 통해 원하는 작업을 묻습니다. 스크립트로 작성하려면 --no-input을, 아무것도 건드리지 않고 계획만 출력하려면 --dry-run을 전달하세요. 이 컨벤션은 Claude 전용이 아니므로, --agent-file=claude|agents|both|none을 전달하여 CLAUDE.md 대신 또는 CLAUDE.md와 함께 AGENTS.md를 스캐폴딩할 수 있습니다.
제가 처음으로 adopt한 저장소는 repoyard 자체였습니다. 이제 이 도구는 자신이 스캐폴딩한 레이아웃(layout) 내부에서 실행됩니다. 기분에 따라 이것이 훌륭한 도그푸딩(dogfooding)인지, 아니면 뱀이 자신의 꼬리를 먹는 격인지 판단될 것입니다.
네, 이것은 기본적으로 mkdir입니다
이 모든 것을 수동으로 설정하는 데는 30초도 걸리지 않을 것입니다. 이 도구는 그렇지 않은 척하지 않습니다.
여러분이 얻는 것은 코드화된 컨벤션(codified convention)입니다. 즉, 명명 규칙(naming), 지속적인 노트(durable notes)와 일회성 연습 작업(disposable scratch work) 사이의 구분, 그리고 상위 디렉토리를 읽는 모든 도구에게 레이아웃을 설명해 주는 에이전트용 지침 파일(agent-facing instruction file)입니다.
컨벤션은 여러분과 여러분의 에이전트, 그리고 다른 기계들이 별도로 생각할 필요 없이 모두 동일한 작업을 수행할 때 그 가치를 발휘합니다. 시스템 콜(syscalls)은 결코 어려운 부분이 아니었습니다.
이 도구는 또한 의도적으로 완성된 상태로 유지됩니다. 설정 파일, 플러그인 시스템, 프레임워크 템플릿, 텔레메트리(telemetry), 또는 업데이트 확인 기능은 없습니다. 워크트리(Worktrees)는 이미 워크스페이스 내부에서 잘 작동합니다:
git worktree add ../myapp-wip
Repoyard 역시 그 영역에 관여하지 않습니다. 1.0 버전 이후의 아이디어들은 단순히 존재하는 것이 아니라, 구체적인 문제를 해결해야 합니다.
만약 이러한 실패 모드로 인해 어려움을 겪은 적이 있거나, 혹은 그런 일이 결코 일어나지 않기를 바란다면, github.com/ddyy/repoyard에서 프로젝트를 찾아보거나, 임시 디렉토리 (scratch directory)에서 npx repoyard를 실행하여 직접 테스트해 볼 수 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기