최근에 비슷한 성격의 두 개의 레포지토리를 합치는 작업을 진행했다.
사실 첫 레포지토리를 잘못 생성하여 삭제하고 두 번쨰 레포지토리를 생성하였는데 삭제 후에 git commit 내용이 해당 날짜들에서 사라지게 되어 다시 복구하고 두 개의 레포지토리를 병합하기로 했다.(커밋 히스토리 유지하면서)
Git에서는 이러한 작업을 위한 다양한 명령어와 옵션을 제공하고 있어 이를 활용해 병합을 진행했다.
Git 레포지토리 병합의 기본 개념
Git 레포지토리 병합은 서로 다른 두 개 이상의 Git 프로젝트를 하나로 합치는 과정을 말한다.
이때 가장 중요한 것은 각 레포지토리의 커밋 히스토리를 유지하는 것이다.
Git에서는 히스토리가 없는 병합(git merge)과
히스토리를 유지하는 병합(git merge --allow-unrelated-histories)을 구분한다.
일반적인 git merge 명령은 공통 조상이 있는 브랜치 간의 병합을 위한 것이지만,
서로 다른 레포지토리를 병합할 때는 공통 조상이 없으므로 --allow-unrelated-histories 옵션이 필요하다.
레포지토리 병합의 기본 아이디어를 순차적으로 정리해봤다.
- 하나의 레포지토리를 기본(base) 레포지토리로 선택한다.
- 다른 레포지토리를 원격 저장소로 추가한다.
- 해당 원격 저장소의 브랜치를 가져와서 로컬 브랜치로 만든다.
- 파일 구조를 정리하여 충돌을 방지한다(보통 하위 디렉토리로 이동).
- 기본 브랜치와 병합한다.
(빠르게 읽으면 이해가 안되니 순차적으로 시간을 가지고 과정을 이해하면 좋을 것 같다.)
레포지토리 병합 단계별 과정
내 경우에는 'nextjs-practice'와 'NextJS_TS_practice'라는 두 개의 레포지토리를 병합했는데,
'NextJS_TS_practice'를 'nextjs-practice'로 통합하는 방식으로 진행했다.
그 과정을 단계별로 살펴보면 다음과 같다.
1. 기본 레포지토리 클론하기
먼저 유지할 메인 레포지토리를 클론한다.
이 레포지토리가 최종적으로 모든 코드와 히스토리를 포함하게 될 것이다.
git clone <첫 번째 레포지토리 URL>
cd <첫 번째 레포지토리 디렉토리>
내 경우에는 이미 로컬에 'nextjs-practice' 레포지토리가 클론되어 있었다.
2. 두 번째 레포지토리를 원격 저장소로 추가하기
다음으로 병합할 두 번째 레포지토리를 원격 저장소로 추가한다.
이 단계에서는 아직 실제 파일은 가져오지 않고, 해당 레포지토리의 위치만 설정한다.
git remote add second-repo <두 번째 레포지토리 URL>
git fetch second-repo
내 경우에는 로컬에 있는 'NextJS_TS_practice' 레포지토리를 다음과 같이 추가했다.
git remote add second-repo ../NextJS_TS_practice
git fetch second-repo
3. 두 번째 레포지토리의 브랜치 체크아웃하기
두 번째 레포지토리의 브랜치를 새로운 로컬 브랜치로 체크아웃한다.
이렇게 하면 해당 레포지토리의 파일과 커밋 히스토리를 가져올 수 있다.
git checkout -b second-repo-branch second-repo/main
이 명령어는 두 번째 레포지토리의 'main' 브랜치를 'second-repo-branch'라는 새 브랜치로 체크아웃한다.
4. 파일 구조 정리하기
두 레포지토리의 파일 구조가 충돌하지 않도록 하위 디렉토리로 옮긴다.
이 단계는 파일 구조를 명확하게 하고 병합 시 충돌을 최소화하기 위한 중요한 과정이다.
mkdir <통합할 디렉토리 이름>
git ls-files | xargs -I{} git mv {} <통합할 디렉토리 이름>/
내 경우에는 'typescript-practice'라는 디렉토리를 만들어 파일을 이동했다.
mkdir typescript-practice
git ls-files | xargs -I{} git mv {} typescript-practice/
Git에서 추적하지 않는 파일(예: node_modules, 빌드 파일 등)은 별도로 이동해야 하지만
node_modules나 빌드 파일 같은 경우엔 용량이 크기에 대용량 파일 문제가 발생할 수도 있다. (GitHub는 100MB 이상의 파일을 푸시할 수 없게 제한 하고 있음)
따라서 꼭 필요한게 아니면 하위 디렉토리로 옮기지 않아도 될 것 같다.!!!
마지막으로 이동한 파일을 커밋한다.
git add .
git commit -m "Move second repo into subdirectory"
5. 브랜치 병합하기
이제 원래 브랜치로 돌아가서 준비한 브랜치를 병합한다.
이때 --allow-unrelated-histories 옵션을 사용하여 서로 관련 없는 히스토리를 병합할 수 있게 한다.
git checkout main
git merge --allow-unrelated-histories second-repo-branch
병합 과정에서 충돌이 발생할 수 있으며, 이 경우 수동으로 충돌을 해결하고 병합을 완료해야 한다.
6. 정리 및 푸시하기
병합이 완료되면 임시 브랜치와 원격 저장소를 제거한다.
git branch -D second-repo-branch
git remote remove second-repo
이제 변경사항을 원격 저장소에 푸시하면 된다!!!
git push origin main