본문 바로가기
빌드노트 검색

빌드노트

git worktree add가 이미 사용 중인 브랜치를 거절할 때

같은 브랜치로 worktree를 만들다 거절되면 오류의 기존 경로와 worktree 목록을 맞춰 본다. 실제 실험으로 기존 폴더·새 브랜치·detached HEAD의 차이와 미커밋 수정이 새 폴더에 따라가지 않는 조건을 확인한다.

git worktree add ../duplicate topic을 실행했는데 already checked out 또는 already used by worktree와 함께 다른 폴더 경로가 나온다면, 먼저 그 경로를 확인한다. Git은 기본적으로 같은 로컬 브랜치를 여러 worktree에 동시에 체크아웃하지 못하게 한다. 그 브랜치의 작업을 이어 갈 목적이면 기존 폴더를 쓰고, 별도 수정을 쌓으려면 새 브랜치를 만든다. 커밋된 코드만 옆에서 읽고 비교하려면 detached HEAD로 폴더를 만들 수 있다.

worktree는 한 저장소에 연결한 작업 폴더다. 폴더마다 현재 위치를 나타내는 HEAD와 인덱스는 따로 있지만, 브랜치 참조는 공유한다. 폴더 이름을 다르게 정했다고 같은 브랜치의 독립 복사본이 되는 것은 아니다. git-worktree 공식 문서 (새 탭에서 열림)는 이미 체크아웃된 브랜치에 대한 거절과 이를 우회하는 --force를 설명한다. 이 오류에서는 우회부터 시도하지 말고 어떤 작업 공간이 필요한지 먼저 정한다.

오류에 나온 폴더와 브랜치를 맞춰 본다

다음은 Windows의 Git 2.45.1.windows.1에서 새 합성 저장소로 재현한 결과다. main에서 만든 topic을 owner 폴더에 체크아웃한 뒤, 다른 폴더에도 같은 브랜치를 지정했다. 명령은 원래 저장소인 repo의 최상위에서 실행했다. 출력의 긴 실험 경로 접두어만 D:/worktree-lab으로 줄였다.

git worktree add ../duplicate topic
Preparing worktree (checking out 'topic')
fatal: 'topic' is already used by worktree at 'D:/worktree-lab/owner'

종료 코드는 128이었고 duplicate 폴더는 생기지 않았다. 이 메시지에서 확인할 곳은 생성하려던 폴더보다 이미 topic을 쓰고 있는 owner다.

오류가 발생한 저장소에서 다음 명령으로 등록된 worktree를 읽는다. Git이 설치되어 있어야 하며, 다른 저장소에서 실행하면 그 저장소의 목록이 나온다.

git worktree list --porcelain
worktree D:/worktree-lab/repo
HEAD 9c3184991d0bc896adcf06df0411bd4c649234bd
branch refs/heads/main

worktree D:/worktree-lab/owner
HEAD 9c3184991d0bc896adcf06df0411bd4c649234bd
branch refs/heads/topic

빈 줄로 나뉜 한 묶음이 worktree 하나다. worktree는 폴더 경로, HEAD는 현재 커밋, branch는 체크아웃한 브랜치다. 위에서는 두 폴더가 같은 커밋을 보지만 브랜치는 각각 main, topic이다. HEAD 해시가 같다는 것과 같은 브랜치를 쓰는 것은 다른 조건이다. 자기 저장소의 해시는 이 예제와 달라지므로, 값 자체를 맞추기보다 브랜치와 경로가 맞는지 읽는다.

topic에서 하던 작업을 계속하려면 목록에 나온 owner를 편집기에서 연다. 먼저 git -C ../owner status --short로 그 폴더의 상태를 읽을 수 있다. 이 상대 경로는 예제의 repo 기준이며, 자기 환경에서는 오류에 나온 실제 경로로 바꾼다. 공백이 있으면 경로를 따옴표로 감싼다. 실험에서는 M note.txt가 나왔다. 첫 칸이 공백이고 다음이 M이므로, 작업 파일에 아직 스테이징하지 않은 수정이 있었다. 출력이 비어 있다면 Git이 표시할 변경이 없는 것이지, 브랜치가 다른 worktree에서 풀렸다는 뜻은 아니다.

별도 수정을 남길 거라면 새 브랜치로 만든다

기존 topic의 작업을 유지하면서 다른 수정을 쌓으려면 출발 커밋만 공유하는 새 브랜치를 만든다. 아래는 topic이 이미 존재하고, topic-try라는 브랜치와 ../branch-copy 폴더는 아직 없는 조건이다. 자기 저장소에서는 브랜치 이름과 대상 경로를 바꾼다. 명령이 실패하면 뒤의 확인 명령으로 넘어가지 말고 해당 오류부터 읽는다.

git worktree add -b topic-try ../branch-copy topic
git -C ../branch-copy branch --show-current
git -C ../branch-copy rev-parse --short=7 HEAD

생성 명령은 종료 코드 0으로 끝났다. 뒤의 두 조회는 순서대로 다음 값을 출력했다.

topic-try
9c31849

-b 뒤의 topic-try는 새 브랜치 이름이고, 마지막 topic은 출발점이다. 마지막 인자를 빼면 현재 worktree의 HEAD에서 시작하므로, 다른 브랜치에 서 있던 경우 의도와 다른 코드가 나올 수 있다. 대문자 -B는 기존 브랜치를 재설정할 수 있어 새 이름을 만드는 이 선택에 쓰지 않는다.

새 폴더는 기존 작업 폴더의 미커밋 파일을 복사하지 않았다. 실험에서는 커밋 당시 note.txt가 committed baseline이었고, owner에서만 이를 owner uncommitted edit으로 고쳐 둔 상태였다. branch-copy의 파일은 committed baseline으로 시작했다. 새 worktree의 출발점은 지정한 커밋이지, 기존 폴더에 저장만 해 둔 수정 내용이 아니다. 그 수정까지 이어 받아야 한다면 새 폴더에 이미 들어 있을 것이라 가정하지 말고 기존 작업을 보존·전달할 방법을 따로 정한다.

이후 branch-copy에서 파일을 바꾸어 커밋하자 topic-try의 끝은 866dc89로 이동했다. 기존 topic은 9c31849에 남았고, owner의 미커밋 파일과 status도 그대로였다. 이 실험에서 확인한 독립성은 새 브랜치의 커밋과 각 폴더의 파일 상태다. 저장소 자체가 복제된 것은 아니다.

커밋된 버전만 비교하려면 detached HEAD를 쓴다

브랜치를 늘릴 필요 없이 topic의 커밋된 파일을 옆에서 읽으려면 다음 선택이 맞는다. ../compare 역시 아직 없는 새 폴더를 지정한다. 앞의 새 브랜치 방식과 목적에 따라 하나를 고르면 되며, 실험에서는 차이를 보기 위해 둘 다 만들었다.

git worktree add --detach ../compare topic
git -C ../compare branch --show-current
git -C ../compare rev-parse --short=7 HEAD

생성은 성공했고, branch --show-current는 출력 없이 종료 코드 0을 반환했다. 이어진 커밋 조회는 9c31849를 출력했다. 다시 읽은 worktree 목록에서도 이 폴더에는 branch refs/heads/... 대신 detached가 표시됐다. 브랜치 이름을 가리키지 않고 커밋을 직접 가리키는 상태다.

compare의 note.txt도 committed baseline이었다. 기존 owner의 미커밋 수정은 가져오지 않았으며, 앞서 topic-try에서 새 커밋을 만든 뒤에도 이 폴더는 원래 커밋에 남았다.

detached 상태가 파일 수정을 막는 읽기 전용 모드는 아니다. 수정과 커밋은 가능하지만 그 커밋에 새 브랜치 이름이 자동으로 붙지는 않는다. git-checkout의 detached HEAD 설명 (새 탭에서 열림)에서 이 차이를 확인할 수 있다. 남길 수정이 목적이라면 처음부터 앞의 새 브랜치 방식을 고르는 편이 분명하다. 여기서는 detached 상태의 커밋 생성과 복구는 실행하지 않았다.

기존 경로가 없거나 잠겨 있어도 바로 지우지 않는다

목록에 locked가 있으면 사유도 함께 읽는다. 실험용 owner에 잠금을 건 뒤에는 locked synthetic lab owner; preserve가 표시됐고, 같은 브랜치를 다시 추가하는 시도는 여전히 종료 코드 128로 거절됐다. 잠금 여부와 별개로 topic이 그 폴더에 연결돼 있었다.

실제 경로가 보이지 않는 경우에는 이동식 디스크나 네트워크 경로가 잠시 연결되지 않았을 수 있다. 폴더를 수동 이동해 등록 경로가 어긋났을 가능성도 있다. 공식 문서의 lock·repair 설명 (새 탭에서 열림)은 이런 상황을 구분한다. 이동한 worktree에는 연결 복구가 필요할 수 있으므로, 소유자와 현재 위치를 확인하기 전에 폴더 삭제나 prune, 강제 잠금 해제로 브랜치를 비우려 하지 않는다. prunable 표시도 그 작업을 버려도 좋다는 사용자 판단을 대신하지 않는다.

직접 실행한 범위는 Windows 11, Git 2.45.1.windows.1, PowerShell 7.6.6의 로컬 텍스트 저장소다. 동일 브랜치 거절, 새 브랜치와 detached HEAD의 생성·커밋 위치·파일 내용, 합성 worktree의 잠금 표시를 확인했다. 이동되거나 사라진 worktree의 복구·정리, 서브모듈과 다른 Git 버전은 시험하지 않았다. 기존 경로를 그대로 쓸지, 새 브랜치에서 수정할지, 커밋만 비교할지를 결정하는 데까지가 이 관찰의 범위다.

← 전체 글 보기