git worktree로 Claude Code와 Codex를 한 저장소에서 동시에 돌리기
한 사람이 Claude Code와 Codex CLI를 같은 프로젝트에 동시에 붙여도 서로의 작업을 덮어쓰지 않도록, git worktree로 작업 공간을 나누는 방법과 실제로 부딪히는 함정(Codex 샌드박스 커밋 실패, .env·node_modules, 포트, 잠긴 worktree)을 정리했습니다.
Claude Code에게 API 리팩터링을 맡겨 두고 기다리는 동안 Codex에게 UI 작업을 시키고 싶을 때가 있습니다. 그런데 두 에이전트를 같은 디렉터리에서 실행하면 문제가 금방 생깁니다.
- 한쪽이 파일을 고치는 중에 다른 쪽이 같은 파일을 읽고 덮어씁니다.
- 한쪽이
git checkout이나git stash를 하면 다른 쪽의 작업 중인 변경이 사라지거나 섞입니다. - 테스트·빌드 결과가 누구의 변경 때문인지 알 수 없습니다.
해결책은 단순합니다. 에이전트마다 별도의 작업 디렉터리와 브랜치를 주는 것입니다. 저장소를 여러 번 clone해도 되지만, git에는 이 용도에 딱 맞는 기능인 git worktree가 있습니다. 이 글은 한 사람이 Claude Code와 Codex CLI를 동시에 쓰는 상황을 기준으로, 실제로 확인한 동작과 함정을 정리합니다.
테스트 환경: Claude Code 2.1.289, codex-cli 0.160.0, git 2.43 (Linux). CLI 동작은 버전에 따라 바뀔 수 있습니다.
1. git worktree란
일반적인 저장소는 .git(저장소 데이터) 하나에 작업 디렉터리 하나가 붙어 있습니다. worktree는 .git은 하나로 공유하면서 작업 디렉터리를 여러 개 붙이는 기능입니다.
clone을 여러 번 하는 것과 비교하면 다음이 다릅니다.
git clone 여러 번 | git worktree | |
|---|---|---|
| 디스크 | 저장소 데이터가 통째로 복제 | 객체는 공유, 작업 파일만 추가 |
| 브랜치·커밋 공유 | push/fetch를 거쳐야 함 | 즉시 보임 (같은 .git) |
| 같은 브랜치 동시 체크아웃 | 가능 (사고 원인) | git이 거부 |
마지막 줄이 중요합니다. git은 한 브랜치를 두 worktree에서 동시에 체크아웃하지 못하게 막습니다.
$ git worktree add ../proj2 worktree-api
fatal: 'worktree-api' is already used by worktree at '.../proj/.claude/worktrees/api'두 에이전트가 실수로 같은 브랜치에서 일하는 상황을 git이 원천적으로 차단해 주는 셈입니다.
2. 수동으로 worktree 만들기
원리를 이해하기 위해 먼저 손으로 만들어 봅니다.
cd ~/work/proj
# 새 브랜치와 함께 worktree 생성 (경로는 저장소 밖 형제 디렉터리 권장)
git worktree add ../proj-claude -b feat/api-refactor
git worktree add ../proj-codex -b feat/ui-polish
git worktree list
# /home/me/work/proj a1b2c3d [main]
# /home/me/work/proj-claude a1b2c3d [feat/api-refactor]
# /home/me/work/proj-codex a1b2c3d [feat/ui-polish]각 디렉터리에서 에이전트를 실행하면 끝입니다.
(cd ../proj-claude && claude)
(cd ../proj-codex && codex) # 또는 codex -C ../proj-codex3. CLI 내장 worktree 기능
두 CLI 모두 worktree를 직접 만들어 주는 옵션이 있습니다. 다만 만드는 위치와 브랜치 처리 방식이 다르므로 차이를 알고 써야 합니다.
Claude Code: claude -w <name>
cd ~/work/proj
claude -w api # worktree 생성 후 그 안에서 세션 시작
claude -w api --tmux # tmux 세션까지 함께 생성실제로 만들어지는 것은 다음과 같습니다.
- 경로:
<repo>/.claude/worktrees/<name> - 브랜치:
worktree-<name>(현재 HEAD에서 분기) - 세션이 쓰는 동안 worktree에 lock이 걸립니다 (
git worktree list에locked표시).
worktree가 저장소 안에 생기므로, 메인 작업 디렉터리의 git status에 ?? .claude/가 보입니다. .gitignore에 추가해 두세요.
.claude/worktrees/Codex: codex --worktree
cd ~/work/proj
codex --worktree # 대화형
codex exec --worktree "README 오타 수정" # 비대화형- 경로:
~/.codex/worktrees/<id>/<repo>(저장소 밖) - 브랜치: 없음 (detached HEAD)
Codex worktree는 브랜치 없이 시작합니다. 작업 결과를 남기려면 먼저 브랜치를 만들어야 합니다.
cd ~/.codex/worktrees/<id>/proj
git switch -c codex/ui-polish4. 가장 큰 문제: Codex 샌드박스에서 커밋 실패
Codex의 기본 샌드박스(workspace-write)에서 worktree 안의 커밋을 시도하면 다음처럼 실패합니다.
fatal: Unable to create '/home/me/work/proj/.git/worktrees/proj/index.lock': Read-only file system원인은 worktree의 구조에 있습니다. worktree 안의 .git은 디렉터리가 아니라 원본 저장소의 .git/worktrees/<name>을 가리키는 파일입니다. 인덱스·HEAD 같은 git 메타데이터는 원본 저장소 쪽에 기록되는데, Codex 샌드박스는 그 경로를 읽기 전용으로 둡니다. --add-dir <repo>/.git으로 쓰기 경로를 추가해도 .git은 계속 보호되어 HEAD.lock 생성이 실패하는 것을 확인했습니다.
현실적인 선택지는 셋입니다.
- Codex는 코드만 고치고, 커밋은 사람이 합니다. (권장) 리뷰를 겸할 수 있어서 오히려 낫습니다.
- 대화형 모드에서 Codex가 샌드박스 밖 실행 승인을 요청하면 git 명령에 한해 승인합니다.
--sandbox danger-full-access. 컨테이너·VM처럼 바깥이 이미 격리된 환경에서만 고려합니다.
Claude Code는 기본적으로 샌드박스가 아니라 권한 승인 방식으로 동작하므로 worktree 안에서 커밋이 정상적으로 됩니다.
5. worktree마다 따로 챙겨야 하는 것
worktree는 git이 추적하는 파일만 체크아웃합니다. .gitignore 대상은 새 worktree에 없습니다. Node.js 프로젝트 기준으로 다음을 챙겨야 합니다.
.env 같은 비밀 파일 — Claude Code는 저장소 루트의 .worktreeinclude에 적힌 gitignore 대상 파일을 새 worktree로 복사해 줍니다.
# .worktreeinclude
.env
.env.localCodex worktree에는 이런 기능이 없으므로 직접 복사합니다.
cp ~/work/proj/.env ~/.codex/worktrees/<id>/proj/의존성 — worktree마다 npm ci를 실행합니다. 메인의 node_modules를 심볼릭 링크로 공유하면 브랜치마다 lock 파일이 달라질 때 원인을 찾기 어려운 오류가 납니다.
dev 서버 포트 — 두 에이전트가 각자 dev 서버를 띄우면 포트가 겹칩니다.
PORT=3001 npm run dev # Claude worktree
PORT=3002 npm run dev # Codex worktree에이전트 지시 파일(CLAUDE.md, AGENTS.md)에 "이 worktree에서는 3001 포트를 쓴다"처럼 적어 두면 에이전트가 알아서 지킵니다.
빌드 캐시 — .next, dist, target 같은 산출물은 worktree마다 따로 생깁니다. 디스크를 생각보다 많이 쓰므로 끝난 worktree는 바로 정리합니다.
6. 충돌을 줄이는 작업 분배
worktree가 막아 주는 것은 작업 중의 파일 충돌뿐입니다. 두 브랜치가 같은 파일의 같은 부분을 고치면 머지할 때 충돌은 그대로 발생합니다. 그래서 일을 나누는 방식이 중요합니다.
디렉터리·모듈 단위로 나눕니다. 기능 단위로 나누면 두 에이전트가 공통 유틸·타입 파일을 동시에 고치기 쉽습니다.
| 에이전트 | 담당 | 손대지 않음 |
|---|---|---|
| Claude Code | src/app/api/**, src/lib/** | src/components/** |
| Codex | src/components/**, 스타일 | src/app/api/** |
공용 파일은 한쪽만 고칩니다. package.json, lock 파일, 라우팅·설정 파일처럼 자주 충돌하는 파일은 담당을 하나로 정합니다. 다른 쪽이 의존성이 필요하면 메모로 남기게 하고, 사람이 반영합니다.
규칙 파일은 하나로 둡니다. Codex는 AGENTS.md를, Claude Code는 CLAUDE.md를 읽습니다. 공통 규칙은 AGENTS.md에 쓰고, CLAUDE.md에서는 import만 하면 두 에이전트가 같은 규칙을 따릅니다.
<!-- CLAUDE.md -->
@AGENTS.md작업 지시에 범위를 명시합니다. "검색 API에 페이지네이션 추가. src/app/api/search/**와 src/lib/search/**만 수정하고, 그 밖의 파일이 필요하면 수정하지 말고 알려줘"처럼 경계를 적어 주면 침범이 크게 줄어듭니다.
7. 통합: 교차 리뷰 → 충돌 사전 확인 → 머지
교차 리뷰. 한 모델이 만든 코드를 다른 모델에게 리뷰시키면, 같은 모델이 스스로 검토할 때 놓치는 부분이 잘 드러납니다.
# Claude가 만든 브랜치를 Codex로 리뷰
cd ~/work/proj/.claude/worktrees/api && codex review --base main
# Codex가 만든 브랜치를 Claude로 리뷰 (커밋 전이면 codex review --uncommitted 도 가능)
cd ~/.codex/worktrees/<id>/proj && claude "main 대비 이 브랜치 변경을 리뷰해줘"충돌 사전 확인. 실제로 머지하지 않고도 충돌 여부를 알 수 있습니다(git 2.38+).
git merge-tree --write-tree main worktree-api && echo "충돌 없음"
git merge-tree --write-tree main codex/ui-polish && echo "충돌 없음"종료 코드가 0이 아니면 충돌이 있는 것이고, 출력에 충돌 파일 목록이 나옵니다.
머지 순서. 작고 먼저 끝난 브랜치부터 main에 넣고, 나머지 브랜치는 git rebase main 후 테스트를 다시 돌린 다음 머지합니다. 충돌 해결이 필요하면 그 브랜치를 만든 에이전트에게 맡기는 편이 맥락이 남아 있어 빠릅니다.
8. 정리하기
git worktree list
# Codex worktree
git worktree remove ~/.codex/worktrees/<id>/proj
# Claude worktree: 세션 lock이 남아 있으면 remove가 거부된다
git worktree remove .claude/worktrees/api
# fatal: cannot remove a locked working tree, lock reason: claude session api (pid …)
git worktree unlock .claude/worktrees/api
git worktree remove .claude/worktrees/api
git branch -d worktree-api # 머지된 브랜치 삭제
git worktree prune # 디렉터리를 직접 지운 경우 메타데이터 정리Claude 세션이 비정상 종료되면 lock이 남는 경우가 있습니다. lock 사유에 pid가 적혀 있으므로, 해당 프로세스가 살아 있지 않은지 확인한 뒤 unlock합니다.
9. 실전 레이아웃: tmux 한 화면에 묶기
worktree는 tmux로 Claude Code·Codex 세션 유지하기와 잘 맞습니다. window 하나에 에이전트 하나를 두면 SSH가 끊겨도 양쪽 작업이 계속 돌아갑니다.
cd ~/work/proj
tmux new -d -s dev -n claude 'claude -w api'
tmux new-window -t dev -n codex 'codex --worktree'
tmux new-window -t dev -n main # 사람이 리뷰·머지하는 창
tmux attach -t dev체크리스트
-
.gitignore에.claude/worktrees/추가 -
.worktreeinclude에.env등록 (Codex worktree는 수동 복사) - worktree마다
npm ci, dev 서버 포트 분리 - Codex worktree는
git switch -c로 브랜치부터 생성, 커밋은 사람이 - 담당 디렉터리를 나누고 공용 파일(
package.json, lock)은 한쪽만 - 공통 규칙은
AGENTS.md,CLAUDE.md는@AGENTS.mdimport - 교차 리뷰 →
git merge-tree→ 작은 브랜치부터 머지 - 끝난 worktree는
unlock→remove→branch -d
worktree는 에이전트를 "동시에" 돌리게 해 주지만, "충돌 없이" 끝나게 해 주는 것은 결국 작업 분배와 머지 순서입니다. 다음 글에서는 이 방식을 여러 사람이 각자의 Claude·Codex로 협업하는 팀 단위로 확장하는 방법을 다루겠습니다.