프로젝트를 진행하다 보면 여러 레포지토리를 하나로 합치거나, 반대로 하나의 큰 레포지토리를 여러 개로 분리해야 할 때가 있습니다. 이 글에서는 git subtree 명령어를 활용해 레포지토리를 자유자재로 통합하고 분리하는 방법을 알아보겠습니다.
들어가며: 왜 레포지토리를 합치거나 분리할까?
합치는 경우 (Monorepo)
- 관련된 여러 프로젝트를 한 곳에서 관리하고 싶을 때
- 공통 코드나 설정을 쉽게 공유하고 싶을 때
- 의존성 관리를 단순화하고 싶을 때
분리하는 경우 (Multi-repo)
- 특정 모듈을 독립적인 라이브러리로 배포하고 싶을 때
- 팀별로 레포지토리를 분리해서 관리하고 싶을 때
- 레포지토리가 너무 커져서 가볍게 만들고 싶을 때
git subtree란?
git subtree는 Git에 기본 내장된 명령어로, 다른 레포지토리를 현재 레포지토리의 하위 디렉토리로 포함시키거나, 특정 디렉토리를 별도의 레포지토리로 분리할 수 있게 해줍니다.
비슷한 기능인 git submodule과 비교하면 다음과 같은 차이가 있습니다.
| 특성 | subtree | submodule |
|---|---|---|
| 코드 포함 방식 | 완전히 복사됨 | 링크로 연결 |
| 관리 복잡도 | 단순함 | 복잡함 |
| clone 시 | 자동 포함 | 별도 명령 필요 |
| 커밋 히스토리 | 통합됨 | 분리됨 |
대부분의 경우 subtree가 더 직관적이고 관리하기 쉽습니다.
여러 레포지토리를 하나로 합치기
시나리오
frontend, backend, common 세 개의 레포지토리를 my-project라는 하나의 모노레포로 합친다고 가정합니다.
1단계: 새 레포지토리 생성
mkdir my-project
cd my-project
git init
2단계: 첫 번째 커밋 생성
echo "# My Project" > README.md
git add README.md
git commit -m "Initial commit"
3단계: 각 레포지토리를 subtree로 추가
# frontend 레포지토리 추가
git subtree add --prefix=frontend https://github.com/username/frontend.git main
# backend 레포지토리 추가
git subtree add --prefix=backend https://github.com/username/backend.git main
# common 레포지토리 추가
git subtree add --prefix=common https://github.com/username/common.git main
4단계: 결과 확인 및 push
# 구조 확인
ls -la
# GitHub에 push
git remote add origin https://github.com/username/my-project.git
git push -u origin main
최종 구조
my-project/
├── README.md
├── frontend/
│ └── (frontend 레포의 모든 파일)
├── backend/
│ └── (backend 레포의 모든 파일)
└── common/
└── (common 레포의 모든 파일)
각 폴더에는 원본 레포지토리의 커밋 히스토리가 그대로 보존됩니다.
하나의 레포지토리를 여러 개로 분리하기
시나리오
my-project 모노레포에서 common 폴더를 독립적인 레포지토리로 분리한다고 가정합니다.
1단계: subtree split으로 브랜치 생성
cd my-project
git subtree split --prefix=common -b common-branch
이 명령은 common 폴더의 히스토리만 추출해서 common-branch라는 브랜치를 생성합니다.
2단계: 새 레포지토리 생성 및 코드 이동
# 새 디렉토리 생성
cd ..
mkdir common-repo
cd common-repo
git init
# 분리한 브랜치 가져오기
git pull ../my-project common-branch
3단계: GitHub에 push
git remote add origin https://github.com/username/common.git
git push -u origin main
4단계: 원본 레포에서 폴더 제거 (선택사항)
분리 후 원본 모노레포에서 해당 폴더를 제거하고 싶다면:
cd ../my-project
git rm -r common
git commit -m "Remove common folder (moved to separate repo)"
git push
실전 팁
1. 커밋 히스토리 보존 확인
합치거나 분리한 후에는 반드시 git log로 히스토리가 제대로 보존되었는지 확인하세요.
git log --oneline --graph
2. 원격 레포지토리 정리
합친 후 기존 레포지토리들을 어떻게 처리할지 결정해야 합니다.
- Archive: 읽기 전용으로 보관 (GitHub Settings → Archive)
- Delete: 완전히 삭제
- README 업데이트: 새 레포지토리로 이동했다는 안내 추가
3. squash 옵션 활용
히스토리를 보존하지 않고 하나의 커밋으로 합치고 싶다면 --squash 옵션을 사용합니다.
git subtree add --prefix=frontend https://github.com/username/frontend.git main --squash
4. 이후 업데이트 반영하기
원본 레포지토리에 변경사항이 생겼을 때 가져오려면:
git subtree pull --prefix=frontend https://github.com/username/frontend.git main
주의사항
- 충돌 가능성: 합칠 때 파일명이 겹치면 충돌이 발생할 수 있습니다. 미리 구조를 확인하세요.
- 대용량 레포지토리: 히스토리가 많은 레포지토리를 합치면 시간이 오래 걸릴 수 있습니다.
- GitHub UI 미지원: 이 작업들은 GitHub 웹 인터페이스에서는 할 수 없습니다. 반드시 로컬 Git 클라이언트를 사용해야 합니다.
- 팀 공유: 모노레포 전환 시 팀원들에게 미리 공지하고, 기존 레포지토리의 PR/이슈를 정리하세요.
마치며
git subtree를 활용하면 프로젝트 구조를 유연하게 변경할 수 있습니다. 모노레포와 멀티레포 각각의 장단점을 고려해서 프로젝트에 맞는 구조를 선택하시기 바랍니다.