본문 바로가기
개발일기

git worktree로 브랜치 전환 없이 두 작업하기

by 꼬질꼬질두부 2026. 9. 11.
반응형

 

어두운 배경에서 하나의 Git 저장소가 두 작업 공간으로 나뉘는 git worktree 표지

리뷰 수정이 끝나지 않았는데 긴급 수정이 들어오면, 브랜치를 바꾸기 전에 현재 파일 상태부터 정리해야 한다.

 

git stash로 잠시 치울 수도 있지만 다시 돌아왔을 때 복원 과정이 남는다. 이럴 때 git worktree를 쓰면 원래 디렉터리를 그대로 둔 채 다른 브랜치를 별도 디렉터리에서 열 수 있다.

 

이 글에서는 직접 재현한 명령과 화면을 따라 add, list, 중복 checkout 제한, remove, prune까지 확인한다.

 

브랜치 전환 대신 작업 디렉터리를 하나 더 둔다

git worktree는 하나의 Git repository에 여러 작업 디렉터리를 연결하는 기능이다.

 

각 worktree는 작업 파일, HEAD, index를 따로 가진다. object database와 대부분의 refs는 공유한다.

 

그래서 main worktree에 미완료 파일이 남아 있어도 linked worktree에서 다른 브랜치를 checkout할 수 있다.

하나의 공통 Git 데이터에서 review-fix와 hotfix 작업 디렉터리가 갈라지는 구조

 

두 디렉터리는 작업 상태를 나누지만 Git object database와 대부분의 refs를 공유한다.

 

완전한 저장소 복제본을 두 개 관리하는 것은 아니다. 커밋 객체와 브랜치 ref를 공유하면서 현재 checkout과 작업 파일만 worktree별로 나눈다.

 

한쪽에서 만든 commit은 공통 object database에 저장된다. 다른 worktree에서도 그 commit을 참조할 수 있다.

 

내가 이해하기 가장 쉬웠던 표현은 “저장소를 하나 더 복사한다”보다 “같은 저장소의 작업 화면을 하나 더 연다”였다.

 

자세한 경계는 Git worktree 공식 문서와 repository layout 문서에서 확인할 수 있다.

 

git worktree add로 새 브랜치와 디렉터리를 만든다

전제는 main worktree가 있고, 긴급 수정 브랜치는 아직 없다는 것이다.

 

먼저 원래 디렉터리의 변경 상태를 확인한 뒤 새 브랜치와 디렉터리를 만든다.

 

git status --short
git worktree add -b hotfix/login-timeout ../urgent-fix main
git worktree list

명령에서 -b hotfix/login-timeout은 새 브랜치, ../urgent-fix는 새 작업 디렉터리, 마지막 main은 브랜치의 시작점이다.

 

세 값을 직접 적어 두면 나중에 명령만 다시 봐도 무엇을 만들었는지 알 수 있다. add와 -b의 공식 동작도 같은 흐름을 설명한다.

확인 시점 실행할 명령과 통과 기준
시작 전 git status --short로 기존 변경을 확인한다.
생성 후 git worktree list에 두 경로와 서로 다른 branch가 보여야 한다.
작업 중 각 디렉터리에서 git status --short를 실행해 변경이 섞이지 않았는지 본다.
제거 전 git -C ../urgent-fix status --short가 비어 있거나, 남은 변경을 먼저 보존한다.

새 디렉터리에서는 의존성이나 빌드 결과처럼 Git이 추적하지 않는 파일도 별도로 생길 수 있다.

 

첫 실행 전에 프로젝트의 설치 명령을 다시 확인해야 한다. branch는 맞지만 실행 환경이 비어 있는 상황을 여기서 자주 만난다.

 

이미 존재하는 브랜치를 열 때는 -b를 빼고 다음처럼 실행한다.

 

git worktree add ../review-copy review/feature-x

이 명령은 review/feature-x가 존재하고 다른 worktree에서 checkout되지 않았을 때 쓴다.

 

git worktree list로 두 작업 상태를 확인한다

재현은 macOS 26.4.1, Git 2.52.0의 격리된 저장소에서 진행했다.

 

기존 lab/repo는 review-fix, 추가한 lab/urgent-fix는 hotfix/login-timeout을 가리켰다.

 

.../lab/repo        7ee2a17 [review-fix]
.../lab/urgent-fix  7ee2a17 [hotfix/login-timeout]

두 줄의 commit id가 같은 이유는 두 branch를 같은 main commit에서 시작했기 때문이다. 이후 각 branch에 commit이 생기면 revision은 달라질 수 있다.

 

git worktree list는 경로, 현재 revision, branch를 한 번에 보여 준다. 상황에 따라 locked나 prunable 상태도 함께 표시한다.

 

각 디렉터리에 서로 다른 untracked file을 만든 뒤 상태를 확인했다.

 

원래 디렉터리에는 review-note.md, 추가 디렉터리에는 hotfix-note.md만 나타났다.

Git 2.52.0 재현에서 review-fix와 hotfix 브랜치의 서로 다른 작업 상태를 보여 주는 터미널

 

실제 재현 화면: 같은 commit에서 출발한 두 branch와 각 디렉터리의 서로 다른 파일 상태.

 

이 화면에서 worktree의 장점이 가장 선명하게 보였다. 두 작업을 동시에 열어 두더라도 수정 파일과 staging 상태는 각 디렉터리에 남는다.

 

출력의 일반 의미는 Git 공식 list 설명을 근거로 했다.

 

같은 브랜치의 중복 checkout은 기본적으로 거부된다

같은 로컬 브랜치를 두 worktree에 checkout하면 Git이 기본적으로 거부한다.

 

이미 review-fix를 쓰는 상태에서 아래 명령을 실행해 보니, 기존 worktree 경로를 알리는 오류와 함께 exit code 128이 반환됐다.

 

git worktree add ../duplicate review-fix

--force는 일부 보호 조건을 우회하지만 두 작업을 분리하려는 상황의 기본 해결책은 아니다.

 

오류를 만났다면 git worktree list로 그 브랜치가 연결된 경로부터 확인한다. 두 작업에는 서로 다른 브랜치를 지정하면 된다.

 

공식 문서의 --force 조건도 기본 흐름과 예외를 구분한다.

 

git worktree remove로 안전하게 정리한다

작업을 끝낸 뒤에는 대상 worktree의 변경을 확인하고 remove로 닫는다.

 

git worktree list
git -C ../urgent-fix status --short
git worktree remove ../urgent-fix

status --short에 내용이 보이면 제거를 멈춘다. 변경을 commit, stash 또는 별도 복사로 보존한 뒤 다시 확인한다.

 

Git은 수정된 추적 파일이나 untracked file이 있는 worktree의 제거를 기본적으로 거부한다. 그래서 --force를 평소 정리 명령처럼 붙이지 않는 편이 안전하다.

긴급 작업이 끝난 뒤 변경 보존 여부를 확인하고 git worktree remove로 정리하는 흐름

 

정상 경로는 status 확인 → 변경 보존 → remove다. prune은 디렉터리를 수동으로 지워 stale metadata가 남은 경우에만 쓴다.

 

git worktree prune은 정상적인 remove 뒤에 붙이는 마무리 명령이 아니다.

 

파일 탐색기나 다른 명령으로 작업 디렉터리를 먼저 삭제해 $GIT_DIR/worktrees 아래에 관리 정보만 남았을 때 사용한다.

 

git worktree prune --dry-run
git worktree prune

이 경우에도 --dry-run으로 후보를 먼저 확인한다. remove와 prune의 공식 설명도 정상 제거와 이미 사라진 디렉터리의 관리 정보 정리를 나눠 안내한다.

 

remove는 디렉터리를 없애지만 그곳에서 쓰던 branch를 자동으로 지우지 않는다.

 

긴급 수정이 merge됐고 branch도 더 이상 필요 없다는 것을 확인한 뒤에만 git branch -d hotfix/login-timeout처럼 별도로 정리한다.

 

결국 내가 확인할 것은 세 가지였다. 두 디렉터리가 서로 다른 branch를 가리키는지, 제거 전에 변경을 보존했는지, prune을 정상 정리 명령으로 오해하지 않았는지다.

반응형

댓글