두 개의 프로젝트를 하나의 monorepo로 통합하고, 각 프로젝트의 git 이력을 모두 보존하면서 합치는 방법을 제시 합니다. 이 작업을 수행하려면 git의 subtree 혹은 submodule 기능을 사용할 수 있지만, 일반적으로 이력 병합과 유지의 목적으로는 subtree 방법이 더 많이 사용됩니다. 아래에 subtree를 이용해 이력을 유지하면서 두 개의 git 저장소를 하나의 monorepo로 합치는 방법을 설명합니다.
monorepo 설정 방법
1. 새로운 Monorepo 생성
먼저 새로운 monorepo를 위한 빈 저장소를 생성합니다.
mkdir monorepo
cd monorepo
git init
# monorepo에서 `HEAD` 참조 오류를 방지하기 위해 빈 초기 커밋을 생성합니다.
git commit --allow-empty -m "Initial commit for monorepo
2. 기존 프로젝트를 Subtree로 추가하기
이제 두 개의 기존 프로젝트를 subtree로 추가하여 각각의 git 이력을 보존할 수 있습니다. 다음의 예시에서는 두 개의 프로젝트가 project-A와 project-B라는 이름을 가지고 있다고 가정합니다.
순서를 지켜야 합니다.
2.1 프로젝트 A 추가
- 먼저 프로젝트 A의 원격 저장소를 추가합니다.
git remote add projectA <프로젝트_A_저장소_URL>
projectA의 모든 브랜치와 태그를 가져옵니다.
git fetch projectA main
- 프로젝트 A를 monorepo의 하위 디렉토리로 추가합니다. 이 때 이력을 유지하면서
project-A폴더에 추가됩니다.
git merge -s ours --allow-unrelated-histories --no-commit projectA/main
git read-tree --prefix=project-A/ -u projectA/main
git commit -m "Add project A as subtree"
위 명령어는 projectA의 이력을 보존하면서 project-A라는 하위 디렉토리에 프로젝트를 통합합니다.
2.2 프로젝트 B 추가
프로젝트 B도 비슷한 절차로 추가합니다.
- 프로젝트 B의 원격 저장소를 추가합니다.
git remote add projectB <프로젝트_B_저장소_URL>
projectB의 모든 브랜치와 태그를 가져옵니다.
git fetch projectB
- 프로젝트 B를 monorepo의 하위 디렉토리로 추가합니다.
git merge -s ours --allow-unrelated-histories --no-commit projectB/main
git read-tree --prefix=project-B/ -u projectB/main
git commit -m "Add project B as subtree"
3. Git 이력 확인하기
이제 git log를 실행하여 두 개의 프로젝트의 이력이 보존된 것을 확인할 수 있습니다. project-A와 project-B 각각의 폴더에 대한 이력들이 모두 유지되어 합쳐진 것을 확인할 수 있습니다.
참고사항
이 작업을 할 때 --allow-unrelated-histories 플래그를 사용하면 두 저장소의 서로 다른 이력을 합칠 수 있습니다. 이 플래그는 서로 무관한 두 히스토리를 병합할 때 필수적입니다. 또한, subtree 방식은 이력을 보존하면서 두 프로젝트를 통합할 수 있어 기존 히스토리를 유지하는 데 매우 유용합니다.
이렇게 하면 기존 프로젝트 각각의 이력을 모두 유지하면서 하나의 monorepo로 통합하여 관리할 수 있습니다.
monorepo 사용법
subtree 방식을 사용하여 프로젝트를 통합한 이후, 특정 프로젝트(project-A)의 이력만 보고 싶다면 디렉토리에 진입하지 않아도 Git 명령어를 사용하여 쉽게 이력을 필터링할 수 있습니다. 즉, 특정 디렉토리 (project-A/)에 대한 변경 사항만 추적하여 해당 프로젝트의 이력을 확인할 수 있습니다.
1. 이력관리
1.1 특정 디렉토리 이력 확인하기 (project-A)
git log 명령어를 사용하면서 -- <directory> 옵션을 추가하면 해당 디렉토리와 관련된 커밋만을 필터링해서 확인할 수 있습니다.
git log -- project-A/
이 명령은 project-A/ 디렉토리의 파일과 관련된 변경 사항만 포함한 커밋들을 보여줍니다. 즉, project-A의 이력을 분리해서 볼 수 있는 것입니다.
1.2 이력 확인 시 다양한 옵션 사용하기
git log에는 다양한 옵션을 조합할 수 있기 때문에 원하는 형태로 프로젝트의 이력을 쉽게 볼 수 있습니다. 예를 들어:
-
--oneline옵션을 추가해서 간단하게 요약된 형태로 볼 수 있습니다.git log --oneline -- project-A/ -
--stat옵션을 통해 파일 변경 내역을 요약해서 볼 수 있습니다.git log --stat -- project-A/ -
--graph옵션을 사용하여 그래프 형태로 브랜치와 병합 관계를 시각적으로 볼 수도 있습니다.git log --graph -- project-A/
1.3 디렉토리 이동 후 git log 확인
물론, project-A/ 디렉토리로 이동한 후에 git log를 실행해도 동일하게 해당 디렉토리와 관련된 이력만 확인할 수 있습니다.
cd project-A/ git log
이 방식은 project-A 디렉토리에 있는 상태에서 직접적으로 이력을 보고 싶을 때 유용합니다. 하지만 디렉토리에 진입하지 않고도 -- <directory> 옵션을 사용하면 전역적인 관점에서 project-A의 이력만 볼 수 있어서 더 편리할 때가 많습니다.
요약
- 특정 프로젝트의 이력만 보려면
git log -- project-A/와 같이-- <directory>옵션을 사용하여 필터링합니다. - 디렉토리에 진입하지 않고도, 특정 디렉토리와 관련된 이력을 확인할 수 있습니다.
이렇게 하면 subtree로 통합된 상태에서도 각각의 프로젝트 이력을 간편하게 조회할 수 있습니다.
subtree로 구성된 project-A에 대한 작업을 할 경우, 커밋을 어디서 진행하든 상관없이 최종적으로 monorepo의 이력에 통합됩니다. subtree 방식으로 프로젝트를 합친 후에는 monorepo의 모든 디렉토리와 파일이 하나의 Git 저장소로 관리되기 때문에, 커밋 위치에 따라 이력 관리 방식이 달라지지는 않습니다. 구체적으로 설명드리면 다음과 같습니다.
2. 커밋 관리
2.1 Monorepo의 최상위에서 Commit 하는 경우
-
상위 디렉토리에서 작업:
monorepo의 최상위 디렉토리에서 작업을 진행할 수 있습니다. -
커밋:
project-A폴더 내부 파일들을 수정한 후, 최상위 디렉토리에서 커밋을 실행하면project-A폴더의 변경 사항이 포함된 커밋이 기록됩니다.bash
코드 복사
# 상위 디렉토리에서 파일 수정 vim project-A/some-file.js # 상위 디렉토리에서 커밋 git add project-A/some-file.js git commit -m "Update some file in project A"이 경우 해당 커밋은 monorepo 전체의 이력에 포함되고,
git log -- project-A/를 통해 보면 이 커밋도project-A와 관련된 이력으로 확인됩니다.
2.2 project-A 디렉토리에서 직접 Commit 하는 경우
-
하위 디렉토리로 이동:
project-A디렉토리로 이동하여 작업을 진행할 수 있습니다. -
커밋:
project-A내부 파일을 수정한 후, 그 위치에서 커밋을 진행해도 마찬가지로 최상위monorepo의 이력에 통합됩니다.bash
코드 복사
# project-A 디렉토리로 이동 cd project-A # 파일 수정 vim some-file.js # 커밋 git add some-file.js git commit -m "Update some file in project A"이 경우에도 해당 커밋은 최상위 저장소의 이력에 포함되며,
git log에서 전체 이력의 일부로 보이게 됩니다.
3. 기타 관리 팁
- 브랜치 관리: 각 프로젝트의 변경 사항을 별도로 관리하기 위해 브랜치를 나누거나,
project-A및project-B와 관련된 작업을 구분할 수 있습니다. - CI/CD 파이프라인 설정: 두 프로젝트가 합쳐진 상태에서 빌드 및 테스트를 독립적으로 수행하기 위해 각 프로젝트에 맞는 CI/CD 파이프라인을 설정할 수 있습니다.
- 폴더 구조 유지: 각 프로젝트의 코드는
project-A/,project-B/와 같은 구조로 유지되므로 파일 구조가 명확하게 분리됩니다.
3.1 중요한 점: 통합된 저장소로서의 관리
subtree방식으로 monorepo를 구성하면, 두 프로젝트(project-A,project-B)는 이제 하나의 통합된 Git 저장소의 일부로 간주됩니다.- 이 통합된 저장소는 하나의
.git디렉토리만 가지며, 따라서 최상위 디렉토리든 하위 디렉토리에서 작업하든 모든 이력은 같은 저장소에 기록됩니다. 즉, 어느 디렉토리에서 커밋을 하든지 모든 작업은 동일한 Git 히스토리에 추가됩니다.
3.2 참고: 커밋 메시지와 컨벤션
- 커밋 메시지 관리: 각 하위 프로젝트에서 작업할 때는 커밋 메시지에 프로젝트 관련 내용을 명시하는 것이 좋습니다. 예를 들어,
[project-A] 새로운 기능 추가와 같이 명시적으로 표시하면 이력이 더 잘 정리됩니다. - 분리된 브랜치 관리: 각 하위 프로젝트가 독립적으로 관리될 수 있도록 각 프로젝트별로 브랜치를 운영하거나, PR(풀 리퀘스트)을 통해 변경 사항을 통합하는 것도 좋은 방법입니다. 이를 통해 작업을 분리하고 협업을 원활하게 할 수 있습니다.