git worktree로 브랜치별 작업 디렉토리 분리하기
보통 Git 저장소를 clone하면 하나의 .git 디렉토리와 하나의 워킹 디렉토리를 가지고 작업한다. 이 디렉토리 안에서 브랜치를 바꾸고, 파일을 수정하고, 스테이징하고, 커밋하는데 일반적인 작업 흐름은 아래와 비슷하다.
git checkout main
git checkout -b feature/a
# 작업
git checkout main
git checkout -b feature/b
# 작업
문제는 하나의 디렉토리 안에서 브랜치를 계속 바꿔가며 작업한다는 점이다. 예를 들어 feature/a 브랜치에서 아직 커밋하지 않은 작업을 하고 있는데, 갑자기 main 기준으로 급한 수정이 필요할 수 있다. 이때 보통은 stash 기능을 사용한다.
git stash
git checkout main
git checkout -b hotfix
# 급한 작업
git checkout feature/a
git stash pop
하지만 이 방식은 stash가 여러 개 쌓이면 관리가 복잡해지고, 잘못된 stash를 꺼내거나 충돌이 생기는 경우도 있다. 그래서 브랜치를 자주 오가야 하거나, 동시에 여러 작업을 진행해야 하는 상황이라면 git worktree를 사용할 수 있다.
1. git worktree란?
git worktree는 하나의 Git 저장소에 여러 개의 실제 작업 디렉토리를 연결해서 사용할 수 있게 해주는 기능이다. 일반적인 Git 저장소는 하나의 저장소에 하나의 워킹 디렉토리를 가진다. 반면 git worktree를 사용하면 같은 저장소를 기준으로 여러 개의 워킹 디렉토리를 만들고 넘나들 수 있다.
project/
.git/
src/
package.json
project-feature-a/
src/
package.json
project-feature-b/
src/
package.json
여기서 project가 기존 저장소이고, project-feature-a, project-feature-b가 worktree로 분리된 작업 디렉토리다. 각 worktree는 같은 Git 저장소에 연결되어 있지만, 서로 다른 브랜치를 checkout한 독립적인 작업 디렉토리처럼 사용할 수 있다. 즉, 하나의 디렉토리 안에서 브랜치를 계속 바꾸는 것이 아니라 브랜치별로 작업 폴더를 따로 두는 방식이다.
2. 왜 git worktree를 사용할까?
기존에는 하나의 저장소 디렉토리 안에서 브랜치를 바꿔가며 작업하는 경우가 많았다. 예를 들어 feature/a 브랜치에서 작업 중인데 급하게 main 기준으로 hotfix를 해야 한다면 보통 아래처럼 처리한다.
git stash
git checkout main
git checkout -b hotfix
작업을 끝낸 뒤에는 다시 원래 브랜치로 돌아와서 stash를 복구한다.
git checkout feature/a
git stash pop
작업이 단순할 때는 이 방식도 충분하지만 작업 중인 파일이 많거나, stash가 여러 개 쌓여 있거나, 여러 브랜치를 동시에 확인해야 하는 상황에서는 점점 번거로워진다. 특히 아래와 같은 문제가 생길 수 있다.
- stash 목록이 많아져서 어떤 stash가 어떤 작업이었는지 헷갈린다.
- 잘못된 stash를 pop할 수 있다.
- stash pop 과정에서 충돌이 발생할 수 있다.
- 브랜치를 바꿀 때마다 작업 상태를 정리해야 한다.
git worktree를 사용하면 이런 상황에서 브랜치별로 작업 디렉토리를 분리할 수 있다. 예를 들어 feature/a는 project-feature-a 디렉토리에서 작업하고, hotfix는 project-hotfix 디렉토리에서 작업하는 식이다. 그러면 기존 작업 디렉토리를 건드리지 않고도 다른 브랜치 작업을 바로 진행할 수 있다.
3. AI 에이전트와 git worktree
git worktree 자체는 예전부터 존재하던 Git 기능이다. 다만 최근에는 AI 에이전트를 활용한 병렬 작업이 많아지면서 다시 자주 언급되고 있다. 예를 들어 여러 AI 에이전트에게 각각 다른 작업을 맡긴다고 해보자.
agent-a → feature/a 작업
agent-b → feature/b 작업
agent-c → refactor 작업
이때 하나의 작업 디렉토리를 공유하면 서로 파일을 덮어쓰거나, 브랜치 상태가 꼬이거나, 아직 커밋하지 않은 변경사항이 충돌할 수 있다. 반면 worktree를 사용하면 각 에이전트에게 서로 다른 작업 디렉토리를 줄 수 있다.
project-agent-a/
project-agent-b/
project-agent-c/
각 디렉토리는 같은 저장소를 기준으로 연결되어 있지만, 작업 공간은 분리되어 있다. 그래서 병렬 작업을 시키거나, 여러 브랜치를 동시에 열어두고 비교해야 할 때 유용하다.
4. 기본 사용법
현재 브랜치가 main이고, 이미 A, B 브랜치가 있다고 가정한다.
main
A
B
현재 main 브랜치에 checkout되어 있는 상태에서 B 브랜치를 별도 디렉토리로 분리하고 싶다면 아래처럼 실행한다.
git worktree add ../test-branch B
이 명령은 현재 저장소의 상위 디렉토리에 test-branch라는 새 디렉토리를 만들고, 그 디렉토리에서 B 브랜치를 checkout한다. 즉, 아래와 같은 의미다.
../test-branch 디렉토리를 만든다.
해당 디렉토리를 현재 Git 저장소의 worktree로 연결한다.
그 worktree에서 B 브랜치를 checkout한다.
이제 B 브랜치 작업을 하고 싶다면 기존 저장소에서 git checkout B를 하는 것이 아니라, 그냥 ../test-branch 디렉토리로 이동하면 된다.
cd ../test-branch
worktree로 분리된 브랜치는 이미 해당 디렉토리에서 checkout된 상태라고 보면 된다.
5. 브랜치명과 폴더명
worktree를 만들 때 폴더명과 브랜치명이 반드시 같을 필요는 없다. 예를 들어 아래 명령은 B 브랜치를 test-branch라는 폴더에 checkout한다.
git worktree add ../test-branch B
폴더명은 test-branch이고, checkout된 브랜치는 B다. 이미 존재하는 브랜치명을 경로로 그대로 사용하고 싶다면 아래처럼 쓸 수도 있다.
git worktree add ../B B
또는 브랜치명과 같은 이름의 디렉토리를 만들고 싶다면 상황에 따라 아래처럼 사용할 수 있다.
git worktree add ../<브랜치명>
이 경우 별도로 checkout할 브랜치나 커밋을 지정하지 않았기 때문에, Git은 경로의 마지막 이름을 기준으로 브랜치명을 잡는다. 예를 들어 현재 main 브랜치에서 아래 명령을 실행한다고 해보자.
git worktree add ../test-branch
그러면 test-branch라는 이름의 브랜치가 없을 경우, 현재 HEAD를 기준으로 test-branch 브랜치를 새로 만들고 해당 worktree에서 checkout한다. 즉, 현재 main에 있었다면 main의 현재 커밋을 기준으로 test-branch 브랜치가 만들어진다. 정리하면 다음과 같다.
# 기존 B 브랜치를 ../test-branch 디렉토리에서 checkout
git worktree add ../test-branch B
# 경로 이름을 기준으로 브랜치를 만들거나 checkout
git worktree add ../test-branch
# 폴더명과 브랜치명을 다르게 지정
git worktree add ../<사용할폴더명> <브랜치명>
6. 같은 브랜치는 동시에 두 worktree에서 checkout할 수 없다
git worktree를 사용할 때 가장 주의해야 할 점은 같은 브랜치를 동시에 두 개 이상의 worktree에서 checkout할 수 없다는 것이다. 예를 들어 현재 기존 저장소에서 main 브랜치에 checkout되어 있다고 하자. 이 상태에서 아래 명령을 실행하면 실패한다.
git worktree add ../test-branch main
왜냐하면 main 브랜치는 이미 기존 worktree에서 checkout되어 있기 때문이다. 이때는 아래와 비슷한 오류가 발생한다.
fatal: 'main' is already used by worktree at ...
즉, worktree는 브랜치별 작업 디렉토리를 분리해주는 기능이지만, 하나의 브랜치를 여러 작업 디렉토리에서 동시에 checkout하는 구조는 아니다. main 브랜치가 이미 기존 디렉토리에서 checkout되어 있다면, 새 worktree에서 다시 main 브랜치를 checkout할 수 없다.
7. 이미 checkout된 브랜치를 기준으로 새 브랜치 만들기
그렇다고 해서 main의 내용을 기준으로 새 worktree를 만들 수 없는 것은 아니다. 이미 checkout되어 있는 main 브랜치를 그대로 새 worktree에서 checkout할 수는 없지만, main을 기준으로 새로운 브랜치를 만들면서 worktree를 생성할 수는 있다.
git worktree add -b real-branch ../test-branch main
이 명령은 아래와 같은 의미다.
main 브랜치를 기준으로
real-branch라는 새 브랜치를 만들고
../test-branch 디렉토리에 worktree를 생성한 뒤
그 worktree에서 real-branch를 checkout한다.
즉, main을 직접 checkout하는 것이 아니라 main에서 새 브랜치를 따서 checkout하는 방식이다. main뿐만 아니라 다른 브랜치를 기준으로도 동일하게 사용할 수 있다.
git worktree add -b new-branch ../new-worktree base-branch
8. 브랜치 작업 없이 내용만 필요할 때
어떤 브랜치의 내용만 확인하고 싶고, 새 브랜치 작업을 할 필요가 없다면 detached HEAD 상태로 worktree를 만들 수도 있다.
git worktree add --detach ../test-branch main
이 명령은 main 브랜치의 현재 커밋을 기준으로 ../test-branch 디렉토리를 만들지만, 해당 worktree는 main 브랜치를 checkout한 상태가 아니다. 대신 main과 같은 커밋을 가리키는 detached HEAD 상태가 된다. 즉, 특정 브랜치의 파일 상태만 확인하거나 테스트용으로 잠깐 사용할 때 적합하다. 브랜치 작업을 이어갈 목적이라면 --detach보다는 새 브랜치를 만들어 사용하는 편이 낫다.
git worktree add -b real-branch ../test-branch main
9. worktree 목록 확인하기
현재 연결된 worktree 목록은 아래 명령으로 확인할 수 있다.
git worktree list
예를 들어 아래처럼 나올 수 있다.
/path/project abc1234 [main]
/path/test-branch def5678 [B]
이 출력은 현재 저장소에 어떤 worktree가 연결되어 있고, 각 worktree가 어떤 브랜치 또는 커밋을 보고 있는지 보여준다. worktree를 사용하다 보면 어떤 브랜치가 어느 디렉토리에 연결되어 있는지 헷갈릴 수 있으므로 자주 확인하는 것이 좋다.
10. worktree 제거하기
worktree를 제거할 때는 단순히 폴더를 삭제하는 것보다 git worktree remove를 사용하는 것이 좋다.
git worktree remove ../test-branch
이 명령은 worktree 연결 정보를 정리하고, 해당 worktree 디렉토리도 제거한다. 다만 기본적으로 git worktree remove는 정리된 상태의 worktree를 제거할 때 사용한다. 해당 worktree 안에 아직 커밋하지 않은 변경사항이나 추적되지 않는 파일이 있으면 제거가 거부될 수 있다. 이 경우 정말 삭제해도 되는 상태인지 먼저 확인해야 한다.
cd ../test-branch
git status
정말 강제로 제거해야 한다면 --force 옵션을 사용할 수 있다.
git worktree remove --force ../test-branch
다만 --force는 작업 중인 파일을 잃을 수 있으므로 신중하게 사용하는 것이 좋다. 주의할 점은 worktree를 제거한다고 해서 그 worktree에서 사용하던 브랜치가 삭제되는 것은 아니라는 점이다. 예를 들어 real-branch 브랜치를 checkout한 ../test-branch worktree를 제거해도 real-branch 브랜치 자체는 그대로 남아 있다.
worktree 제거
→ 작업 디렉토리와 worktree 연결 정보 제거
브랜치 삭제
→ 별도의 브랜치 삭제 명령 필요
즉, worktree는 브랜치 자체가 아니라 브랜치를 checkout해둔 작업 디렉토리 구조라고 보는 편이 이해하기 쉽다.
11. 폴더를 직접 삭제했다면 prune으로 정리하기
worktree 디렉토리를 수동으로 삭제하면 실제 파일은 사라질 수 있다. 하지만 Git 저장소 내부에는 해당 worktree에 대한 참조 정보가 남아 있을 수 있다. 이 경우 아래 명령으로 정리할 수 있다.
git worktree prune
prune은 실제 작업 디렉토리는 사라졌지만 Git 내부에 남아 있는 오래된 worktree 관리 정보를 정리한다. 현재 상태를 먼저 보고 싶다면 아래 명령을 사용한다.
git worktree list
목록에서 이미 사라진 worktree가 남아 있거나, 정리 가능한 상태로 표시된다면 prune으로 정리하면 된다. 하지만 다음부터는 가능하면 폴더를 직접 삭제하기보다 아래 명령을 사용하는 것이 낫다.
git worktree remove ../test-branch
12. worktree 디렉토리는 저장소 바깥에 만드는 것이 좋다
worktree 디렉토리는 기존 저장소 디렉토리 안에 만들 수도 있다. 하지만 보통은 기존 저장소 바깥에 만드는 편이 낫다. 예를 들어 기존 저장소가 아래 위치에 있다고 하자.
~/projects/my-app
그러면 worktree는 아래처럼 상위 디렉토리에 나란히 만드는 식이 좋다.
~/projects/my-app
~/projects/my-app-feature-a
~/projects/my-app-hotfix
명령어로는 아래처럼 작성할 수 있다.
git worktree add ../my-app-hotfix -b hotfix main
반대로 기존 저장소 내부에 worktree를 만들면 아래처럼 된다.
~/projects/my-app
~/projects/my-app/worktrees/hotfix
이렇게 만들 수도 있지만, 기존 저장소 안에 또 다른 작업 디렉토리가 생기므로 .gitignore에 추가해야 하는 번거로움이 생길 수 있다. 그래서 특별한 이유가 없다면 기존 저장소 바깥에 worktree 디렉토리를 만드는 편이 관리하기 쉽다.
13. .gitignore에 포함된 파일은 자동으로 생기지 않는다
git worktree는 현재 폴더를 그대로 복사하는 기능이 아니다. 특정 브랜치나 커밋을 별도 작업 디렉토리에 checkout하는 기능이다. 따라서 Git이 추적하지 않는 로컬 파일은 새 worktree에 자동으로 생기지 않는다. 예를 들어 프로젝트에 아래와 같은 파일들이 있다고 하자.
.env
node_modules/
dist/
그리고 이 파일들이 .gitignore에 포함되어 있다면, 새 worktree를 만들었을 때 자동으로 복사되지 않는다. 또한 현재 작업 디렉토리에 아직 커밋하지 않은 변경사항도 새 worktree로 복사되지 않는다. worktree는 현재 디렉토리의 파일 상태를 그대로 복제하는 기능이 아니라, 특정 브랜치나 커밋을 별도 작업 디렉토리에 checkout하는 기능이기 때문이다. 그래서 worktree를 만든 뒤에도 필요한 로컬 파일은 별도로 준비해야 한다. 예를 들어 .env 같은 파일이 필요하다면 직접 복사하거나, 프로젝트에 맞는 별도 스크립트를 만들어두는 편이 좋다.
cp .env ../my-app-hotfix/.env
또는 자주 필요한 파일이 있다면 간단한 스크립트로 처리할 수 있다.
#!/bin/bash
TARGET=$1
cp .env "$TARGET/.env"
사용 예시는 아래와 같다.
./copy-local-files.sh ../my-app-hotfix
프로젝트마다 필요한 로컬 파일이 다르기 때문에, worktree를 사용할 때는 이 부분을 미리 정리해두는 것이 좋다.
14. worktree로 분리한 브랜치에 접근하는 방식
worktree로 분리한 브랜치는 이미 해당 작업 디렉토리에서 checkout된 상태다. 그래서 다른 worktree에서 그 브랜치로 다시 checkout하려고 하면 안 된다. 예를 들어 B 브랜치를 ../test-branch worktree에 checkout했다고 하자.
git worktree add ../test-branch B
이제 기존 저장소 디렉토리에서 아래 명령을 실행하면 실패할 수 있다.
git checkout B
왜냐하면 B 브랜치는 이미 ../test-branch worktree에서 사용 중이기 때문이다. 이 경우 B 브랜치에 접근하는 방법은 checkout이 아니라 해당 디렉토리로 이동하는 것이다.
cd ../test-branch
즉, worktree를 사용하면 브랜치 접근 방식이 달라진다.
기존 방식
→ 같은 디렉토리에서 git checkout으로 브랜치 이동
worktree 방식
→ 브랜치별 디렉토리로 직접 이동
이 개념을 이해하지 못하면 “왜 checkout이 안 되지?”라고 헷갈릴 수 있다. worktree로 분리한 브랜치는 이미 다른 디렉토리에서 checkout되어 있는 상태라고 보면 된다.
15. worktree를 제거해야 다시 checkout할 수 있다
worktree에서 사용 중인 브랜치를 기존 저장소 디렉토리에서 다시 checkout하고 싶다면 먼저 해당 worktree를 제거해야 한다.
git worktree remove ../test-branch
그 후에는 기존 저장소에서 해당 브랜치를 checkout할 수 있다.
git checkout B
단순히 ../test-branch 폴더만 삭제하는 것은 권장하지 않는다. 폴더를 직접 삭제해도 Git 내부의 worktree 연결 정보가 남아 있을 수 있기 때문이다. 그래서 worktree를 정리할 때는 가능하면 아래 명령을 사용하자.
git worktree remove ../test-branch
만약 이미 폴더를 직접 삭제했다면 아래 명령으로 남은 정보를 정리한다.
git worktree prune
16. worktree의 단점
git worktree는 편리하지만 단점도 있다. 가장 큰 단점은 관리할 디렉토리가 늘어난다는 점이다. 브랜치별로 디렉토리가 생기기 때문에 프로젝트가 많아 보일 수 있고, 어떤 디렉토리가 어떤 브랜치인지 헷갈릴 수 있다. 또한 같은 프로젝트 파일이 여러 디렉토리에 존재하게 되므로 디스크 용량도 더 사용한다. 예를 들어 의존성 설치가 필요한 프로젝트라면 각 worktree마다 node_modules를 따로 설치해야 할 수도 있다.
my-app/
my-app-feature-a/
my-app-hotfix/
이런 구조가 편해지는 경우도 있지만, 반대로 관리 포인트가 늘어나는 경우도 있다. 그래서 단순히 브랜치를 가끔 바꾸는 정도라면 기존 checkout 방식이나 stash만으로도 충분할 수 있다. 하지만 여러 작업을 동시에 진행하거나, 브랜치 전환 비용이 크거나, AI 에이전트처럼 독립된 작업 환경을 여러 개 만들어야 한다면 worktree가 꽤 유용하다.
17. 자주 쓰는 명령어 정리
기존 브랜치를 새 worktree로 checkout한다.
git worktree add ../test-branch B
경로 이름을 기준으로 브랜치를 만들거나 checkout한다.
git worktree add ../test-branch
기준 브랜치에서 새 브랜치를 만들고 worktree를 생성한다.
git worktree add -b real-branch ../test-branch main
특정 브랜치의 커밋을 detached HEAD 상태로 checkout한다.
git worktree add --detach ../test-branch main
현재 worktree 목록을 확인한다.
git worktree list
worktree를 제거한다.
git worktree remove ../test-branch
수동 삭제 등으로 남은 worktree 관리 정보를 정리한다.
git worktree prune
18. 정리
git worktree는 하나의 Git 저장소에 여러 작업 디렉토리를 연결해서 사용할 수 있게 해주는 기능이다. 기존에는 하나의 디렉토리 안에서 브랜치를 바꿔가며 작업했다.
git checkout main
git checkout feature/a
git checkout feature/b
하지만 worktree를 사용하면 브랜치별로 작업 디렉토리를 분리할 수 있다.
my-app/ → main
my-app-feature-a/ → feature/a
my-app-feature-b/ → feature/b
핵심은 worktree가 브랜치를 복사하는 기능이 아니라, 특정 브랜치나 커밋을 별도의 작업 디렉토리에 checkout해두는 기능이라는 점이다. 그래서 worktree로 분리한 브랜치는 이미 해당 디렉토리에서 checkout된 상태다. 다른 디렉토리에서 같은 브랜치를 다시 checkout하려고 하면 실패할 수 있다. 접근 방식도 달라진다.
기존 방식
→ git checkout으로 브랜치 이동
worktree 방식
→ 브랜치가 checkout된 폴더로 직접 이동
그리고 worktree를 제거한다고 해서 브랜치가 삭제되는 것은 아니다.
git worktree remove
→ worktree 구조와 작업 디렉토리 제거
git branch -d
→ 브랜치 삭제
결론:
전환할 브랜치가 많지 않다
→ 기존 checkout 방식으로 충분하다.
작업 중인 상태를 잠깐 저장하고 다른 브랜치로 이동해야 한다
→ git stash를 사용할 수 있다.
여러 브랜치를 동시에 열어두고 독립적으로 작업하고 싶다
→ git worktree가 유용하다.
특히 AI 에이전트처럼 여러 작업 주체에게 독립된 작업 공간을 나눠줘야 한다면 git worktree를 고려해볼 만하다.