1. 문제 상황
익숙한 시나리오
개발하다 보면 이런 상황을 자주 만납니다:
현재 상황: feature/new-dashboard 브랜치에서 대규모 리팩토링 중
갑자기: 프로덕션 버그 발생! main 브랜치에서 핫픽스 필요
문제: 작업 중인 변경사항이 수십 개 파일에 걸쳐 있음
기존 방식의 한계:
# 방법 1: stash 사용 - 복잡하고 위험
git stash push -m "WIP: dashboard refactoring"
git checkout main
# ... 핫픽스 작업 ...
git checkout feature/new-dashboard
git stash pop # ← 충돌 발생 가능!
# 방법 2: 커밋하기 - 지저분한 히스토리
git add .
git commit -m "WIP: incomplete work" # ← 나쁜 커밋 메시지
git checkout main
# ... 핫픽스 작업 ...
git checkout feature/new-dashboard
# 나중에 rebase로 정리해야 함
실제 발생하는 문제들
| 방식 | 문제점 |
|---|---|
git stash |
stash 충돌, 잊어버림, 복잡한 stash 목록 |
| WIP 커밋 | 지저분한 히스토리, rebase 필요 |
| 레포 복제 | 디스크 낭비, 설정 중복, 동기화 문제 |
# 레포 복제 방식의 문제
git clone repo ~/project-main
git clone repo ~/project-feature # ← 전체 히스토리 중복!
# 디스크 사용량 확인
du -sh ~/project-main/.git # 500MB
du -sh ~/project-feature/.git # 500MB ← 똑같이 500MB 낭비
2. Git Worktree란?
핵심 개념
Git Worktree는 하나의 .git 디렉토리를 공유하면서 여러 작업 디렉토리를 만드는 기능입니다.
# 기존 방식: 레포 복제
~/project-main/.git (500MB)
~/project-feature/.git (500MB)
총 1GB
# Worktree 방식: .git 공유
~/project/.git (500MB) ← 하나만!
~/project-feature/ (소스 파일만, 수 MB)
총 ~500MB
작동 원리
┌─────────────────────────────────────────────────────┐
│ .git 디렉토리 │
│ (커밋 히스토리, 객체, 설정 - 모든 worktree가 공유) │
└─────────────────────────────────────────────────────┘
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ Main Worktree │ │ Linked Worktree │
│ ~/project │ │ ~/project-feat │
│ (main branch) │ │ (feature branch)│
│ │ │ │
│ src/ │ │ src/ │
│ package.json │ │ package.json │
│ ... │ │ ... │
└─────────────────┘ └─────────────────┘
Worktree의 장점
# 1. 디스크 효율성
# .git 히스토리를 공유하므로 추가 용량이 거의 없음
# 2. 즉시 전환
# checkout 없이 다른 디렉토리로 이동만 하면 됨
cd ~/project-feature # ← 끝!
# 3. 동시 작업
# IDE 창 2개로 두 브랜치를 동시에 열어둘 수 있음
# 4. 빌드 캐시 유지
# 각 worktree가 독립된 node_modules, build 캐시 보유
~/project/node_modules # main용
~/project-feature/node_modules # feature용
3. Worktree 생성하기
기본 생성 명령어
# 기본 문법
git worktree add <경로> <브랜치>
# 예시: 기존 브랜치로 worktree 생성
git worktree add ../project-feature feature/new-dashboard
# └─ 새 디렉토리 └─ 기존 브랜치
# 예시: 새 브랜치 생성과 동시에 worktree 생성
git worktree add -b hotfix/urgent-fix ../project-hotfix main
# └─ 새 브랜치 생성 └─ 경로 └─ 기반 브랜치
실전 예시: PR 리뷰용 worktree
# 시나리오: PR #42를 로컬에서 테스트하고 싶음
# 1. 원격 브랜치 fetch
git fetch origin pull/42/head:pr-42
# 2. PR용 worktree 생성
git worktree add ../project-pr-42 pr-42
# 3. 해당 디렉토리에서 테스트
cd ../project-pr-42
npm install
npm test
# 4. 리뷰 완료 후 정리
cd ../project
git worktree remove ../project-pr-42
git branch -D pr-42
실전 예시: feature 브랜치 개발
# 현재 위치: ~/projects/my-app (main 브랜치)
# 1. feature 브랜치용 worktree 생성
git worktree add -b feat/check-usage ../my-app-check-usage main
# 결과:
# ~/projects/my-app ← main 브랜치 (기존)
# ~/projects/my-app-check-usage ← feat/check-usage 브랜치 (새로 생성)
# 2. feature 작업 시작
cd ../my-app-check-usage
code . # VS Code로 열기
# 3. 동시에 main에서 다른 작업 가능
cd ../my-app
# main 브랜치 작업...
네이밍 컨벤션
# 권장: 프로젝트명-브랜치설명
git worktree add ../my-app-feature-auth feat/auth
git worktree add ../my-app-hotfix-login hotfix/login
git worktree add ../my-app-pr-42 pr-42
# 또는: 프로젝트명-브랜치타입
git worktree add ../my-app-feat feat/new-feature
git worktree add ../my-app-fix hotfix/urgent
# 피해야 할 것
git worktree add ../temp feature # ← 모호함
git worktree add ../work feat # ← 구분 안됨
4. Worktree 관리하기
현재 worktree 목록 확인
git worktree list
출력 예시:
/Users/kim/projects/my-app abc1234 [main]
/Users/kim/projects/my-app-check-usage def5678 [feat/check-usage]
/Users/kim/projects/my-app-pr-42 ghi9012 [pr-42]
상세 정보 확인
git worktree list --porcelain
출력 예시:
worktree /Users/kim/projects/my-app
HEAD abc1234567890
branch refs/heads/main
worktree /Users/kim/projects/my-app-check-usage
HEAD def5678901234
branch refs/heads/feat/check-usage
Worktree 간 이동
# 단순히 디렉토리 이동
cd ../my-app-check-usage
# 또는 절대 경로
cd /Users/kim/projects/my-app-check-usage
# 팁: 자주 쓰는 worktree는 alias 설정
echo 'alias cdmain="cd ~/projects/my-app"' >> ~/.zshrc
echo 'alias cdfeat="cd ~/projects/my-app-check-usage"' >> ~/.zshrc
Worktree에서 브랜치 작업
# 각 worktree에서 평소처럼 git 명령어 사용
cd ../my-app-check-usage
git add .
git commit -m "feat: add new feature"
git push origin feat/check-usage
# 주의: 같은 브랜치를 두 worktree에서 동시에 checkout 불가!
git checkout main # ← 에러! main은 다른 worktree에서 사용 중
5. Worktree 정리하기
작업 완료 후 정리 프로세스
PR이 머지된 후의 전체 정리 플로우:
# 1. 메인 worktree에서 머지된 내용 pull
cd ~/projects/my-app
git pull origin main
# 2. worktree 제거
git worktree remove ../my-app-check-usage
# 또는 강제 제거 (uncommitted changes가 있을 때)
git worktree remove --force ../my-app-check-usage
# 3. 로컬 브랜치 삭제
git branch -d feat/check-usage
# 또는 강제 삭제 (머지되지 않은 브랜치)
git branch -D feat/check-usage
# 4. 원격 브랜치 삭제 (필요시)
git push origin --delete feat/check-usage
수동 삭제 후 정리
디렉토리를 직접 삭제한 경우:
# worktree 디렉토리 수동 삭제
rm -rf ../my-app-check-usage
# dangling worktree 참조 정리
git worktree prune
# 정리 확인
git worktree list
일괄 정리 스크립트
#!/bin/bash
# cleanup-worktrees.sh
# 머지된 브랜치의 worktree 정리
for worktree in $(git worktree list --porcelain | grep "^worktree" | cut -d' ' -f2); do
branch=$(git -C "$worktree" branch --show-current)
# main worktree는 스킵
if [ "$branch" = "main" ] || [ "$branch" = "master" ]; then
continue
fi
# 머지 여부 확인
if git branch --merged main | grep -q "$branch"; then
echo "Removing merged worktree: $worktree ($branch)"
git worktree remove "$worktree"
git branch -d "$branch"
fi
done
gone 브랜치 정리
원격에서 삭제된 브랜치(gone)와 연결된 worktree 정리:
# 원격 브랜치 정보 업데이트
git fetch --prune
# gone 상태인 브랜치 확인
git branch -vv | grep ': gone]'
# gone 브랜치들의 worktree 정리
git branch -vv | grep ': gone]' | awk '{print $1}' | while read branch; do
worktree=$(git worktree list | grep "\[$branch\]" | awk '{print $1}')
if [ -n "$worktree" ]; then
echo "Removing worktree for gone branch: $worktree"
git worktree remove "$worktree" 2>/dev/null || rm -rf "$worktree"
fi
git branch -D "$branch"
done
git worktree prune
6. 핵심 개념 정리
명령어 요약
| 명령어 | 설명 | 예시 |
|---|---|---|
git worktree add <path> <branch> |
기존 브랜치로 worktree 생성 | git worktree add ../proj-feat feature |
git worktree add -b <new-branch> <path> <base> |
새 브랜치 생성 + worktree | git worktree add -b fix ../proj-fix main |
git worktree list |
모든 worktree 목록 | - |
git worktree remove <path> |
worktree 제거 | git worktree remove ../proj-feat |
git worktree prune |
삭제된 worktree 참조 정리 | - |
git worktree move <path> <new-path> |
worktree 이동 | git worktree move ../old ../new |
git worktree lock <path> |
worktree 잠금 (prune 방지) | git worktree lock ../important |
git worktree unlock <path> |
worktree 잠금 해제 | git worktree unlock ../important |
Worktree vs 다른 방식 비교
| 방식 | 디스크 | 전환 속도 | 동시 작업 | 복잡도 |
|---|---|---|---|---|
git stash |
0 | 느림 | ❌ | 중간 |
git checkout |
0 | 느림 | ❌ | 낮음 |
| 레포 복제 | 높음 | 빠름 | ✅ | 낮음 |
| Worktree | 낮음 | 빠름 | ✅ | 중간 |
Worktree 제한사항
# 1. 같은 브랜치를 여러 worktree에서 checkout 불가
git worktree add ../another-main main
# error: 'main' is already checked out at '/Users/kim/projects/my-app'
# 해결: 다른 브랜치 사용 또는 detached HEAD
git worktree add --detach ../temp-main main
# 2. bare repository에서는 main worktree가 없음
git clone --bare repo.git
cd repo.git
git worktree add ../working main # ← 모든 작업을 worktree로
# 3. worktree 내에서 worktree 생성은 가능하지만 권장하지 않음
cd ../my-app-check-usage
git worktree add ../my-app-sub-feature # 가능하지만 혼란스러움
7. 베스트 프랙티스
Worktree 사용 체크리스트
✅ Worktree 생성 전
- [ ] 명확한 디렉토리 네이밍 규칙 정하기
- [ ] 프로젝트별 worktree 위치 통일 (예: 같은 부모 디렉토리)
- [ ] IDE 설정이 worktree별로 독립적인지 확인
✅ 작업 중
- [ ] 각 worktree에서 독립적으로 의존성 설치
- [ ] worktree 간 파일 복사 시 git 상태 확인
- [ ] 정기적으로 `git worktree list`로 현황 파악
✅ 정리 시
- [ ] PR 머지 후 즉시 worktree 정리
- [ ] 로컬/원격 브랜치 함께 삭제
- [ ] `git worktree prune`으로 찌꺼기 정리
IDE 설정 팁
# VS Code: 각 worktree를 별도 창으로
code ~/projects/my-app
code ~/projects/my-app-check-usage
# VS Code workspace로 관리
cat > ~/projects/my-app.code-workspace << 'EOF'
{
"folders": [
{ "path": "my-app", "name": "main" },
{ "path": "my-app-check-usage", "name": "feature" }
]
}
EOF
code ~/projects/my-app.code-workspace
Git alias 설정
# ~/.gitconfig에 추가
git config --global alias.wt 'worktree'
git config --global alias.wtl 'worktree list'
git config --global alias.wta 'worktree add'
git config --global alias.wtr 'worktree remove'
# 사용 예시
git wt list
git wta ../my-app-feat feat/new
git wtr ../my-app-feat
자동 정리 Git Hook
# .git/hooks/post-merge (PR 머지 후 자동 실행)
#!/bin/bash
# 머지된 브랜치 정리 알림
merged_branches=$(git branch --merged main | grep -v "^\*\|main\|master")
if [ -n "$merged_branches" ]; then
echo "🧹 다음 브랜치들이 머지되었습니다. 정리하세요:"
echo "$merged_branches"
echo ""
echo "정리 명령어:"
echo "git worktree list"
echo "git worktree remove <path>"
echo "git branch -d <branch>"
fi
8. FAQ
Q: Worktree와 submodule의 차이점은?
A: 완전히 다른 기능입니다.
# Worktree: 같은 레포의 다른 브랜치를 동시에 작업
git worktree add ../feature feat/new # 같은 레포!
# Submodule: 다른 레포를 현재 레포에 포함
git submodule add https://github.com/other/repo # 다른 레포!
Q: Worktree에서 npm install을 따로 해야 하나요?
A: 네, 각 worktree는 독립된 작업 디렉토리이므로 node_modules도 별도입니다.
cd ../my-app-check-usage
npm install # ← 필수!
# 장점: 브랜치별로 다른 의존성 버전 테스트 가능
# 단점: 디스크 사용량 증가, 설치 시간
Q: Worktree 디렉토리를 실수로 삭제했어요
A: git worktree prune으로 정리하면 됩니다.
# 삭제된 worktree 참조 정리
git worktree prune
# 확인
git worktree list
# 필요하면 다시 생성
git worktree add ../my-app-check-usage feat/check-usage
Q: 두 worktree에서 같은 파일을 수정하면 어떻게 되나요?
A: 각각 독립된 작업 디렉토리이므로 충돌 없이 수정 가능합니다. 단, 나중에 브랜치를 머지할 때 일반적인 merge conflict가 발생할 수 있습니다.
# worktree A (main)
echo "version A" > file.txt
git commit -am "Update from main"
# worktree B (feature)
echo "version B" > file.txt
git commit -am "Update from feature"
# 머지 시 충돌 발생 - 일반적인 git 워크플로우와 동일
git merge feature
# CONFLICT!
Q: Worktree를 다른 컴퓨터로 옮길 수 있나요?
A: Worktree는 절대 경로로 연결되어 있어서 직접 복사하면 안 됩니다. 다른 컴퓨터에서는 새로 생성하세요.
# ❌ 잘못된 방법
scp -r ../my-app-check-usage remote:/projects/
# ✅ 올바른 방법 (원격에서)
git worktree add ../my-app-check-usage feat/check-usage