Git Worktree로 작업 효율성 높이기
Git Worktree로 작업 효율성 높이기
Git Worktree란?
Git Worktree는 하나의 저장소에서 여러 브랜치를 동시에 체크아웃할 수 있게 해주는 Git의 강력한 기능입니다. 일반적으로 Git 저장소는 한 번에 하나의 브랜치만 체크아웃할 수 있지만, worktree를 사용하면 여러 작업 디렉토리를 만들어 각각 다른 브랜치에서 작업할 수 있습니다.
모든 worktree는 동일한 .git 디렉토리를 공유하므로, 저장소를 여러 번 클론할 필요 없이 효율적으로 여러 작업을 병렬로 진행할 수 있습니다.
기존 방식의 한계와 불편함
Worktree를 사용하지 않을 때 여러 작업을 전환하려면 stash, checkout 등의 명령어를 반복적으로 사용해야 합니다. 실제 시나리오를 통해 이런 불편함을 살펴보겠습니다.
시나리오: 기능 개발 중 긴급 수정 요청 발생
새로운 기능을 개발하는 feature/user-service 브랜치에서 작업 중이라고 가정해봅시다.
# feature/user-service 브랜치에서 작업 중
$ git checkout feature/user-service
$ vim user_handler.go # 코드 수정 중...
이때 갑자기 운영팀에서 긴급 버그 수정 요청이 들어왔습니다. 기존 방식으로는 다음과 같은 절차를 거쳐야 합니다.
# 1. 현재 작업 내용을 stash에 임시 저장
$ git stash save "WIP: user service refactoring"
Saved working directory and index state On feature/user-service: WIP: user service refactoring
# 2. main 브랜치로 이동
$ git checkout main
Switched to branch 'main'
# 3. 긴급 수정을 위한 새 브랜치 생성
$ git checkout -b hotfix/auth-panic
Switched to a new branch 'hotfix/auth-panic'
# 4. 버그 수정 작업
$ vim auth.go
$ git add auth.go
$ git commit -m "Fix nil pointer panic in auth middleware"
# 5. main에 머지
$ git checkout main
$ git merge hotfix/auth-panic
# 6. 다시 원래 작업으로 돌아가기
$ git checkout feature/user-service
# 7. stash했던 작업 내용 복원
$ git stash pop
# 충돌이 발생할 수 있음!
문제점
컨텍스트 스위칭 오버헤드: 브랜치를 전환할 때마다 작업 디렉토리의 파일들이 변경되어 IDE나 빌드 시스템이 재로딩되어야 합니다.
Stash 관리의 복잡성: stash가 쌓이면 어떤 stash가 어떤 작업인지 추적하기 어렵습니다.
$ git stash list
stash@{0}: On feature/user-service: WIP: user service refactoring
stash@{1}: On feature/api-v2: WIP: API v2 migration
stash@{2}: On feature/monitoring: WIP: add prometheus metrics
Stash 충돌 가능성:
git stash pop을 할 때 다른 변경사항과 충돌이 발생할 수 있습니다.빌드 아티팩트 문제: 브랜치를 전환하면 빌드된 바이너리나 캐시 파일들이 불일치할 수 있어 클린 빌드가 필요합니다.
테스트 실행의 어려움: 두 브랜치의 코드를 동시에 비교하거나 테스트하려면 여러 번 브랜치를 오가야 합니다.
Git Worktree로 개선하기
같은 시나리오를 worktree로 처리해봅시다.
초기 설정
# 메인 저장소
$ cd ~/projects/myapp
# 현재 feature/user-service에서 작업 중
$ git branch
* feature/user-service
main
Worktree를 사용한 긴급 수정
# 1. 긴급 수정을 위한 별도 worktree 생성
$ git worktree add ../myapp-hotfix main
Preparing worktree (checking out 'main')
HEAD is now at a1b2c3d Latest stable release
# 2. 새로운 디렉토리로 이동하여 작업
$ cd ../myapp-hotfix
$ git checkout -b hotfix/auth-panic
$ vim auth.go
$ git add auth.go
$ git commit -m "Fix nil pointer panic in auth middleware"
$ git push origin hotfix/auth-panic
# 3. 원래 작업 디렉토리로 돌아가기
$ cd ../myapp
# 작업 내용이 그대로 유지됨! stash 불필요
$ vim user_handler.go # 바로 작업 재개 가능
동시에 여러 작업 진행
# 프로젝트 루트
$ cd ~/projects/myapp
# 현재 worktree 목록 확인
$ git worktree list
/home/user/projects/myapp a1b2c3d [feature/user-service]
/home/user/projects/myapp-hotfix a1b2c3d [hotfix/auth-panic]
# 코드 리뷰를 위한 또 다른 worktree 추가
$ git worktree add ../myapp-review feature/api-v2
$ cd ../myapp-review
# 코드 리뷰 진행...
# 메인 작업 디렉토리
$ cd ~/projects
$ ls -la
drwxr-xr-x myapp/ # feature/user-service
drwxr-xr-x myapp-hotfix/ # hotfix/auth-panic
drwxr-xr-x myapp-review/ # feature/api-v2
Worktree vs 기존 방식 비교
| 측면 | 기존 방식 (stash/checkout) | Worktree |
|---|---|---|
| 브랜치 전환 | 파일 시스템 변경 발생 | 디렉토리 이동만 하면 됨 |
| 작업 보존 | stash 필요 | 자동으로 보존됨 |
| 동시 작업 | 불가능 (순차적) | 여러 브랜치 동시 작업 가능 |
| IDE 로딩 | 브랜치마다 재로딩 | 각 디렉토리별 독립 세션 |
| 빌드 상태 | 브랜치 전환 시 재빌드 필요 | 각 worktree가 독립적인 빌드 상태 유지 |
| 테스트/비교 | 브랜치 전환 반복 필요 | 동시에 열어서 비교 가능 |
| 디스크 사용량 | 적음 | 각 worktree마다 작업 디렉토리 필요 |
실전 활용 팁
1. Worktree 명명 규칙
일관된 명명 규칙을 사용하면 관리가 쉬워집니다.
# 브랜치 이름을 반영한 명명
$ git worktree add ../myapp-feature-user feature/user-service
# 또는 작업 타입별로 구분
$ git worktree add ../myapp-hotfix hotfix/critical-bug
$ git worktree add ../myapp-review feature/code-review
2. 임시 작업용 Worktree
빠른 테스트나 확인이 필요할 때 임시 worktree를 만들 수 있습니다.
# 특정 커밋 체크아웃
$ git worktree add --detach ../myapp-temp a1b2c3d
# 작업 완료 후 삭제
$ git worktree remove ../myapp-temp
3. Worktree 정리
# 현재 worktree 목록 확인
$ git worktree list
# 특정 worktree 제거
$ git worktree remove ../myapp-hotfix
# 또는 디렉토리를 직접 삭제한 후 정리
$ rm -rf ../myapp-hotfix
$ git worktree prune # 참조 정리
4. 각 Worktree에서 독립적인 환경 설정
각 worktree는 독립적인 작업 디렉토리이므로 서로 다른 설정을 가질 수 있습니다.
# 메인 worktree: 개발 환경
$ cd ~/projects/myapp
$ export ENV=development
$ go run main.go
# hotfix worktree: 프로덕션 유사 환경
$ cd ~/projects/myapp-hotfix
$ export ENV=production
$ go build -o app
$ ./app
주의사항
- 브랜치 중복 체크아웃 불가: 같은 브랜치를 여러 worktree에 동시에 체크아웃할 수 없습니다.
$ git worktree add ../myapp-test main
fatal: 'main' is already checked out at '/home/user/projects/myapp-hotfix'
디스크 공간: 각 worktree는 전체 작업 디렉토리를 가지므로 대용량 프로젝트에서는 디스크 공간을 고려해야 합니다.
Worktree 삭제 시 주의: worktree를 삭제하기 전에 커밋하지 않은 변경사항이 없는지 확인하세요.
실제 개발 워크플로우 예시
Go 애플리케이션 개발에서 worktree를 활용하는 실제 시나리오입니다.
# 프로젝트 구조
~/projects/
├── myapp/ # main 브랜치 (안정 버전)
├── myapp-feature-user/ # 사용자 서비스 개발
├── myapp-feature-api/ # API 리팩토링
└── myapp-hotfix/ # 긴급 수정용
# 1. 메인 개발 작업
$ cd ~/projects/myapp-feature-user
$ vim internal/user/handler.go
$ go test ./...
# 2. 동시에 다른 터미널에서 API 작업
$ cd ~/projects/myapp-feature-api
$ vim api/v2/router.go
$ go test -v ./api/...
# 3. 긴급 버그 발생 시
$ cd ~/projects/myapp-hotfix
$ git pull origin main
$ git checkout -b hotfix/urgent-fix
$ vim middleware/auth.go
$ go test ./middleware
$ git commit -am "Fix authentication middleware panic"
$ git push origin hotfix/urgent-fix
# 4. 다시 원래 작업으로 즉시 복귀
$ cd ~/projects/myapp-feature-user
# 모든 작업 내용이 그대로 유지됨
Go 모듈 캐시 공유
Go는 모듈 캐시를 $GOPATH/pkg/mod에 저장하므로, 모든 worktree가 자동으로 같은 캐시를 공유합니다.
# 각 worktree에서 의존성을 다시 다운로드할 필요 없음
$ cd ~/projects/myapp-feature-user
$ go mod download # 한 번만 실행하면 됨
$ cd ~/projects/myapp-hotfix
# 이미 캐시된 모듈 사용
$ go build # 빠른 빌드
독립적인 바이너리 빌드
각 worktree에서 독립적으로 바이너리를 빌드하고 실행할 수 있습니다.
# feature 브랜치: 개발 중인 새 기능 테스트
$ cd ~/projects/myapp-feature-user
$ go build -o myapp-dev
$ ./myapp-dev &
# hotfix 브랜치: 수정된 버전 테스트
$ cd ~/projects/myapp-hotfix
$ go build -o myapp-hotfix
$ ./myapp-hotfix &
# 두 버전을 동시에 실행하여 비교 테스트 가능
결론
Git Worktree는 특히 다음과 같은 상황에서 매우 유용합니다:
- 긴급 수정과 기능 개발을 병행해야 할 때
- 여러 버전의 코드를 동시에 테스트하거나 비교해야 할 때
- 코드 리뷰를 위해 다른 브랜치를 확인하면서 현재 작업을 유지하고 싶을 때
- 대규모 리팩토링 작업과 일반 개발을 분리하고 싶을 때
stash와 checkout을 반복하는 기존 방식에서 벗어나 worktree를 활용하면 작업 효율성을 크게 높일 수 있습니다. 각 작업을 독립적으로 유지하면서도 빠르게 전환할 수 있는 worktree의 장점을 활용해보세요.