본문으로 건너뛰기

© 2026 Molayo

Qiita헤드라인2026. 06. 23. 09:41

Claude Code의 '대기 시간'이 아까워서 worktree로 병렬 개발을 시도해 보았다

요약

Claude Code 사용 시 발생하는 대기 시간을 줄이기 위해 git worktree를 활용한 병렬 개발 방법을 소개합니다. 별도의 디렉토리에 브랜치를 전개하여 여러 Claude Code 세션을 동시에 운영하는 워크플로우를 다룹니다.

핵심 포인트

  • git worktree를 사용하여 동일 리포지토리의 브랜치를 별도 디렉토리에 동시 전개 가능
  • Claude Code의 `--worktree` 옵션을 통해 네이티브하게 병렬 작업 환경 구축
  • 생성된 worktree 디렉토리를 VS Code로 별도 오픈하여 시각적 병렬 작업 수행
  • 브랜치 전환 시 발생하는 작업 내용 보존 번거로움 해결

Claude Code에 작업을 맡겨두는 동안의 대기 시간, 꽤 길죠. 그 사이에 다른 작업도 진행하고 싶어져서, git worktree(작업 디렉토리를 분리하는 기능)를 사용한 병렬 개발을 시도해 보았습니다.

직접 해보니 생각보다 간단해서, "worktree를 만들고, 그 디렉토리를 VS Code로 다시 여는 것"만으로 병렬 작업 환경이 갖춰졌습니다.

이 기사에서는 그 절차를 중심으로 소개합니다. 아울러 도중에 알게 된 worktree의 주의점과, 제가 Dev Container로 열고 있는 덕분에 도움이 되고 있는 이야기도 적어두겠습니다.

보통 하나의 작업 디렉토리에서 여러 브랜치를 다루려고 하면, git checkout으로 브랜치를 전환할 때마다 작업 중인 변경 사항을 대피시켜야 해서 번거롭죠. 게다가 Claude Code에 무언가를 맡기고 있는 도중에 다른 브랜치로 전환하면, 그 작업까지 함께 휘말리게 됩니다.

그래서 git worktree를 사용하면, 동일한 리포지토리의 다른 브랜치를 별도의 디렉토리로서 동시에 전개할 수 있습니다. 한쪽의 Claude Code에는 기능 추가를 시키면서, 다른 쪽의 Claude Code로는 또 다른 기능을 진행하는 식의 병렬 작업이 가능해지는 것입니다. 둘 다 동일한 .git을 공유하고 있으므로, commit도 merge도 diff도 평소처럼 할 수 있습니다.

Claude Code는 git worktree를 네이티브로 지원합니다. 가장 간단한 방법은 실행 시 --worktree (약어는 -w)를 붙이는 방법입니다.

claude --worktree feature-login

이것만으로 리포지토리 루트의 .claude/worktrees/feature-login/에 worktree가 생성되고, 그 안에서 세션이 시작됩니다. 원래의 디렉토리는 더럽혀지지 않습니다. 이름을 생략하면 Claude가 bright-running-fox와 같은 이름을 알아서 붙여줍니다.

claude --worktree

다른 터미널에서 다시 한번 다른 이름으로 실행하면, 두 번째 병렬 세션이 됩니다.

claude --worktree feature-search

실행 중인 Claude Code에 "worktree로 작업해줘"라고 지시해도 만들어 줍니다. 그 경우에는 .claude/worktrees/agent-xxxxxxxx와 같은 이름의 디렉토리가 생성됩니다. 제 로컬 환경은 이런 상태였습니다.

$ git worktree list
/Users/me/work/myapp 816bae4 [dev]
/Users/me/work/myapp/.claude/worktrees/agent-xxxxxxxx 54c8bab [wip/feature-login]

본체는 dev인 상태로, 별도 디렉토리에 wip/feature-login이 전개되어 있습니다. Claude Code가 병렬 작업을 위해 worktree를 생성해 준 상태입니다.

위치나 브랜치를 직접 결정하고 싶을 때는 git을 직접 입력하는 것이 확실합니다.

git worktree add ../myapp-feature-login -b feature-login

이렇게 하면 ../myapp-feature-loginfeature-login 브랜치의 작업 디렉토리가 생깁니다.

이 부분이 제 방식의 핵심인데, 병렬 처리를 하고 싶어서 worktree를 만들면 그 디렉토리를 VS Code로 다시 엽니다. worktree는 단순한 디렉토리이므로, 열기만 하면 그 안에서 평소처럼 편집도 차이 확인(diff)도 할 수 있습니다.

code .claude/worktrees/agent-xxxxxxxx

본체 창은 그대로 남겨두고 worktree 창을 별도로 열면, 두 개의 브랜치를 두 개의 창으로 나란히 놓고 작업할 수 있습니다. CUI의 git worktree list만으로는 상태를 파악하기 어려우므로, 창을 나누어 두면 머릿속도 정리하기 쉽습니다.

참고로 저는 Dev Container로 프로젝트를 열고 있기 때문에, worktree 디렉토리를 다시 열면 그대로 worktree를 기준으로 컨테이너 안으로 들어가는 형태가 됩니다. 이것이 나중에 나올 리스크 이야기와 연결됩니다.

실제로 사용해 보면서 주의해야겠다고 느낀 점이 두 가지 있었습니다.

첫 번째는 베이스 브랜치 (base branch)의 동작입니다. Claude Code의 worktree는 기본적으로 원격의 origin/HEAD에서 분기되기 때문에, 현재 브랜치의 커밋되지 않은 변경 사항은 이어받지 않습니다. 현재 작업의 연속성부터 분기하고 싶을 때는 설정에서 worktree.baseRefhead로 변경해야 합니다.

{
"worktree": {
"baseRef": "head"
...

실제로 제 환경에서 테스트해 본 결과, 기본값(fresh) 상태에서는 worktree가 origin/HEAD의 커밋부터 시작되어 본체의 미커밋 변경 사항을 가져오지 않았습니다. 반면 baseRefhead로 설정하면, 현재의 HEAD에서 분기할 뿐만 아니라 본체 측의 미커밋 변경 사항(추적 파일의 변경)까지 worktree 측으로 이어받았습니다. 본체의 diff와 완전히 일치했으므로, 말 그대로 '현재 작업의 연속'부터 시작할 수 있는 동작입니다. 작업 중인 모든 것을 그대로 가져가고 싶을 때는 head 설정이 편리합니다.

두 번째는 git 관리 외의 파일이 복사되지 않는다는 점입니다. worktree는 새로운 체크아웃 (checkout)이므로 .envnode_modules는 따라오지 않습니다. "똑같아 보이는데 작동하지 않는다"는 현상은 대부분 이것이 원인입니다. 여기서 제가 고생했습니다...

이에 대해 Claude Code에는 .worktreeinclude라는 기능이 있습니다. 프로젝트 루트에 .gitignore와 동일한 형식으로 작성해 두면, 지정한 관리 외 파일을 worktree 생성 시 복사해 주는 기능입니다.

.env
.env.local
config/secrets.json

다만, 제 환경에서 테스트할 때 걸렸던 부분이 있습니다. 실행 중인 Claude에게 세션 내에서 worktree를 만들게 하는 경로(.claude/worktrees/agent-xxxxxxxx가 생성되는 방식)를 사용하면, .worktreeinclude에 작성한 파일이 복사되지 않았습니다. 아무래도 이 기능은 claude --worktree CLI 실행 경로를 위한 것으로 보이며, 세션 내에서 생성하는 경로에서는 작동하지 않을 가능성이 있습니다. 저처럼 VS Code 상에서 Claude에게 worktree 생성을 시키는 스타일이라면, .worktreeinclude에만 전적으로 의존하기보다 worktree 측에서 .env를 직접 준비한다는 전제로 접근하는 것이 안전해 보입니다.

node_modules와 같이 용량이 큰 것은 어차피 복사하는 것보다 worktree 측에서 npm install을 다시 하는 편이 더 현실적이었습니다.

또한, .claude/worktrees/.gitignore에 넣어두는 것도 중요합니다. 이를 하지 않으면 본체 측에서 git status를 했을 때 worktree의 내용이 쓰레기 데이터처럼 보이게 됩니다.

병렬 개발에 유용한 worktree이지만, 조사하던 도중 신경 쓰이는 글을 발견했습니다 (Claude Code가 Git Worktree를 엉망으로 망가뜨린 이야기).

핵심은 이렇습니다. worktree는 git의 작업 디렉토리를 나누는 메커니즘이지, 프로세스를 격리하는 샌드박스 (sandbox)가 아니라는 점입니다. 디렉토리는 분리되어 있어도 그곳에서 실행되는 프로세스는 일반적인 파일 권한을 가지므로, 상위 디렉토리나 옆에 있는 다른 worktree에도 접근할 수 있습니다.

해당 글의 재현 예시가 이해하기 쉬웠습니다. 빌드 스크립트 안에 출력 대상이 상위 디렉토리를 가리키는 상대 경로로 작성되어 있었습니다.

mkdir -p ../repo/published
echo "..." > ../repo/published/index.html

Claude Code는 다른 worktree 안에서 실행되고 있었음에도 불구하고, README에 적힌 대로 이 스크립트를 실행한 결과 ../repo, 즉 본체 측의 파일을 덮어써 버렸다는 이야기입니다. 해당 글에 따르면, 이 현상은 Opus, Sonnet, Haiku 모든 모델에서 발생했다고 합니다 (2026년 6월 16일 기준).

무서운 점은 Claude가 잘못을 저지른 것이 아니라는 점입니다. 사용자의 지시에 따라 README를 읽고, 적힌 절차를 순순히 실행했을 뿐이니까요. 사람이라면 "이 스크립트, 외부 파일에 쓰게 될 텐데?"라고 눈치챌 수 있었을 상대 경로(relative path)라도, 에이전트는 그대로 실행해 버립니다. worktree로 분리되어 있다는 시각적인 안도감이 오히려 방심을 불러오는 셈입니다.

만약을 위해 제 환경에서도 확인해 보았습니다. 테스트용 worktree를 만들고, 그 안에서 상대 경로를 이용해 본체 측 디렉토리에 써 보았더니 너무나 쉽게 성공해 버렸습니다. 본체 측에 파일이 제대로 나타납니다. worktree는 파일 시스템을 격리하지 않는다는 것은 기사의 내용과 같습니다. 한 가지 보충하자면, Claude Code가 만드는 worktree는 본체 리포지토리 내부(.claude/worktrees/<이름>/)에 위치하므로, 본체 루트에 도달하는 상대 경로는 기사의 예시(../repo)와 단계(depth)가 다릅니다. 배치에 따라 ../의 개수는 달라지겠지만, "외부에 쓸 수 있다"는 결론은 동일했습니다.

여기서 처음 이야기했던 "worktree를 VS Code로 다시 열기"로 돌아가겠습니다.

저는 Dev Container로 프로젝트를 열고 있기 때문에, worktree 디렉토리를 다시 열면 해당 컨테이너 안에서 Claude Code가 동작합니다. 컨테이너 내부에서는 호스트 측의 파일 시스템 중 마운트(mount)된 범위만 보입니다.

즉, 방금 본 기사와 같은 "상대 경로로 worktree 외부를 써버리는" 사고가 발생하더라도, 컨테이너 경계에서 멈춰줄 것이라는 기대가 있습니다. worktree 자체는 격리해 주지 않지만, Dev Container라는 레이어(layer)가 그 외부의 방파제 역할을 해준다는 이미지입니다.

다만, 이 부분은 솔직히 아직 컨테이너 내부에서 확실히 검증하지는 못했습니다 (경계를 넘는 쓰기 테스트는 호스트 직결 환경에서 수행한 것입니다). 컨테이너 안에서 동일한 시도를 했을 때 정말로 호스트 측으로 새어 나가지 않는지는 조만간 확인해 보려 합니다. 또한, 효과가 있을지는 마운트 설정에 따라 다르기도 합니다. 호스트 측을 넓게 마운트해 두었다면 그대로 통과해 버리므로, worktree마다 컨테이너를 연다면 마운트 범위를 해당 프로젝트로 한정해 두는 것이 좋을 것 같습니다.

Dev Container가 있다고는 하지만, 만약을 위해 다음 사항들은 해두어야겠다고 생각했습니다.

worktree에서 작업을 시키기 전에 반드시 본체 브랜치를 커밋(commit)하거나 푸시(push)해 둘 것. 사고가 나더라도 되돌릴 수 있는 상태를 만드는 것이 최우선입니다. 기사의 사고도 본체가 git restore .로 되돌릴 수 있었던 것은 커밋되지 않은 상태였기 때문이며, 만약 커밋된 상태였다면 훨씬 골치 아픈 상황이었을 것입니다.

그 외에는 worktree 측에서 실행되는 build나 test 스크립트에 ../를 통해 외부로 나가는 쓰기 작업이 없는지 미리 살펴볼 것, --dangerously-skip-permissions(권한 확인을 건너뛰는 플래그)를 자율 실행 시 안이하게 사용하지 않을 것, 이 정도겠네요.

병렬 개발을 위해 worktree를 만들고, 그 디렉토리를 VS Code로 다시 연다. 실제로 해보니 절차는 이것뿐이었고, 대기 시간을 다른 작업으로 채울 수 있다는 점은 상당히 쾌적했습니다.

한편, worktree는 격리 메커니즘이 아니라는 점은 염두에 두는 것이 좋아 보입니다. 이는 실제로 제 환경에서 worktree 내부로부터 본체 측에 쓸 수 있음을 확인했습니다. 디렉토리가 나누어져 있어도 그곳에서 동작하는 프로세스는 외부 파일을 건드릴 수 있습니다. 제 경우에는 Dev Container로 열고 있으므로 컨테이너가 방파제가 되어주기를 기대하고 있지만, 이 부분은 아직 완전히 검증되지 않았으므로 과신은 금물입니다. 그렇지 않은 환경이라면 본체를 수시로 커밋하거나 스크립트 내용을 확인하는 등의 대비가 필요할 것입니다.

당분간은 이 "worktree + Dev Container로 다시 열기" 스타일로 병렬 개발을 계속해 보려고 합니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0