git worktree - 브랜치를 폴더로 바꾸기

요약. 브랜치를 옮길 때마다 git stash 를 하고, 돌아와서 빌드를 처음부터 다시 돌리고 있다면 이 글이 그 낭비를 없앱니다. worktree 는 브랜치 전환을 폴더 이동으로 바꿉니다. 시작에 필요한 명령은 세 개고, 미리 알아야 할 함정도 세 개입니다.

도토리 블루투스 넘패드 - 폰을 PC 의 17키 숫자패드로

제가 만든 무료 앱입니다. 많이 써 주세요.

전환 비용은 소스가 아니라 빌드 산출물에 있습니다

git switch 가 갈아끼우는 것은 추적 파일뿐입니다. 정작 비싼 것은 그 옆에 남는 obj/, bin/, node_modules/ 입니다. 소스가 통째로 바뀌면 증분 빌드가 무효화되므로, 한 줄 확인하러 브랜치를 옮겼다가 몇 분을 기다립니다. 작업 중이던 변경은 stash 로 밀어 넣어야 하고, 돌아와 pop 하다 충돌을 만납니다.

저장소를 하나 더 clone 하면 해결되지만 히스토리와 오브젝트가 그대로 복제됩니다. worktree 는 저장소 하나에 작업 폴더만 여러 개 붙입니다. 오브젝트와 refs 는 공유하고 체크아웃만 분리하는 구조입니다. 2015년 7월 29일 Git 2.5 에 add/list/prune 로 들어온 기본 기능이라 따로 설치할 것도 없습니다.

방식히스토리빌드 캐시동시 작업
stash + switch하나전환마다 무효화불가
저장소 추가 clone폴더마다 복제유지가능
worktree공유유지가능

clone 을 늘리면 fetch 도 폴더마다 따로 돌려야 하고, 한쪽에서 만든 브랜치가 다른 쪽에 보이지 않습니다. worktree 는 refs 를 공유하므로 옆 폴더에서 방금 만든 브랜치가 그 자리에서 보입니다.

명령 세 개로 시작합니다

git worktree add ../hotfix -b hotfix   # 새 브랜치 + 폴더를 한 번에
git worktree list                      # 어느 폴더에 어느 브랜치가 붙었는지
git worktree remove ../hotfix          # 폴더 정리 (브랜치는 남습니다)

첫 줄은 형제 폴더 ../hotfix 를 만들고 거기에 새 브랜치를 체크아웃합니다. 원래 폴더는 손대지 않으므로 빌드 산출물도, 편집 중이던 파일도 그대로입니다. 이미 있는 브랜치를 꺼내려면 -b 를 빼고 git worktree add ../review feature/login 으로 씁니다. list 는 폴더마다 한 줄씩 sha 와 브랜치를 찍습니다.

.../demo    dfd2991 [main]
.../hotfix  dfd2991 [hotfix]

함정은 셋뿐입니다

  1. 같은 브랜치를 두 폴더에 둘 수 없습니다. 이미 붙은 브랜치를 또 체크아웃하면 fatal: 'main' is already used by worktree at ... 로 거부합니다. 브랜치와 폴더는 일대일입니다.
  2. remove 는 폴더만 지웁니다. 브랜치는 그대로 남으니 git branch -d 로 따로 지웁니다. 반대로 탐색기에서 폴더를 지웠으면 등록 정보가 남으므로 git worktree prune 으로 정리합니다.
  3. 링크된 worktree 의 .git 은 폴더가 아니라 파일입니다. 안에는 gitdir: .../worktrees/hotfix 한 줄이 들어 있습니다. .git 디렉터리 존재를 가정하고 경로를 조립하는 스크립트나 툴은 여기서 깨집니다.

메인 폴더의 특권을 없애는 bare 레이아웃

기본 사용법은 "메인 저장소 + 딸린 폴더" 라서 메인이 특별한 지위를 갖습니다. 메인을 지우면 나머지가 고아가 되고, 폴더 목록에서 어느 것이 원본인지 기억해야 합니다. 폴더를 전부 대등하게 두려면 bare 저장소를 숨기고 브랜치마다 폴더를 하나씩 두는 배치가 낫습니다.

proj/
  .bare/          # bare 저장소 (여기엔 작업 파일이 없습니다)
  .git            # "gitdir: ./.bare" 한 줄이 든 파일
  master/         # 폴더 = 브랜치
  feature-login/

git clone --bare <url> .bare 로 받고, .git 포인터 파일을 만든 뒤 git worktree add master 로 첫 폴더를 냅니다. 이후 브랜치 이름과 폴더 이름이 일대일이라 ls 만으로 지금 벌여 놓은 작업이 전부 보입니다.

정리

브랜치 전환의 실제 비용은 소스 교체가 아니라 빌드 산출물 무효화입니다. worktree 는 폴더를 분리해 그 비용을 0으로 만들고, add/list/remove 세 명령이면 충분합니다. 브랜치와 폴더가 일대일이라는 제약, 그리고 .git 이 파일이라는 사실만 기억하면 사고가 없습니다.

지금 저장소에서 git worktree add ../hotfix -b hotfix 를 한 번 실행해 보십시오. 다음 편에서는 이렇게 벌려 놓은 폴더를 병렬 작업 슬롯으로 쓰고, 마지막에 한 줄로 병합하는 방법을 다룹니다.