워크트리는 만들기는 쉽고 잊어버리기도 쉽다. 에이전트가 브랜치를 격리된 환경에서 작업할 수 있도록 하나 만들어 주고, 에이전트가 작업을 마치면 diff를 검토하고, 그러고 나면 그 디렉터리는 그냥 거기 남아 있다. 일주일 뒤에는 git worktree list가 화면을 넘어가고, 저장소에 du -sh를 실행하면 12기가바이트가 나오며, 그중 세 개는 며칠 전에 이미 병합되고 삭제된 브랜치를 가리키고 있다. 아무도 이것들을 남겨두기로 선택하지 않았다. 만드는 건 명령 한 줄이었지만 정리하는 건 귀찮은 일이었기 때문에 쌓여만 갔다.
이것이 병렬 에이전트 작업에서 아무도 경고해주지 않는 부분이다. 격리 프리미티브는 잘 문서화되어 있다. AI 코딩 에이전트를 위한 git worktrees 가이드에서는 생성과 브랜치 메커니즘을 깊이 있게 다룬다. '완료' 이후의 라이프사이클이 바로 고통이 도사리는 곳이며, 워크트리를 만드는 주체가 1분에 다섯 개를 열어젖히고 정리할 본능은 없는 에이전트일 때 상황은 빠르게 나빠진다. 이 글은 그 뒷부분에 관한 것이다. 정리 규율, 정확한 명령어, 각 단계에서 도사리는 실패 모드, 그리고 직접 만든 스크립트가 더 이상 충분하지 않게 되는 지점 말이다.
Sharkly는 "누가 정리하는가"라는 문제에 대한 하나의 답이다. Sharkly는 모든 Task를 자체 워크트리에서 실행하며, 그 워크트리를 사용자가 기억해야 하는 디렉터리가 아니라 Task 라이프사이클의 일부로 취급한다. 이 이야기는 뒤에서 다루겠다. 먼저 메커니즘부터 살펴보자. 손으로 하기를 그만두기로 결정하기 전에, 수동 방식이 어떻게 돌아가는지 이해하고 있어야 하니까.

TL;DR
git 워크트리는 하나의 저장소에 연결된 두 번째 작업 디렉터리로, 자체 브랜치와 인덱스, 그리고 HEAD를 가진다. 에이전트는 실행할 때마다 격리를 원하지만 그중 어느 것도 스스로 뒷정리를 하지 않기 때문에 워크트리가 쌓여만 간다. 정리 절차는 네 개의 명령어로 이루어진다. git worktree list로 무엇이 존재하는지 확인하고, git worktree remove로 끝난 워크트리를 삭제하고, git worktree prune으로 오래된 메타데이터를 정리하고, git worktree lock으로 남겨두고 싶은 워크트리를 보호한다. 각 단계를 건너뛰면 고아가 된 디렉터리, 유실된 작업, 잠긴 브랜치 같은 실패 모드가 나타난다. 워크트리가 몇 개뿐일 때는 수동 방식으로 충분하다. 그 이상이 되면 각 워크트리를 태스크 레코드에 묶어 정리 작업에 주인이 생기게 하라. Sharkly가 자동으로 하는 일이 바로 이것이다.
에이전트와 함께라면 워크트리가 더 빨리 쌓이는 이유
워크트리에는 사람이 자연스럽게 관리하는 라이프사이클이 있다. 만들고, 작업하고, 병합하고, 삭제한다. 문제는 삭제 단계가 사람의 기억에 의존한다는 점이다. 에이전트는 이 가정을 두 방향에서 동시에 무너뜨린다.
첫째는 양이다. 개발자 한 명이 에이전트 네 개를 병렬로 돌리면 하루에 하나가 아니라 한 시간에 워크트리 네 개를 만드는 셈이다. 여러 Claude Code 에이전트를 병렬로 실행하기 글에서 이 수치가 왜 이렇게 빠르게 치솟는지 자세히 다룬다. 둘째는 정리 본능의 부재다. 에이전트는 태스크를 읽고, 작업을 하고, 결과를 쓰고, 멈춘다. "브랜치가 병합됐으니 이 디렉터리는 이제 짐이다"라고 생각하지 않는다. 그래서 디렉터리들은 자기 쓸모보다 오래 살아남고, 그 생존자들이 문제다. 삭제된 브랜치 위에 남은 낡은 체크아웃, 에이전트가 중도 포기한 미완성 실험, 그리고 각 디렉터리마다 디스크를 잡아먹는 중복된 node_modules 트리 말이다.
비용은 추상적인 것이 아니다. 워크트리 하나는 전체 체크아웃에 더해 에이전트가 그 안에 설치한 온갖 것들로 이루어진다. 중간 규모 JavaScript 저장소에 워크트리 열 개가 있다면 node_modules 디렉터리도 열 개다. 디스크가 차고, git status는 전체 집합에 걸쳐 느려지고, 다음 사람이 git worktree list를 실행해도 어떤 디렉터리가 살아 있는 작업이고 어떤 게 잔해인지 알 수 없다.
단계별 정리 절차
전체 라이프사이클은 네 개의 명령어로 정리된다. 이 순서대로 실행하면 실패 모드는 닫힌 채로 유지된다.
무엇이 존재하는지 확인한다. 모든 정리 작업은 여기서 시작한다:
git worktree list
# /repo a1b2c3d [main]
# /repo-auth-refactor 4d5e6f7 [auth-refactor]
# /repo-fix-logging 8g9h0i1 [fix-logging]
이 단계를 건너뛰었을 때의 실패 모드: 잘못된 디렉터리를 삭제하게 된다. 비슷한 이름의 브랜치에서 돌아가는 두 에이전트는 비슷한 이름의 워크트리 경로를 만들어내고, 살아 있는 쪽을 제거하면 커밋되지 않은 작업을 잃게 된다. 무엇이든 건드리기 전에 목록을 꼼꼼히 읽어라.
끝난 워크트리를 제거한다. 워크트리의 브랜치가 병합되었고 그 안에 지저분한 것이 없다는 걸 확인했다면:
git worktree remove /repo-fix-logging
실패 모드: remove는 워크트리에 커밋되지 않은 변경 사항이나 추적되지 않는 파일이 있으면 거부한다. 이는 안전한 기본 동작이다. 위험한 행동은 오류를 없애려고 --force를 집어 드는 것이다. 지저분한 워크트리에 force를 쓰면 에이전트가 만들어냈지만 커밋하지 않은 진짜 작업이 삭제된다. remove가 불평한다면 먼저 그 디렉터리를 살펴봐라. 그 불평은 대개 옳다.
오래된 메타데이터를 prune한다. 워크트리 디렉터리를 git worktree remove 대신 rm -rf로 삭제했다면, git은 여전히 그에 대한 관리 기록을 보관하고 있다. 이것이 전형적인 고아다:
git worktree prune
git worktree prune --dry-run # preview first
실패 모드: prune을 건너뛰면 git worktree list에 유령 항목이 남고, 더 나쁘게는 git이 아직 어딘가에서 체크아웃되어 있다고 생각하는 브랜치를 재사용하기를 거부할 수 있다. prune은 이 기록을 정리한다. 무엇을 버릴지 실제로 버리기 전에 확인할 수 있도록 --dry-run을 먼저 실행하라. git worktree 문서는 prune이 무엇을 오래된 것으로 간주하는지 정확히 설명한다.
남겨두고 싶은 것은 잠근다. 느린 외장 드라이브에 있는 워크트리, 또는 장기 실행 실험을 담고 있는 워크트리는 공격적인 정리 스크립트가 prune해서는 안 된다:
git worktree lock /repo-experiment --reason "release repro, keep until 2.0 ships"
실패 모드: 잠금이 없으면 "오래된" 것은 무엇이든 prune하는 야간 정리 작업이 당신이 일부러 남겨둔 워크트리를 제거할 수 있다. 잠금과 이유 문자열은 신뢰할 수 있는 정리 스크립트와, 중요한 걸 먹어치운 뒤 비활성화하게 되는 정리 스크립트 사이의 차이다.
정리 스크립트가 확장을 멈추는 지점
네 단계 모두 자동화할 수 있다. 워크트리를 나열하고, 각 브랜치를 병합된 이력과 대조하고, 병합된 것들을 제거하는 cron 작업은 셸 서른 줄이면 된다. 이건 작동하며, 에이전트 몇 개를 돌리는 1인 개발자에게는 충분하다. 워크트리 수가 적고 저장소의 주인이 한 명일 때는 스크립트를 써라.
확장이 멈추는 지점은 처리량이 아니라 판단이다. 스크립트는 브랜치가 병합되었다는 건 알아낼 수 있다. 하지만 워크트리가 아직 검토하지 않은 에이전트의 커밋되지 않은 작업을 담고 있다거나, "오래된" 브랜치가 사실 누군가 재개하려는 일시 중지된 태스크라거나 하는 건 알아낼 수 없다. 정리가 워크트리의 의도를 파악하는 일이 되는 순간, git 상태만 보는 규칙은 결국 중요했던 무언가를 삭제하게 된다. 또 다른 한계는 조정이다. 공유 머신에서는 한 사람의 정리 스크립트가 다른 사람의 에이전트가 무엇을 하는지 알지 못하고, "이걸 제거해도 안전한가"라는 질문은 git worktree list만으로는 답할 수 없게 된다. 공유 머신 문제에 대해서는 병렬 AI 코딩 에이전트를 관리하는 도구 정리 글을 참고하라.
태스크 보드가 더해주는 것
해법은 모든 워크트리에 셸 세션보다 오래 사는 주인을 붙여주는 것이다. 각 워크트리를 태스크 레코드에 묶으면 정리는 "어떤 디렉터리가 오래돼 보이는가"가 아니라 "어떤 태스크가 완료되어 검토까지 끝났는가"가 된다.
여기가 Sharkly가 위치한 층이다. 이미 코딩 에이전트는 가지고 있다. Sharkly는 각 실행을 Task로 만들어 그것들을 팀으로 바꿔준다. Task가 시작되면 연결된 Computer의 로컬 서비스가 그 Task를 위한 격리된 워크트리를 준비한다. Task의 결과가 검토를 위해 돌아오고 사람이 이를 승인하면, 워크트리의 라이프사이클은 아무도 기억하지 못하는 디렉터리로 남는 대신 Task와 함께 끝난다. 워크트리가 결코 익명이 아니기 때문에 정리 질문에는 답이 있다.
역할 분담은 정직하게 유지된다. 에이전트는 태스크를 맡아 격리된 워크트리에서 작업하고, 테스트를 실행하고, diff를 반환한다. 사람은 방향을 정하고 병합 및 릴리스 단계를 결정한다. Sharkly는 Claude Code, Codex, 또는 위의 git 명령어를 대체하는 것이 아니다. 요청부터 릴리스까지 격리, 진행 상황, 결과, 정리가 터미널 곳곳에 흩어지지 않고 계속 보이도록 공유 기록을 더해줄 뿐이다. 에이전트 하나를 돌리면서 손으로 정리하는 데 10초밖에 안 걸린다면 아직 이게 필요하지 않다. 워크트리 목록이 화면을 넘어가기 시작하면 관리 문제가 진짜 문제이며, 에이전트 실행 전반에 걸쳐 사람을 루프 안에 두기 글에서 그 검토 측면을 다룬다.
오늘 바로 실행할 수 있는 체크리스트
에이전트가 작업해온 저장소라면 어디든 이 과정을 실행하라:
git worktree list를 실행하고 무엇이든 제거하기 전에 전체를 꼼꼼히 읽는다.- 끝난 워크트리마다: 브랜치가 병합됐는지 확인하고, 디렉터리가 깨끗한지 확인한 뒤
git worktree remove를 실행한다 (지저분한 트리에--force는 절대 쓰지 않는다). git worktree prune --dry-run으로 미리 확인하고 검토한 뒤,git worktree prune으로 고아가 된 메타데이터를 정리한다.- 일부러 남겨두는 워크트리는 이유 문자열과 함께
git worktree lock으로 잠근다. - 디스크를 확인한다. 워크트리 전체에 걸쳐
du -sh를 실행하고, 죽은 트리에서 중복된 의존성 설치를 삭제한다. - 하루에 한 번 이상 이 작업을 하고 있다면, 정리 스크립트 작성을 그만두고 각 워크트리에 Task 주인을 붙여라.
네 개의 명령어를 그대로 두고 손으로 실행해도 되고, 기존 코딩 에이전트를 Sharkly를 통해 실행해서 워크트리가 속한 Task와 함께 생성되고, 추적되고, 은퇴되게 할 수도 있다.



