본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 24. 08:42

AI가 병렬로 작업하기를 원하시나요? 먼저 각자에게 전용 작업 공간을 부여하세요

요약

여러 AI 에이전트가 동일한 프로젝트를 병렬로 편집할 때 발생하는 파일 충돌 문제를 해결하는 방법을 다룹니다. 물리적 복제(Clone)의 디스크 낭비 문제를 해결하기 위해 git worktree를 활용한 효율적인 작업 공간 격리 방안을 제시합니다.

핵심 포인트

  • 읽기 전용 작업은 공유 가능하지만, 파일 쓰기 작업은 반드시 격리가 필요함
  • 단순 프로젝트 클론 방식은 디스크 용량을 과도하게 점유하는 단점이 있음
  • git worktree를 사용하면 단일 .git을 공유하며 효율적으로 작업 공간을 격리할 수 있음
  • worktree 방식은 작업 완료 후 즉시 디스크 공간을 회수할 수 있어 경제적임

얼마 전 저는 병렬성(parallelism)—하나의 큰 작업을 가져와 이를 분할하고 여러 에이전트(agents)에게 동시에 퍼뜨리는 방식—에 대해 글을 쓴 적이 있습니다. 하지만 해결되지 않은 실타래를 남겨두었습니다. 여러 에이전트가 동시에 코드를 수정할 때, 서로의 작업을 망치지 않게 하는 방법은 무엇일까요? 이번 포스트가 바로 그 내용에 관한 것입니다.

제가 직접 맞닥뜨렸던 벽부터 시작하겠습니다. AI가 세션 내에서 스스로 생성하는 하위 에이전트(subagents)들은 사실 괜찮습니다. 그들은 자체적으로 격리(isolation)되어 작동하므로 크게 걱정할 필요가 없습니다. 저를 괴롭혔던 것은 다른 종류였습니다. 제가 수동으로 여러 개의 AI 터미널을 열고, 그것들이 동시에 동일한 프로젝트를 편집하도록 시켰을 때입니다. 여러 손이 동일한 작업 디렉토리(working directory)로 동시에 뻗어 들어가는 상황, 당신이 조금 쓰고 내가 조금 쓰면 파일이 서로 덮어쓰여지고 상태(state)는 엉망이 됩니다. 작업 중간쯤 가면 그 누구의 작업도 깨끗하게 남아있지 않게 됩니다.

내가 원하는 것, 그리고 하나의 경계

제가 원하는 것은 복잡하지 않습니다. 여러 개의 병렬적인 손들이 각자 자기 일을 하면서, 서로를 망치지 않고 동일한 프로젝트를 편집하는 것입니다.

하지만 미리 경계를 하나 정해두겠습니다. 모든 종류의 병렬성에 격리가 필요한 것은 아닙니다. 만약 제가 여러 에이전트를 보낸다면—한 명은 로그를 뒤지고, 한 명은 원인을 분석하고, 한 명은 문서를 훑어보는 식이라면—이들은 모두 읽기 전용(read-only)이므로 아무런 문제 없이 동일한 작업 공간(workspace)에 모여도 됩니다. 각자에게 땅을 나누어 줄 필요가 없습니다. 실제로 격리가 필요한 것은 파일에 쓰기(writes to files)를 수행하는 병렬성입니다. 읽기는 공유할 수 있지만, 쓰기는 분리되어야 합니다. 이것이 아래의 모든 논의를 위한 출발점입니다.

우회로: 처음에는 두 번 클론(clone)했습니다

두 개의 AI가 서로 간섭하지 않고 하나의 프로젝트를 편집하게 만들기 위해, 제가 처음 시도한 방법은 가장 어리석은 방법인 물리적 격리(physical isolation)였습니다. 프로젝트를 두 개의 별도 디렉토리에 클론(clone)하고, 복사본 하나당 AI 하나를 배정하여 각자 자기 일에만 집중하게 하는 것이었습니다.

깔끔하고, 정말로 깔끔합니다. 하지만 곧 저를 불편하게 만든 문제가 있었습니다. 바로 디스크(disk) 용량입니다. 제 프로젝트 중 상당수는 React 프론트엔드(frontend)와 Python 백엔드(backend)로 구성되어 있으며, 수많은 의존성(dependencies)이 쌓여 있습니다. 클론(clone) 하나당 수 기가바이트(GB)를 차지하죠. 두 번 클론하면 디스크의 큰 부분이 중복됩니다. 더 나쁜 점은, 이 "두 개의 복사본" 방식을 계속 유지하고 싶다면 두 복사본 모두 공간을 차지하며 계속 남아 있어야 한다는 것입니다. 이를 회수할 방법이 없습니다.

그때 저는 git worktree로 전환했습니다. 이 방식의 장점은 바로 그 고통스러운 지점을 해결해 준다는 것입니다. 여러 개의 워크트리(worktrees)가 단일 .git을 공유하므로, 전체 저장소(repo)와 히스토리(history)를 반복해서 복사할 필요가 없습니다. 또한 이는 일시적입니다. 작업이 완료되고 검증되면, 계속 유지해야 하는 클론과 달리 즉시 공간을 회수할 수 있습니다. 두 접근 방식 모두 격리 수준은 거의 비슷하지만, worktree는 디스크를 낭비하지 않습니다.

Physical clone vs git worktree: a physical clone copies the whole repo and its dependencies N times—disk multiplies, and it stays as long as you work this way; worktree shares one .git across working trees, only the working tree is new and temporary, reclaimed the moment you're done

두 가지 종류의 병렬성 — 누가 워크트리를 여는가

실제로 적용할 때는 두 가지 시나리오를 구분해야 합니다. 워크트리를 여는 방식이 다르기 때문입니다.

하나는 **세션 내의 서브에이전트 병렬성 (subagent parallelism within a session)**입니다. 이 방식은 가장 손이 덜 갑니다. 저는 AI에게 그냥 "병렬로 실행해"라고 말하기만 하면 됩니다. 그러면 AI가 스스로 작업을 나누고, 격리가 필요할 때 직접 워크트리를 엽니다. 제가 일일이 설명할 필요가 없습니다.

다른 하나는 제가 수동으로 여러 터미널(terminals)을 병렬로 여는 것입니다. AI는 기본적으로 이 사실을 알지 못합니다. 다른 AI가 지금 이 디렉토리를 건드리고 있다는 사실을 전혀 모릅니다. 그래서 저는 명시적으로 말해줘야 합니다: "이미 이 프로젝트 디렉토리를 편집 중인 다른 AI가 있습니다. 워크트리 모드(worktree mode)로 작업하세요." 제가 이를 지적하면, AI는 메인 워킹 트리(main working tree)로 바로 들어가는 대신 작업할 새로운 워크트리를 생성합니다.

매끄럽게 돌아가는 워크플로 (workflow)

격리는 첫 번째 단계일 뿐입니다. 작업 결과는 결국 다시 돌아와야 합니다. 저의 워크플로는 대략 다음과 같습니다:

실제로 분할 가능한 작업 라인을 따라 분할하세요. 지난 포스트와 마찬가지로, 느슨하게 결합된 (loosely coupled) 부분들을 선택하여 각각 별도의 워크트리 (worktree)로 보냅니다. 모든 작업이 완료되면, 리드 에이전트 (lead agent)가 하나씩 브랜치 (branch)로 다시 병합(merge)합니다. 하나를 병합하고 검증하며, 그 자리에서 문제를 수정합니다. 하나의 조각이 검증되면 해당 워크트리를 해제합니다.

만약 두 워크트리가 실제로 동일한 파일을 건드렸다면, 리드 에이전트가 개입하여 병합합니다. 하지만 솔직히 말해서 그런 일은 드뭅니다. 작업을 분할할 때 각 조각을 최대한 독립적으로 유지하기 때문입니다. 만약 두 조각이 충돌할 정도로 결합되어 있다면, 애초에 두 개의 작업으로 분할해서는 안 되는 것이었습니다.

The worktree pipeline: split the task along loosely coupled lines, send each into its own worktree to work, the lead agent merges them back one at a time—merge one, verify one, fix on the spot—then releases each worktree once it checks out

제가 겪었던 함정과 주의해야 할 함정들

가장 흔한 함정은 정리(clean up)하는 것을 잊는 것입니다. 삭제하는 것을 잊은 워크트리는 그저 그 자리에 남아 공간을 차지합니다. 하지만 치명적인 것은 아닙니다. 해당 기능은 이미 오래전에 트렁크 (trunk)에 병합되었으므로, 잃어버린 것이나 이름 충돌, 엉망이 된 git 상태 같은 것은 없습니다. 그저 공간을 차지할 뿐입니다.

그렇더라도 "공간을 차지하는 것"은 처리가 필요합니다. 저는 저의 글로벌 규칙 (global rules)에 한 줄을 적어 넣었습니다: 워크트리의 작업이 검증되고 문제없이 병합되면, 정리하라. 또한 안전장치도 추가했습니다. 해제하기 전에, 해당 워크트리의 모든 커밋 (commit)이 실제로 트렁크에 반영되었는지 다시 한번 확인하여, 성급한 손길이 병합되지 않은 기능을 통째로 쓸어버리지 않도록 하는 것입니다. 더 강력한 AI는 이러한 인식과 정리를 스스로 처리합니다. 반면 더 약한 AI는 이를 놓치는 경향이 있으며, 이 경우 제가 지켜보거나 리드 에이전트를 다시 불러 처리하게 해야 합니다.

지금까지 실수로 유용한 워크트리를 삭제한 적은 없습니다. 모든 정리 작업 전에 수행하는 "커밋 확인" 단계가 기본적으로 방어선을 지켜주었습니다. 하지만 사람이 수동으로 정리할 때는 그 확인 단계가 사라지므로, 병합되지 않은 작업을 잃을 수 있습니다. 그 부분은 직접 주의 깊게 살펴봐야 합니다.

강요하지 마세요, 하지만 한 줄이 버팀목이 됩니다

worktree를 만능 해결사로 취급해서도 안 됩니다. 전체 기능(feature)이 아니라 단순한 작업이나 몇 개의 파일만 변경하는 경우라면, worktree를 여는 것은 과유불급입니다. 그냥 하나의 워크스페이스(workspace)에서 변경하고 끝내면 됩니다.

하지만 제가 절대 타협하지 않는 한 가지 원칙이 있습니다. 바로 trunk(메인 줄기)에서 직접 작업하지 마세요. 모든 변경 사항은 새로운 브랜치(branch)에서 시작되어 검증을 거친 후, PR(Pull Request)을 통해 trunk로 돌아가야 합니다. worktree를 사용하든 단일 브랜치를 사용하든, 두 방법 모두 trunk를 항상 깨끗하고 신뢰할 수 있는 복사본으로 유지한다는 이 원칙을 따릅니다.

마지막으로, 다시 worktree 자체로 돌아가 보겠습니다. 누군가는 비웃을지도 모릅니다. "이건 이미 몇 년 전부터 있었던 git 기능인데, 대체 무슨 이야깃거리가 더 있다는 거지?"라고 말이죠. 맞습니다. 오래된 기능입니다. 하지만 AI가 병렬로 작업하는 이 새로운 환경에서, 이 기능은 "여러 손이 동시에 하나의 프로젝트를 편집하는" 실제 문제를 진정으로 해결해주며, 예전보다 훨씬 더 큰 비중을 차지하게 되었습니다. 오래된 나무가 새로운 가지를 뻗어내는 것이라고 불러도 좋겠네요.

다음 포스트에서는 조금 다른 주제를 다뤄보고 싶습니다. AI는 이토록 유능하고 우리를 위해 많은 업무를 짊어질 수 있는데, 왜 우리는 하루 일과가 끝날 때 여전히 녹초가 되어 있을까요? 어디서부터 잘못된 걸까요? 관심이 있다면 댓글로 알려주세요.

AI 자동 생성 콘텐츠

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

원문 바로가기
0

댓글

0