한 번의 명령으로 얻는 안전망: 거대한 코드베이스에서 Git Worktree로 두려움 없이 실험하기
Git worktree를 활용해 대규모 코드베이스에서 추가 클론, 잦은 브랜치 전환, 위험한 stash 없이 안전하게 실험하고, 이를 일상적인 워크플로에 자연스럽게 녹여 넣는 방법을 알아보세요.
한 번의 명령으로 얻는 안전망: 거대한 코드베이스에서 Git Worktree로 두려움 없이 실험하기
거대한 코드베이스에서 일할 때, 작업을 전환하는 건 위험하고 비용이 많이 드는 일처럼 느껴집니다. 대규모 리팩터링을 절반쯤 진행하던 중에 프로덕션 버그가 터질 수 있죠. 이럴 때 어떻게 하나요?
- 지금까지의 변경을 stash 할까요?
- 반쯤 깨진 코드를 어쩔 수 없이 커밋할까요?
- 아예 레포를 한 번 더 clone하고, 또 한 번이나 되는 대규모 의존성 설치를 기다릴까요?
솔직히, 어느 쪽도 마음에 드는 선택지는 아닙니다.
Git worktree는 훨씬 나은 방법을 제공합니다. 하나의 레포지토리를 기반으로 하는 여러 개의 독립적인 작업 디렉터리를 가질 수 있게 해 주죠. 명령 하나만 더 치면, 메인 작업 디렉터리를 건드리지 않고도 실험, 버그 픽스, 코드 리뷰를 위한 안전한 샌드박스를 만들 수 있습니다.
이 글에서는 worktree가 무엇인지, 왜 대규모 코드베이스에서 특히 빛을 발하는지, 그리고 일상적인 개발 워크플로에 어떻게 녹여 쓸 수 있는지 살펴봅니다.
Git Worktree란 무엇인가?
Git worktree는 동일한 .git 레포지토리에 연결된 추가 작업 디렉터리입니다. 각 worktree는 보통 서로 다른 브랜치를 체크아웃해 두지만, 모두 같은 Git 오브젝트 데이터베이스를 공유합니다.
실제로는 이런 의미입니다:
- 여러 개의 브랜치를 동시에 체크아웃해 둘 수 있고, 각 브랜치는 자기 디렉터리에서 독립적으로 존재합니다.
- 모든 worktree는 동일한
.git히스토리와 오브젝트를 공유하므로, 레포를 중복해서 들고 있는 것이 아닙니다. - 각 worktree는 자기만의 독립된 파일 시스템 상태를 가집니다. 수정된 파일, 빌드 아티팩트, 로컬 설정 등이 모두 독립적입니다.
이것은 단순히 레포를 한 번 더 clone 하는 것과는 완전히 다른 개념입니다.
- 여러 개의 clone = 여러 개의
.git디렉터리, 중복된 히스토리, 반복되는git fetch/git pull, 그리고 자주 중복 설치되는 의존성 - 여러 개의 worktree = 하나의
.git디렉터리와 오브젝트 데이터베이스, 값싼 추가 디렉터리, 공유되는 히스토리
대규모 코드베이스에서 Worktree가 빛나는 이유
작은 프로젝트에서도 브랜치를 자꾸 바꾸는 건 번거롭습니다. 하지만 큰 프로젝트에서는 아예 워크플로를 망가뜨리기도 합니다.
1. 끝없는 브랜치 전환에서 해방
worktree를 쓰면, 기존에는 이렇게 했다면:
git checkout feature-x # 작업 # 앗, 버그 발생 git stash git checkout hotfix-branch # 버그 수정 git checkout feature-x git stash pop
이제는 이렇게 할 수 있습니다:
# 메인 작업 디렉터리: feature-x에서 작업 중 # hotfix용 별도 worktree 생성 $ git worktree add ../project-hotfix hotfix-branch $ cd ../project-hotfix # 여기서 독립적으로 버그 수정
두 브랜치는 각각의 디렉터리에서 동시에 체크아웃된 상태로 존재합니다. stash를 juggling 할 필요도 없고, 컨텍스트를 잃어버릴 일도 훨씬 줄어듭니다.
2. 위험한 stash와 작별
stash는 종종 “언젠가 보려고 넣어 두었지만, 뭐가 들어 있는지 잘 기억 안 나는” 변경들의 창고가 되곤 합니다. worktree를 사용하면 각 작업 라인을 숨겨진 stash 스택이 아니라 실제 디렉터리에 그대로 둘 수 있습니다.
- 각 실험은 고유한 worktree 디렉터리 안에서 살아 있습니다.
- “메인” 디렉터리(대개
main이나develop)는 늘 깨끗하고 믿을 수 있는 상태로 유지할 수 있습니다. - 어떤 stash에 뭐가 들어 있는지 기억하려 애쓸 필요도 없고, 실수로
git stash drop을 눌러 날려버릴 걱정도 크게 줄어듭니다.
3. 여러 번 clone 하는 비용 절감
대형 레포를 여러 번 clone 하면 이런 문제들이 생깁니다:
- clone 시점마다 네트워크 사용량과 시간이 많이 듭니다.
.git디렉터리가 복제되면서 디스크 공간을 크게 낭비합니다.- 의존성 설치(
node_modules, 빌드 아티팩트 등)를 clone마다 또 해야 합니다.
worktree는 이 문제를 우아하게 해결합니다.
- 레포는 하나,
.git스토리지는 하나입니다. - 추가 worktree는 대부분 작업 디렉터리의 파일들만 추가되며, Git 히스토리를 다시 복제하지 않습니다.
git fetch는 한 번만 해두면, 같은 커밋들을 여러 worktree에서 재활용할 수 있습니다.
4. 더 안전한 실험 환경
위험한 리팩터링을 스파이크로 시도해 보고 싶거나, 새로운 툴체인을 시험해 보고 싶거나, 프로토타입을 빠르게 만들어 보고 싶을 때:
- 새로운 worktree를 하나 만듭니다.
- 기본 작업 공간은 안정적이고 프로덕션 준비된 상태로 유지합니다.
- 실험이 별로였다면, 그 디렉터리 하나만 통째로 지워 버리면 됩니다.
특히 빌드, 마이그레이션, 도구 변경 비용이 큰 대규모 코드베이스에서는 “아이디어 하나당 샌드박스 하나”라는 모델이 엄청난 가치를 제공합니다.
시작하기: 기본 Worktree 명령어
모든 마법은 git worktree를 중심으로 돌아갑니다.
1. 기존 Worktree 목록 보기
git worktree list
출력 예시는 다음과 같습니다:
/path/to/project abc1234 [main] /path/to/project-feature def5678 [feature/cool-idea] /path/to/project-bugfix 9ab0123 [bugfix/login]
각 줄이 하나의 worktree를 의미합니다. 경로, 현재 커밋, 체크아웃된 브랜치가 표시됩니다.
2. 새 Worktree 만들기
기본 패턴은 다음과 같습니다:
git worktree add <path> <branch-or-commit>
자주 쓰는 패턴을 살펴보면:
-
main에서 새 기능 브랜치를 시작할 때:
$ cd /path/to/project $ git fetch origin $ git worktree add ../project-new-feature origin/main $ cd ../project-new-feature $ git switch -c feature/new-api -
기존 브랜치를 새 디렉터리에 체크아웃하고 싶을 때:
$ git worktree add ../project-bugfix bugfix/1234 -
특정 커밋 또는 태그 기준으로 작업하고 싶을 때:
$ git worktree add ../project-old-release v1.2.0
이제 새로운 디렉터리가 생겼고, 그 안에는 다른 worktree와 완전히 분리된 git status, git log, 로컬 변경 사항들이 존재합니다.
3. Worktree 제거하기
어떤 worktree가 더 이상 필요 없을 때:
# 레포 안 어딘가에서 $ git worktree list # 제거할 worktree 경로를 확인 $ git worktree remove /full/path/to/worktree
이 방법은 그냥 rm -rf로 디렉터리를 지우는 것보다 훨씬 안전합니다.
- Git이 해당 worktree에 대한 내부 레퍼런스를 깔끔하게 정리해 줍니다.
git worktree list에 더 이상 쓰지 않는 worktree가 남아서 혼란을 주는 일을 방지합니다.
팁: worktree를 제거하기 전에, 중요한 변경 사항은 반드시 커밋하거나 백업해 두세요. worktree를 제거하면 그 작업 디렉터리 자체가 제거됩니다.
일상에서 쓰는 실용적인 Worktree 워크플로
대규모 코드베이스에서 worktree를 활용해 하루 작업을 구성하는 한 가지 실전 예를 살펴보겠습니다.
1. 안정적인 “홈 베이스” Worktree 유지하기
처음 clone한 디렉터리를 홈 베이스로 삼고, 보통 main 혹은 develop에 두는 식으로 사용합니다:
/path/to/project # 항상 main 또는 develop에 유지
- 여기서 최신 변경을 pull 합니다.
- 빠른 코드 확인, 탐색, 비파괴적인 작업을 이곳에서 수행합니다.
- 위험한 작업은 이 디렉터리에서 바로 시작하지 않습니다.
2. 의미 있는 작업마다 Worktree 하나씩
상당한 규모의 작업마다 전용 worktree를 하나씩 만듭니다:
# 기능 개발 /path/to/project-feature-x /path/to/project-feature-y # 핫픽스 /path/to/project-hotfix-123
이렇게 하면 얻는 이점은:
- 각 디렉터리가 각각의 빌드 아티팩트, 로그, 에디터 설정을 품고 있게 됩니다.
- IDE 창을 여러 개 띄워서, 각 창을 서로 다른 브랜치에 연결해 둘 수 있습니다.
예를 들면:
$ cd /path/to/project $ git fetch origin $ git worktree add ../project-feature-x origin/main $ cd ../project-feature-x $ git switch -c feature/x
3. 인터럽트와 컨텍스트 스위칭 대응하기
급한 이슈가 갑자기 들어왔을 때는 다음과 같이 합니다:
-
진행 중인 기능 작업 디렉터리는 건드리지 않습니다.
-
홈 베이스 worktree에서, 버그 픽스를 위한 새 디렉터리를 만듭니다:
$ cd /path/to/project $ git fetch origin $ git worktree add ../project-critical-fix origin/main $ cd ../project-critical-fix $ git switch -c hotfix/critical-issue -
이 worktree에서 버그를 수정하고, 테스트하고, 푸시한 뒤 PR을 생성합니다.
-
작업이 끝나면:
$ git worktree remove ../project-critical-fix
이 과정 동안 기능 개발용 worktree는 단 한 번도 건드리지 않았습니다. stash도 필요 없고, 체크아웃 충돌도 없고, 반쯤 적용된 변경 때문에 애먹을 일도 없습니다.
4. 오래된 Worktree 정리하기
시간이 지나면 worktree 디렉터리가 쌓이게 됩니다. 주기적으로:
$ git worktree list # 정리할 대상 고르기 $ git worktree remove ../project-feature-you-finished
git worktree remove를 했는데도 Git이 디렉터리를 전부 삭제하지 못하는 경우(예: 일부 파일이 쓰기 보호되어 있는 경우)에는, 나머지를 수동으로 삭제해도 괜찮습니다.
팁, 모범 사례, 주의할 점
팁 1: 디렉터리 이름을 명확하게 짓기
한눈에 봐도 어떤 용도인지 알 수 있는 디렉터리 이름을 쓰는 것이 좋습니다:
project-mainproject-feature-paymentsproject-bugfix-login-timeout
여러 개의 에디터 창과 터미널을 띄워 쓰는 상황에서 큰 도움이 됩니다.
팁 2: 빌드 아티팩트 공유 여부 주의
worktree는 Git 히스토리를 공유하지만, 빌드 아티팩트는 공유하지 않습니다. 대부분의 경우 이것은 좋은 일입니다만:
- 매우 큰 프로젝트에서는 worktree마다 의존성 설치/빌드를 반복하는 것이 여전히 부담일 수 있습니다.
- 툴이 지원한다면, 전역
node_modules캐시나 빌드 캐시 등 공유 캐시를 구성하는 것도 고려해 보세요.
팁 3: 동일 브랜치를 여러 Worktree에서 쓰지 않기
Git은 기본적으로 같은 브랜치를 여러 worktree에서 동시에 체크아웃하는 것을 허용하지 않습니다. 의도적인 제한입니다.
- 하나의 브랜치를 두 군데에서 동시에 수정하면 상태가 헷갈리기 쉽습니다.
- 꼭 필요한 경우라면 worktree마다 별도의 임시 브랜치(
feature/x-spike,feature/x-refactor등)를 만들고, 나중에 머지하는 방식을 쓰는 것이 좋습니다.
팁 4: 코드 리뷰와 bisect에도 Worktree 사용하기
조금 더 고급 사용 패턴으로는 다음과 같은 것들이 있습니다:
- 코드 리뷰: PR 브랜치를 새 worktree에 체크아웃해서, 기존 작업을 건드리지 않고도 로컬에서 빌드/테스트해 볼 수 있습니다.
- bisect:
git bisect를 전용 worktree에서 실행하면, 메인 작업 디렉터리가 이리저리 체크아웃되며 지저분해지는 것을 막을 수 있습니다.
팁 5: 핵심 명령어부터 익히기
처음부터 모든 기능을 다 외울 필요는 없습니다. 아래 세 가지만 제대로 익혀도 큰 효과를 볼 수 있습니다.
git worktree listgit worktree add ../path branchgit worktree remove ../path
이 세 가지만 손에 익어도 생산성이 눈에 띄게 올라가는 걸 느낄 겁니다.
결론: 실제로 쓰게 되는 안전망
Git worktree는 기능 자체는 작지만, 특히 크고 빌드가 느리며 업무에 중요한 코드베이스에서 엄청난 영향력을 가진 도구입니다. 사용하면 다음과 같은 장점을 얻게 됩니다.
- 여러 개의 병렬 작업 공간을, 추가 clone 없이 운영할 수 있습니다.
- 위험한 stash 대신, 실험을 완전히 분리된 디렉터리에 둘 수 있습니다.
- 브랜치를 이리저리 바꾸는 곡예 없이도 빠르게 컨텍스트를 전환할 수 있습니다.
많은 팀이 여전히 git checkout과 git stash 단계에 머물러 있지만, 한 번 worktree에 익숙해지고 나면 “왜 이제까지 이걸 안 썼지?” 하는 생각이 들 겁니다.
다음에 반쯤 끝낸 변경을 stash에 밀어 넣거나, 레포를 또 clone 하려는 충동이 들면 잠시 멈추고 이렇게 해 보세요:
cd /path/to/your/project git worktree add ../project-new-task origin/main cd ../project-new-task
이 한 번의 명령이, 두려움 없는 실험을 위한 당신의 새로운 안전망이 되어 줄지 모릅니다.