블로그 회사 시스템 구축기

git worktree로 작업 중인 브랜치를 두고 main만 꺼내 배포하기

작업 중인 브랜치를 stash로 치우지 않고, git worktree로 main을 옆 폴더에 따로 열어 배포하는 방법입니다. add·list·remove 명령, .env와 node_modules가 따라오지 않는 점, remove가 거부되는 경우까지 정리했습니다.

6월에 홈페이지 레포가 큰 개편 작업 중이라 feature 브랜치를 건드릴 수 없는 상태에서 블로그 글을 배포해야 했습니다. 하던 작업을 git stash로 치우고 main으로 옮겼다가 다시 돌아오는 대신, git worktree add로 main만 옆 폴더에 따로 열고 거기서 배포했습니다. 작업하던 폴더는 손대지 않은 그대로 남았습니다.

배포하는 사이에 개편 브랜치가 PR로 main에 머지됐는데, 블로그 커밋을 새 main 위로 rebase하니 충돌 0건이었고 그대로 다시 배포했습니다. 이 글은 그때 쓴 방법을 명령어 순서대로 적은 것입니다.

git worktree가 하는 일

git worktree는 저장소 하나를 여러 폴더에 동시에 펼쳐 줍니다. 클론을 하나 더 받는 게 아니라 .git 저장소는 하나를 같이 쓰고, 작업 트리만 폴더마다 따로 둡니다. 그래서 한쪽 폴더에서 만든 커밋과 브랜치를 다른 폴더에서도 바로 볼 수 있습니다.

git stash와 git checkout은 작업 폴더 하나 안에서 브랜치를 갈아 끼웁니다. 한 번에 한 브랜치만 펼쳐 둘 수 있고, 옮길 때마다 파일 전체가 그 브랜치 상태로 바뀌며, 빌드 결과도 같이 덮어써져서 돌아오면 다시 빌드해야 하는 경우가 많습니다. stash는 치워 둔 변경을 나중에 다시 얹는 방식이라, 그사이 같은 파일이 바뀌었으면 풀 때 충돌이 납니다.

worktree를 쓰면 작업하던 폴더는 그대로 두고 옆에 폴더를 하나 더 만들기 때문에, 치워 둔 변경을 다시 얹다가 충돌이 나는 일이 없습니다.

저장소 하나를 공유하는 main 폴더와 작업 폴더, 그리고 새 폴더로 따라오지 않는 파일을 나눈 그림

작업 중에 main만 꺼내 배포하는 순서

작업 폴더가 core이고 지금 feature 브랜치에 있다고 하면 순서는 이렇습니다.

# 1. 옆 폴더에 main을 따로 연다 (작업 폴더는 그대로)
git worktree add ../core-deploy main

# 2. 그 폴더로 가서 최신으로 맞추고 배포한다
cd ../core-deploy
git pull
# 수정 → 빌드 → 배포

# 3. 끝나면 원래 작업 폴더로 돌아온다
cd ../core

# 4. 다 쓴 폴더를 치운다
git worktree remove ../core-deploy

1번은 지금 작업 폴더가 main이 아닐 때만 됩니다. 이미 main이 열린 폴더가 있으면 거기서 그냥 배포하면 됩니다. 이유는 아래 “같은 브랜치를 두 폴더에서 못 여는 이유”에 적었습니다.

add · list · remove 기본 명령

자주 쓰는 건 세 개입니다.

# 이미 있는 브랜치를 옆 폴더에 연다
git worktree add ../core-feature feature/worktree-x

# 새 브랜치를 만들면서 동시에 연다
git worktree add -b feature/new-x ../core-new-x

# 지금 열려 있는 폴더 목록과 각자 어느 브랜치인지
git worktree list

# 다 쓴 폴더를 치운다
git worktree remove ../core-feature

git worktree list 출력은 이런 모양입니다.

/Users/me/work/core           a1b2c3d [main]
/Users/me/work/core-feature   e4f5g6h [feature/worktree-x]

원래 레포가 main worktree이고, add로 만든 폴더가 추가 worktree입니다. 브랜치 이름 대신 (detached HEAD)로 나오는 줄은 --detach로 특정 커밋만 열어 둔 폴더입니다.

.env와 node_modules는 새 폴더에 없다

새 worktree에는 git이 추적하는 파일만 채워집니다. .gitignore에 걸린 .env, node_modules/, build/ 같은 파일은 따라오지 않습니다. 그래서 새 폴더에서 바로 빌드하면 의존성이 없거나 환경 변수가 비어서 실패할 수 있습니다.

새 폴더를 만든 뒤에 할 일은 두 가지입니다.

  1. 의존성을 다시 설치합니다 (npm install 같은 명령).
  2. .env를 놓습니다. 복사해 두면 한쪽만 고쳐지기 쉬우니, 원래 폴더의 파일을 심볼릭 링크로 거는 편이 관리가 낫습니다.
ln -s ../core/.env ../core-feature/.env

그 덕분에 작업 폴더에서 빌드해도 main 폴더의 빌드 결과는 덮어쓰지 않습니다. 대신 폴더마다 의존성과 빌드 캐시가 따로 쌓이니, 빌드가 무거운 프로젝트라면 디스크 사용량이 늘어납니다.

같은 브랜치를 두 폴더에서 못 여는 이유

한 브랜치는 한 worktree에만 체크아웃할 수 있습니다. main이 이미 원래 폴더에 열려 있는데 다른 폴더에서 또 main을 열려고 하면 거부됩니다.

git worktree add ../core-2 main
# fatal: 'main' is already checked out at '/Users/me/work/core'

git 버전에 따라 문구는 조금 다를 수 있습니다. 공식 문서 기준으로 --force를 주면 이 안전장치를 넘길 수 있지만, 같은 브랜치를 두 폴더에서 동시에 고치면 어느 쪽이 맞는 상태인지 헷갈리기 쉽습니다. 작업용 폴더는 항상 별도 브랜치로 만드는 편이 낫습니다.

worktree remove가 거부될 때

git worktree remove는 깨끗한 폴더만 지웁니다. git 공식 문서에 따르면 추적하지 않는 파일이 있거나 추적 파일에 수정이 있으면 거부되고, --force를 줘야 지워집니다. 잠근(lock) worktree는 --force를 두 번 줘야 합니다.

상황할 일
수정한 파일이 남아 있음커밋하거나, 버릴 거면 --force
폴더를 rm으로 먼저 지움git worktree prune
폴더를 다른 곳으로 옮기려 함git worktree move, 이미 옮겼으면 git worktree repair
외장 디스크에 둔 폴더git worktree lock으로 정리 대상에서 뺌

폴더를 rm으로 지우면 .git/worktrees 안에 그 폴더 정보가 남습니다. prune이 이 남은 정보를 치웁니다. 처음부터 remove로 지우면 이 단계가 필요 없습니다. 위 표의 명령 설명은 2026년 10월에 확인한 공식 문서(2.56.0 기준) 내용이고, 제가 쓰는 맥의 git은 2.50.1입니다.

혼자 배포할 때 폴더를 나눠 두는 방식

main이 열린 폴더는 늘 배포할 수 있는 상태로 두고, 기능 작업은 별도 폴더에서 합니다.

  • 급한 수정이 생기면 작업 폴더는 그대로 두고 main 폴더로 가서 고치고 배포합니다.
  • 한 폴더에서 긴 빌드가 도는 동안 다른 폴더에서 계속 작업할 수 있습니다.
  • 남의 브랜치를 리뷰할 때도 별도 폴더로 열면 내 작업 브랜치를 건드리지 않고 돌려 볼 수 있습니다.

AI에게 레포 작업을 맡길 때도 같은 이유로 씁니다. 텔레그램으로 받은 작업을 맥 미니에서 Claude Code로 돌리는 워커 지시서에는, 작업마다 git worktree add ../wo-<id> -b wo/<id>-<slug> origin/main으로 폴더를 따로 만들고 끝나면 지우는 순서를 적어 뒀습니다. 제가 쓰는 폴더와 AI가 고치는 폴더가 겹치지 않게 하려는 것입니다. 새벽에 AI 작업을 몰아서 돌리는 구조는 새벽 AI 워커 글에, 배포를 집 컴퓨터에서 돌리는 방법은 GitHub Actions self-hosted 러너 글에 적어 두었습니다.

자주 묻는 질문

git worktree는 git stash·checkout과 뭐가 다른가요?

stash와 checkout은 작업 디렉토리 하나를 공유해 한 번에 한 브랜치만 펼칠 수 있습니다. worktree는 브랜치마다 별도 디렉토리를 만들어 여러 브랜치를 동시에 체크아웃하므로, 전환할 때 작업 트리가 덮어쓰이지 않고 재빌드도 없습니다.

worktree를 만들면 .env나 빌드 결과도 같이 복사되나요?

복사되지 않습니다. worktree는 git이 추적하는 파일만 채우고, .gitignore에 걸린 .env·build·node_modules 같은 비추적 파일은 새 디렉토리에 없습니다. 의존성 설치나 .env 배치를 한 번 더 해야 하며, .env는 공통 위치를 심볼릭 링크로 거는 편이 관리가 낫습니다.

같은 브랜치를 두 worktree에서 동시에 열 수 있나요?

없습니다. 한 브랜치는 하나의 worktree에만 체크아웃됩니다. 작업용 디렉토리를 항상 별도 브랜치로 만들면 이 충돌을 피할 수 있습니다.

다 쓴 worktree는 어떻게 정리하나요?

git worktree remove 명령으로 정리합니다. 디렉토리를 rm으로 직접 지웠다면 git worktree prune으로 남은 메타데이터를 청소합니다. 커밋·푸시하지 않은 변경이 있으면 git이 remove를 막으니, 의도적으로 버릴 때만 --force를 씁니다.

#git worktree#git#브랜치 전략#배포#1인 개발