[ Git 정복기 ] Git Submodule

Table of contents

Git Submodule의 이해
Git Submodule은 하나의 Git 리포지토리 안에 다른 Git 리포지토리를 포함할 수 있는 기능을 말합니다.
구조적이고 재사용 가능한 프로그램을 만들기 위해 **"공통으로 사용될 수 있는 코드는 모듈로 분리"**는 소프트웨어 개발의 중요한 철학에도 적용 됩니다.
예시로 “A 홈페이지” 를 관리하는 A-repo 와 “B 홈페이지” 를 관리하는 B-repo 가 있다고 가정합니다.
A와 B 홈페이지는 “C,D,E 팝업” 이 필요합니다. 만약 개발한다면 폴더 구조는 다음과 같겠죠?
A-repo/ -- A 홈페이지
└── src/
└── popup/
├── C/
├── D/
└── E/
B-repo/ -- B 홈페이지
└── src/
└── popup/
├── C/
├── D/
└── E/
이 방식에서는 코드가 중복되어 문제가 발생할 수 있습니다.
예를 들어, C 팝업에서 기능 수정이 필요할 때 A-repo를 수정한 뒤 B-repo에서도 동일한 수정이 필요합니다. 결국 일을 두 번 하게 됩니다.
“C, D, E 팝업”을 공통적으로 관리할 수 있도록 popup-repo를 생성하고, 이를 A-repo와 B-repo에 할당하는 방식은 어떨까요? (이 과정에서 popup-repo를 서브모듈로 추가하기 위해 .gitmodules
파일이 필요하게 됩니다..)
popup-repo/ -- A,B에서 사용하는 팝업
└── popup/
├── C/
├── D/
└── E/
A-repo/ -- A 홈페이지
└── .gitmodules
└── src/
└── popup/ (Git Submodule)
...C,D,E 팝업 존재
B-repo/ -- B 홈페이지
└── .gitmodules
└── src/
└── popup/ (Git Submodule)
...C,D,E, 팝업 존재
만약 C 팝업에서 기능 수정이 요구 된다면 popup-repo에서 한번만 수정하면 됩니다.
네, 결국 일을 한번만 하게 되네요. Git Submodule 덕분에 이런 구조가 가능해졌습니다.
Git Submodule 원리
Submodule은 A-repo에 직접적인 popup-repo 파일 복사가 아닌, 포함된 popup-repo의 특정 커밋을 참조합니다.
이 참조는 A-repo와 B-repo 의 .gitmodules란 파일에 저장되며, popup-repo(Submodule)의 위치와 URL 정보를 포함합니다.
# 서브모듈을 설정한 A-repo
A-repo/
└── **.gitmodules** -- 서브모듈 설정 파일
└── src/
└── popup/ (Git Submodule)
...C,D,E 팝업 존재
# A-repo의 .gitmodules 파일 내용
[submodule "src/popup"]
path = src/popup -- 서브모듈 저장할 A-repo 폴더 경로
url = https://github.com/example/popup-repo.git -- 서브모듈 Git 주소
branch = main -- 가져올 서브모듈의 브랜치
참고로, popup-repo에는
main
,develop
등의 브랜치가 존재할 수 있습니다.
특정 브랜치를 가져와야 할 경우, 아래와 같이 명시할 수 있으며, 이를 명시하지 않을 경우 popup-repo의 기본 브랜치(default branch)가 가져와집니다.
# A-repo가 popup-repo의 main 브랜치 코드 가져오는 경우
[submodule "src/popup"]
path = src/popup
url = https://github.com/example/popup-repo.git
branch = main
# A-repo가 popup-repo의 develop 브랜치 코드 가져오는 경우
[submodule "src/popup"]
path = src/popup
url = https://github.com/example/popup-repo.git
branch = develop
이걸 우리가 수동으로 만들어야 할까요? (물론 수동으로 해도 돼요.)
아닙니다. Git은 파일과 설정을 자동으로 만들 수 있도록 Git 명령어를 제공합니다.
Git Submodule 세팅하기
사이드 프로젝트로 진행 중인 Nettee Backend 팀에서 다음과 같이 Main Repo와 Submodule을 정했습니다.
Main Repository
Submodule
→ 목적은 샘플 데모 프로젝트를 한 곳에 모아 편히 볼 수 있도록 하였습니다.
(1) 먼저 Main Repository를 원하는 폴더 위치에 Git Clone을 해줍시다.
## Git Clone 명령어
git clone [Main Repository URL]
(2) Clone이 완료된 폴더로 들어가 Submodule을 추가해 줍니다.
## Git Submodule 추가 명령어
git submodule add [Submodule-url] [path]
여기서 [path]는 Main Repository에 Submodule을 포함시킬 하위 디렉토리 경로입니다.
하위 디렉토리가 Main Repository에 없으면 폴더는 자동 생성 됩니다.
저희는 hexagonal 이라는 폴더에 추가할 것입니다.
IDE ( IntelliJ 혹은 VSCode )에 Main Repository을 확인 해보시면 원하는 경로에 Submodule로 세팅이 되고 .gitmodules
가 추가 되었습니다.
해당 Submodule에 main
브랜치를 참조하기 위해 추가하였습니다.
(3) 이후 Git이 .gitmodules
파일에 기록된 정보를 사용할 수 있도록 설정 합니다.
## Git Submodule 초기화 및 업데이트
git submodule update --init
- 초기화 후에도 Submodule 파일은 비어 있을 수 있습니다. 업데이트를 통해 실제 데이터를 다운로드하고, 부모 리포지토리가 참조하는 커밋 상태로 동기화 합니다.
(4) Submodule을 추가한 내용을 커밋 후 Push 합니다.
## Git add. 및 push
git add .
git commit -m "Add Submodule"
git push origin [Main Reposiotory Branch]
(5) Github에 들어가 본인이 올린 Submodule이 잘 올라갔는지 확인합니다.
hexagonal @ a37974e 은 현재 Main Repository가 Submodule에 a37974e 커밋 시점을 바라보고 있다는 말입니다.
(6) 다른 팀원이 Submodule이 포함된 Main Repository를 가져올 때는 다음 명령어를 사용하면 됩니다.
이 명령어는 Submodule의 초기화와 업데이트 과정을 포함하여 Main Repository를 클론합니다.
git clone --recursive [Main Repository URL]
Subscribe to my newsletter
Read articles from silberbullet directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

silberbullet
silberbullet
모든 언어와 솔루션에 고정관념을 버리고 접근하며, MSA를 이해해보려는 개발자