최근에 눈에 띈 블로그들이 있었다:
- "most devs ignore git worktree. here's why they're wrong"
- "Devs can no longer avoid learning Git worktree"
- "How I use git worktrees"
?? 오 저는 git worktree가 뭔지도 몰랐는데요,, ^_^ 알아보자.
Git Worktree란?
한 줄 요약부터 하자면:
같은 저장소(repo)를 여러 개의 폴더에 동시에 체크아웃해서 쓰는 기능.
기존에 우리가 git을 쓰는 방식은 대충 이런 느낌이다:
my-project/
├── .git/
└── src/ ← 여기서 checkout으로 브랜치를 갈아탐
폴더 하나에서 git checkout main, git checkout feature/login 왔다갔다 하면서 작업하는 구조. 브랜치를 바꾸면 같은 폴더의 파일 내용이 싹 바뀐다. IDE는 다시 인덱싱하고, 빌드 캐시는 날아가고, 흐름은 끊긴다. 작업하다가 브랜치를 변경하려면 stash 하거나 커밋을 해야하는 번거로움도 있다.
Worktree 방식은 이걸 뒤집는다:
`my-project/ ← main 브랜치
├── .git/
└── src/
my-project-hotfix/ ← hotfix 브랜치 (별도 폴더, 같은 repo)
└── src/
my-project-review/ ← 동료 PR 리뷰용
└── src/`
브랜치마다 자기만의 폴더를 가진다. 그런데 .git 내부(커밋 히스토리, 오브젝트 등)는 공유한다. clone을 여러 번 하는 것과는 다르다 — 디스크 공간도 훨씬 절약되고, 내부적으로 같은 저장소이기 때문에 브랜치 간 통신도 자유롭다.
기본 사용법
새 worktree 만들기
# 기존 브랜치를 새 폴더에 체크아웃
git worktree add ../hotfix hotfix
# 새 브랜치를 만들면서 폴더도 함께 생성
git worktree add -b feature/new-login ../new-login
목록 확인
git worktree list
# /Users/me/my-project abc1234 [main]
# /Users/me/my-project-hotfix def5678 [hotfix]
제거
git worktree remove ../hotfix
# 폴더를 수동으로 지웠다면
git worktree prune
브랜치 자체는 남아있으니 브랜치까지 지우려면 별도로:
git branch -D hotfix
Git Worktree 워크플로우 좀 더 구체적으로 정리
방법 1: 기존 브랜치만 체크아웃
# git worktree add <새 폴더 경로> <체크아웃할 브랜치>
git worktree add ../myapp-hotfix main
이 경우 main 브랜치를 ../myapp-hotfix 폴더에 그대로 체크아웃. 작업하려면 이후에 새 브랜치를 파는 게 좋음 (아래 5번 참조).
방법 2: 새 브랜치 생성 + 체크아웃 한 방에 ⭐ 추천
# git worktree add -b <새 브랜치명> <새 폴더 경로> <기반 브랜치>
git worktree add -b hotfix ../myapp-hotfix main
main에서 파생된 hotfix 브랜치를 만들면서 동시에 ../myapp-hotfix 폴더에 체크아웃. 한 줄로 끝.
전체 플로우
# 1. worktree 생성 (방법 2 추천)
git worktree add -b hotfix ../myapp-hotfix main
# 2. 새 폴더로 이동
cd ../myapp-hotfix
# 3. ★ IDE를 새 창으로 연다 ★
code . # VS Code
# 또는
idea . # IntelliJ
# 4. 새 IDE 창에서 확인
# - 창 제목에 hotfix 경로 표시되는지
# - 좌하단 브랜치 표시 "hotfix"인지
# 5. 방법 1로 만들었다면 여기서 브랜치 생성
# (방법 2로 만들었으면 이 단계 스킵)
git checkout -b hotfix
# 6. 수정, 커밋, 푸시, PR
git add .
git commit -m "fix: ..."
git push -u origin hotfix
gh pr create --base main
# 7. 작업 끝나면 정리
cd ../myapp-hotfix/.. # 또는 원래 폴더로
git worktree remove ../myapp-hotfix
git branch -D hotfix
기존 작업 폴더는 건드리지도 않는다. 새 터미널 창에서 다른 폴더 열고 딴 일 하는 것과 똑같다.
왜 이걸 써야 하냐
세 블로그가 공통적으로 지적하는 지점은 결국 하나다: 컨텍스트 스위칭 비용을 0에 가깝게 만든다는 것. 각자가 짚는 구체적인 상황이 조금씩 다른데, 그 시나리오들을 모아보자.
🔥 상황 1: 긴급 핫픽스
develop 브랜치에서 큰 리팩토링 중이다. 아직 커밋 못 한 변경사항이 가득. 그런데 prod에 긴급 버그 제보가 들어왔다.
기존 방식:
git stash # 작업 스태시
git checkout main # 메인 이동 (파일 싹 바뀜)
git pull
git checkout -b hotfix # 핫픽스 브랜치
# ... 수정, 커밋, PR
git checkout develop # 돌아옴
git stash pop # 스태시 복구 (운 좋으면 충돌 없음)
IDE 재인덱싱, 빌드 캐시 무효화, 머릿속 컨텍스트 증발. George가 글에서 한 표현 그대로 "sucked the life out of my flow" 다.
👀 상황 2: PR 리뷰
Bill Mill이 특히 강조하는 시나리오다. 동료 PR을 리뷰하려면 보통 그 브랜치를 체크아웃해서 직접 실행해봐야 하는데, 그 순간 내 작업은 멈춘다.
git worktree add ../myapp-review origin/feature/their-pr
cd ../myapp-review
# 빌드, 실행, 테스트 다 해봄
# 내 원래 폴더는 그대로 내 작업 진행
리뷰 끝나면 git worktree remove ../myapp-review로 청소. 흔적 없이 사라진다.
🧪 상황 3: 오래 걸리는 테스트/빌드와 병행 개발
# 현재 폴더에서 E2E 테스트 30분짜리 돌리고
npm run test:e2e &
# 다른 worktree에서 새 기능 개발
cd ../myapp-feature
# 테스트와 포트, 빌드 캐시 충돌 없이 개발
📌 상황 4: 메인 브랜치를 항상 손에 들고 있기
Bill Mill의 워크플로우 중 인상적이었던 부분. 그는 main 브랜치 전용 폴더를 상시 유지한다.
- 기능 작업 중에 "원래 main에선 이 부분이 어떻게 돼있었지?" 궁금할 때 → main 폴더에서 바로 grep
- 동료가 "이 기능 지금 어떻게 동작해?" 물어볼 때 → main 폴더 열어 확인
- 내 작업 브랜치는 건드리지 않고
git show main:path/to/file 같은 어색한 명령어를 외우지 않아도 된다. 그냥 폴더를 바꾸면 된다.
Worktree 주의점: untracked 파일은 안 넘어온다
앞서 소개한 블로그 중 3번째 글의 저자인 Bill Mill이 짚는 worktree의 가장 큰 실무 걸림돌이 나온다.
git worktree add는 git이 추적하는 파일만 체크아웃한다. 즉:
- node_modules/ ❌
- .env, .envrc ❌
- 빌드 산출물 (dist/, build/) ❌
- .vscode/settings.json (gitignore에 있다면) ❌
- 로컬 설정 파일들 ❌
Bill Mill은 "회사 레포에선 npm install이 2분이나 걸린다. worktree 만들 때마다 2분씩 기다려야 하면 나도 worktree 안 쓴다"고 솔직하게 말한다.
해결 방법들
1. pnpm 같은 패키지 매니저 사용
pnpm은 글로벌 스토어에 패키지를 두고 각 폴더엔 심볼릭 링크만 건다. 여러 worktree여도 디스크 중복 거의 없음.
2. 직접 복사 스크립트
Bill Mill은 자기만의 worktree 쉘 스크립트를 만들어 쓴다. 이 스크립트는:
- 브랜치 이름으로 폴더 이름을 자동 생성
- 새 브랜치 여부 자동 판단 (있으면 체크아웃, 없으면 생성)
- node_modules, .env 같은 untracked 파일을 copy-on-write로 복제
- 생성 후 해당 폴더로 자동 cd
. worktree new-feature
# → 폴더 생성, 의존성 복제, cd까지 한 번에
3. 심볼릭 링크
cd ../myapp-feature
ln -s ../myapp/node_modules ./node_modules
cp ../myapp/.env ./
간단하지만 브랜치별로 패키지가 다르면 꼬일 수 있어 주의.
4. Docker / devcontainer
환경 자체를 격리된 컨테이너로 두면 worktree가 더 가벼워진다.
실용 세팅 팁
프로젝트 폴더 구조
Bill Mill이 제안하는 구조가 꽤 합리적이다:
my-weather-app/ ← 프로젝트 루트 (그 자체는 repo가 아님)
├── main/ ← main 브랜치 worktree
├── update-node-deps/ ← 의존성 업데이트 작업
├── verify-user-input/ ← 기능 개발 중
└── hotfix-login-bug/ ← 핫픽스
각 폴더가 독립된 worktree. 루트 폴더는 단순한 컨테이너 역할.
IDE 열기
VS Code나 IntelliJ는 worktree마다 별도 창으로 여는 게 정답이다. 같은 창에서 폴더만 바꾸면 인덱스가 꼬인다.
cd ../myapp-feature code . # 새 VS Code 창
네이밍 컨벤션
터미널에서 식별 쉬우려면:
myapp/ # 메인 myapp.hotfix/ # 핫픽스 (접미사 .) myapp.review-pr-123/ # 리뷰용 myapp.feat-login/ # 기능 작업
언제 안 쓰는 게 좋냐
세 블로그 모두 "무조건 쓰라"고 하는데, 내 생각엔 항상 이득은 아니다.
Worktree가 오히려 부담되는 상황:
- 혼자 하는 작은 프로젝트: 브랜치 간 전환이 드물면 stash-checkout으로도 충분
- 의존성 설치가 엄청 무거운 프로젝트: 스크립트 없이 git worktree 쓰면 매번 고통
- 디스크 공간이 빠듯한 환경: 비록 .git은 공유해도 worktree마다 node_modules, 빌드 산출물은 따로 생김
- 엄격한 모노레포 / Turborepo: 캐시 공유 구조랑 맞물려 복잡도 올라갈 수 있음
그렇지만 일단 몇주간 회사에서 열심히 써보도록 하고 후기를 남기도록 하겠다.
'Dev Log' 카테고리의 다른 글
| GitHub PR이 생성됐는데 목록에 안 보이는 버그 (1) | 2026.05.10 |
|---|---|
| useEffect 꿀팁 (0) | 2026.05.03 |
| IntelliJ에서는 안 되고, Gradle에서는 되는 이유 (PKIX 에러 해결기) (0) | 2026.04.15 |
| 크롬 익스텐션 만들기 2 (1) | 2026.04.09 |
| Android WebView safe-area 이슈 대응 (Chromium 버전 변화 포함) (0) | 2026.04.05 |