팀과 함께 협업하다 보면 서로의 branch를 확인하기 위해 switch(checkout)하는 경우가 허다합니다. 한참 작업을 하다 급한 코드 리뷰, 혹은 핫픽스가 필요해 임시 commit을 만들거나 stash 한 경험이 있으신가요?

무엇이 문제인가!
임시 commit을 만들거나 stash 하는 것으로도 작업 내용을 보존하며 branch를 switch 할 수 있습니다. 하지만 이 방법은 결국 작업자의 '기억'에 의존하게 됩니다. 잠깐 동안만 다른 branch에서 작업하다 돌아온다면 되돌려야 하는 포인트를 금방 찾을 수 있겠지만, 시간이 길어진다면 어떨까요? stash 해둔 것을 모르고 날려버린다면요?(으악) 제가 애용하는 Fork 같은 UI 도구를 사용하면 기억을 더듬는데 도움이 되겠지만, 완전하다고 말할 순 없을 것 같습니다.

생산성 문제도 짚고 넘어가야 합니다.(사실 이게 더 핵심인 듯합니다!) 현재 제가 속한 iOS 팀은 Tuist로 전체 프로젝트의 의존성을 관리하고 있는데 branch를 이동할 때마다 `tuist generate`를 실행시켜줘야 하다 보니 기다리는 시간이 길어졌습니다. 덤으로 clean build까지 돌려줘야 하다 보니,,, 놀 수 있는 휴식 시간(?)이 늘어나게 되었죠.
만약 branch 간 새로 추가된 라이브러리가 있으면 이 시간은 더욱 길어질 것입니다. 실제로 최근 신규 SDK를 통합하는 작업을 진행했었는데, 다른 팀원 분들의 코드 리뷰를 진행할 때마다 라이브러리가 지워지고,,, 추가되는 딱 봐도 비효율 끝판왕을 경험해 보니 문제의 심각성을 더 크게 깨닫게 된 것 같습니다.
또한 빌드를 누른 순간 자연스러운 커피 타임이 되는 등 앞서 언급한 모든 문제는 하나의 디렉토리에서 모든 작업을 진행하기 때문입니다.

Clone 하면 되는 거 아니야?
그렇습니다. 문제는 하나의 디렉토리에서 모든 작업을 진행하고 있는 것이기 때문에, 직관적으로 여러 개의 디렉토리를 만들면 되겠구나!라는 생각을 할 수 있습니다. 가장 기본적인 방법이기도 하며, 실제로 앞서 언급한 문제들을 해결해 줄 수 있을 것입니다. 아래와 같이 세팅해 두면 branch를 이동하는 것이 아닌, 디렉토리 위치를 변경하는 것으로 각각의 프로젝트를 관리할 수 있게 됩니다. 이 방법은 별개의 3개의 프로젝트를 만드는 것과 같습니다!

이렇게 보면 쉽고 익숙한 clone을 사용하지 않을 이유가 없어보이지만, 이 방식은 새로운 문제점들을 만들어냅니다.
- 매번 전체 프로젝트를 clone 하는 것은 네트워크와 디스크 낭비가 심함.
- 별개의 프로젝트로 동작하기 때문에 각 디렉토리 간 작업 내용, 시점 등이 달라 관리가 필요.
첫 번째 내용부터 살펴보겠습니다. `git clone` 명령어는 원격 Repository를 받아오는 작업입니다. 당연하게도 전체 Repository를 받아오기 때문에 특정 변경 사항만 받아오는 fetch나 pull과 비교해 많은 네트워크를 사용하게 될 것입니다.
또한 새로운 프로젝트 '작업 D'를 clone 하게 됐을 때, '작업 A' 파일과 완전히 동일한 파일이 있더라도 이와 상관없이 모든 파일을 받아오기 때문에 디스크 공간도 clone 한 프로젝트의 개수에 비례해 차지하게 될 것입니다.

두 번째 내용도 같은 맥락입니다. 결국 작업 A, B, C는 모두 별개의 프로젝트로 동작하기 때문에 디렉토리간 내용 공유가 어렵습니다. 작업 C 안에서 작업한 내용을 원격 저장소에 업로드하지 않는 이상 A와 B는 이 내용을 공유받기 어렵습니다.(로컬로 직접 옮기면 더 큰 문제가 발생할 수도?)
또한 작업 A에서 특정 브랜치의 내용을 pull 받아 최신화 했더라도 나머지 B, C는 최신화가 되지 않아 실수할 수 있는 여지가 늘어날 수도 있습니다. 매번 각각의 프로젝트에서 최신화를 신경 써줘야 한다는 뜻입니다.
우리의 구원자 worktree
그래서 등장한 것이 오늘의 주인공 worktree입니다. 이름에서 유추할 수 있듯, 여러 개의 작업 트리를 관리할 수 있게 해주는 방법입니다. clone과 다른 가장 큰 특징은 바로, 모든 작업 트리가 단 하나(메인 트리)의 git 저장소와 작업 내용을 공유한다는 것입니다. 바로 이 특징이 위에서 언급한 clone의 모든 문제점을 해결해 줄 수 있게 됩니다.

위 그림에서 Worktree A, B, C는 모두 Main Worktree(처음 git clone 했을 때 만들어지는 기본 작업 디렉토리를 뜻합니다)의 이력을 공유하면서도 특정 branch 혹은 commit을 위한 독립적인 작업 공간을 만들어냅니다. git clone과 마찬가지로 새로운 디렉토리를 생성하는 것에 더해, git 저장소를 공유할 수도 있는 것입니다!
결과적으로 특정 worktree에서 작업 후 git 이력을 남기면, 모든 worktree에서든 작업 내용이 공유 + 최신화 될 수 있게 됩니다!
worktree로 생산성 올려보기
어떤 내용이든 이론적으로만 살펴보면 제 것으로 만들기 어려운 것 같습니다. 그래서 실제 맥락에서 어떻게 사용될 수 있는지 예시를 통해, worktree의 강력함을 알아보겠습니다.
아래 상황은 특정 작업 도중 프로덕트 팀에서 급한 핫픽스 건이 발생해 빠르게 작업해야하는 경우입니다!

1. 새로운 worktree 만들기
핫픽스 요청이 들어오기 전 열심히 기능 개발을 하고 있던 로컬 작업 내용이 있었습니다. 하지만 걱정하지 마세요, 우리에겐 worktree가 있으니까요! hotfix를 위해 기존 production 코드가 올라가 있는 develop 브랜치를 기준으로 worktree를 생성합니다.
git worktree add ../hotfix develop
위 명령어는 `git worktree add {path} {branch}` 형식으로 작성되었습니다. 여기서 눈여겨봐야 할 점은 경로를 지정하는 `../hotfix` 부분입니다. 왜 `../`를 사용해 현재 디렉토리에 포함되지 않게 worktree를 만들어야 할까요?
만약 기존 프로젝트에 새로운 worktree, 즉 새로운 디렉토리가 생성된다면 그 파일 자체로 git에 변경사항이 생기게 됩니다. 결국 아래와 같이 입력하게 되면 `기존경로/hotfix` 경로로 worktree가 생성되어 불필요한 변경사항이 발생하게 됩니다.
git worktree add hotfix develop
우린 보통 worktree를 원격 저장소에 올리려 하지 않기 때문에, 이를 방지해 주기 위해 상위 디렉토리에 만들어주는 것으로 이해할 수 있습니다.
이렇게 CLI를 통해 명령어를 입력하면 별다른 문구 없이 worktree가 생성됩니다. 이를 확인해 보기 위해 다음 명령어를 입력 후 정상적으로 hotfix worktree가 생성된 것을 확인할 수 있습니다.
git worktree list

2. hotfix worktree로 이동
새로운 hotfix worktree를 만들었으니 해당 디렉토리로 이동 후 작업해야 합니다. 여기서 기존 방식처럼 체크포인트 용 commit을 만들거나 stash 해야 할 필요가 있을까요? 우리는 '다른 디렉토리'로 이동하는 것이기 때문에 그냥 위치를 옮기기만 하면 됩니다!
cd ../hotfix

이제 현재 위치는 hotfix worktree에 위치해 있으며, 해당 worktree의 작업 내용은 develop 브랜치에 기록되게 됩니다.
3. hotfix 브랜치 생성
하지만 develop 브랜치에서 바로 hotfix 내용을 수정하면 안 되겠죠? 이를 수정하기 위한 브랜치를 새로 생성합니다.

4. 이제 여기서 핫픽스를 수정합니다!
hotfix 수정을 위한 모든 준비가 끝났습니다. 이제 hotfix에 대한 작업 내용은 모두 hotfix worktree에서 작업하면 될 것 같습니다. 이 worktree는 전체 프로젝트의 git 이력을 공유받으면서도 별개의 프로젝트로서 독립된 작성, 빌드, 테스트 등을 할 수 있습니다!

Fork로 worktree 써보기
Fork를 이용하면 worktree를 훨씬 쉽고 직관적으로 관리할 수 있습니다. 앞서 핫픽스가 발생해 빠르게 작업 공간을 전환해야 하는 경우를 살펴봤습니다. 이번에는 저만의 사용 방식(?)이었던 여러 팀원들의 코드 리뷰를 진행할 때 worktree를 여러 개 만들어 사용한 예시입니다.
민톨, 한톨 팀원이 각각의 branch에서 작업 후 PR을 작성했고, 우린 코드 리뷰를 해야 합니다. 기존 방식은 각각의 branch로 switch 후 코드를 확인하는 방식입니다. 프로젝트 크기가 작다면 부담이 덜하겠지만 각각의 branch에서 추가 혹은 삭제된 SPM, Cocoapod 등의 의존성이 많다면 branch를 전환할 때마다 이를 다시 로드하고,,, 클린 빌드하고,,, 아주 난리도 아닐 겁니다.

이를 위해 각각의 worktree를 생성해 보겠습니다. 상단 Dock에서 Repository > Add Worktree...를 클릭합니다.

이후 Add Worktree Alert 창이 출력되는데, 여기서 Local Branch에 기준으로 삼을 branch를, Location에 디렉토리명을 입력 후 create 합니다. 위에서 살펴봤던 `git worktree add {path} {branch}`와 같은 동작입니다.

이렇게 각각의 branch를 worktree로 생성하면 다음과 같이 UI로 확인할 수 있게 됩니다.

worktree에서 branch를 이동할 때 주의해야 할 점
다시 한번 강조하는 worktree의 가장 중요한 특징은, 모든 작업 트리가 단 하나(메인 트리)의 git 저장소와 작업 내용을 공유한다는 것입니다. 즉, 파일 디렉토리만 다를 뿐 모두 같은 git 저장소를 바라보고 있다는 뜻이죠.
이 말인즉슨, 각각 다른 worktree일지라도 같은 branch에는 같은 내용이 있어야 한다는 것입니다. git 저장소 내용을 공유하기 때문에 당연한 이야기일 수 있겠지만, 이러한 특성 때문에 하나의 branch에는 하나의 worktree만 접근할 수 있도록 제한되어 있습니다.

이는 작업 내용을 안전하게 관리하기 위한 git 안전 시스템이며, 강제로 `--force` 옵션을 통해 check out 할 수 있지만 권장되지 않습니다!(잘못하다간 로컬 파일이 날아갈 겁니다 후후)
그래서 만약 서로 다른 worktree에서 같은 branch에 접근하고 싶다면 새롭게 branch를 파서 사용하는 것을 권장드립니다 👍
worktree 자주 쓰는 명령어 모음집
# worktree 목록 보기
git worktree list
# 새 worktree 추가
git worktree add {path}
# 기존 branch로 worktree 추가
git worktree add {path} {branch}
# 새로운 branch를 만들지 않고 worktree 추가(detached)
git worktree add -d {path}
# worktree 삭제
git worktree remove {path}
생산성이 늘었다!
`tuist generate && pod install` + `clean build` 명령어와 함께 branch를 이동할 때마다 모니터를 바라만 볼 수밖에 없었던 지난 세월들,,, 이제는 worktree와 함께 눈에 띄게 생산성을 향상할 수 있었습니다.
새로운 문제(?)라면 worktree 덕분에 여러 개의 Xcode를 띄워놓을 수 있게 됐는데 빌드를 여러 개 돌리다 보면 맥북이 죽으려 한다는 것,,,? 정도 말고는 아주 좋은 경험이었습니다.
오늘 포스팅은 팀원 분께서 공유해 주신 내용을 기반으로 처음 알게 된 내용이었으며, 이러한 공유 문화가 팀 전체에 긍정적인 효과를 가져올 수 있지 않을까 하는 기대와 함께 다음에 돌아오겠습니다~! 🚀

'실무 내용 내껄로 만들기' 카테고리의 다른 글
| Firebase Remote Config로 배포 없이 값 "딸깍" 바꿔주기 (0) | 2025.11.23 |
|---|---|
| Firebase App Distribution + Fastlane으로 초간단 QA 빌드 뽑아보기 (0) | 2025.10.19 |
| 무지성 Commit은 그만! Git Rebase로 깔끔하게 코드 리뷰 반영하기 (5) | 2025.09.07 |
