저장소 분리
규모가 큰 프로젝트를 효과적으로 관리하기 위해, 프로젝트를 작은 단위로 분리하여 관리하는 방식이 많이 사용된다. 이를 위해 Git은 서브모듈(Submodule) 이라는 개념을 제공한다.
서브모듈은 하나의 Git 저장소가 다른 Git 저장소를 포함하는 형태로, 대형 프로젝트를 모듈화하여 독립적으로 관리할 수 있도록 도와준다. 각각의 기능을 독립된 저장소로 분리하여 관리하며, 독립적으로 관리된 저장소들은 다시 메인 저장소(Main Repository) 와 결합하여 재사용된다. 이러한 방식은 프로젝트의 유지 보수성과 확장성을 크게 향상시킨다.
서브 모듈 추가
부모 저장소와 자식 저장소를 생성하고 각각 원격 저장소에 연결해준 상황이다.
submodule 명령어의 add 옵션은 부모 저장소에 자식 저장소를 추가하며 서브 모듈로 저장소가 추가되면 부모 저장소는 자식 저장소를 서브 폴더 형태로 취급한다. 서브 폴더는 서브 모듈로 분리한 독립된 깃 저장소이다.
$ git submodule add https://github.com/bde574786/child-repo.git
$ git submodule add https://github.com/bde574786/child-repo.git <디렉토리> # 디렉토리 이름 지정
자식의 원격 저장소가 child-repo 폴더에 복제되었고, 서브 모듈의 설정 파일인 .gitmodules가 추가되었다.
처음으로 부모 저장소에 서브 모듈이 등록되면 깃은 루트 위치에 .gitmodules라는 설정 파일을 생성한다. 설정 파일은 숨김 파일 형태로 관리되며 부모 저장소와 연결된 자식 저장소를 관리한다.
모듈 커밋
부모 저장소와 서브 모듈인 자식 저장소 간 관계를 지속적으로 유지하려면 추가된 정보들을 계속 가지고 있어야 한다. 부모 저장소가 자식들의 정보를 계속 가지려면 이를 커밋하여 저장해야 한다. 따라서, 서브 모듈 환경 설정 파일인 .gitmodules 파일을 등록하고 커밋한다.
부모 저장소 내부 서브 모듈에서 직접 작업
부모 저장소에 복제한 자식 저장소에서 수정 작업을 하고 수정 내역의 커밋을 자식 저장소의 원격 저장소를 거쳐 실제 자식 저장소에 반영할 수 있다.
서브 모듈 작업
자식 저장소는 독립된 깃 저장소이므로 자식 저장소 내부에서는 일반 깃 저장소처럼 변경된 파일을 추적한다. 모든 커밋, 푸시, 풀 명령어는 자식 저장소 안에서만 적용된다.
부모 저장소 갱신
부모 저장소는 자식 저장소의 내용이 아닌 커밋 ID를 추적한다. 따라서, 부모 저장소에 자식 저장소의 변경 사항을 반영하려면 부모 저장소에서 업데이트해야 한다.
자식 저장소 갱신
서브 모듈로 연결된 자식 저장소는 부모 저장소의 원격 저장소로 푸시되어도, 자식 저장소 자체의 원격 저장소에는 반영되지 않는다. 따라서, 두 저장소는 아직 동일한 커밋 정보를 가지고 있지 않기 때문에 자식 저장소에 연결된 원격 저장소를 이용하여 실제 자식 저장소를 최신 커밋 정보로 갱신해야 한다.
실제 자식 저장소에서 작업
반대로 실제 자식 저장소에서 코드를 수정하고, 이를 자식 저장소의 원격 저장소를 거쳐 부모 저장소의 서브 모듈로 적용할 수도 있다.
자식 저장소 작업
서브 모듈이 아닌 실제 자식 저장소를 의미한다.
서브 모듈 갱신
실제 자식 저장소에서 변경한 커밋을 부모 저장소의 서브 모듈에 반영하는 과정이다.
부모 저장소 갱신
서브 모듈을 갱신하면 부모 저장소는 자신의 서브 폴더가 변경된 것을 인식한다. 즉, 부모 저장소는 서브 모듈의 변경 내용을 모니터링하고 있는 것이다. 부모 저장소의 서브 폴더 자체를 변경했기 때문에 변경된 내용을 다시 부모 저장소로 커밋해야 한다.
부모 저장소 복제
부모 저장소를 복제하면 서브 모듈에 대한 .gitmodules 설정 파일을 확인할 수 있지만 서브 모듈 폴더 안에는 아무 내용도 없다. 따라서, 서브 모듈의 저장소를 복제하거나 배포할 때는 부모/자식 관계도 같이 복제해야 한다.
모듈 업데이트
서브 모듈의 자식 저장소는 직접 명령어를 실행하여 가져와야 하며 자식 저장소의 내용을 가져오려면 먼저 초기화와 갱신 작업을 해야 한다. 부모 저장소가 지정한 커밋을 자식 저장소를 맞춰주는 것으로 서브 모듈은 pull이 아닌 update를 사용한다.
$ git submodule init
$ git submodule update
부모 저장소는 자식 저장소를 폴더처럼 포함하고 있지만, 실제로는 자식 저장소의 특정 커밋 해시만 기억하고 있을 뿐이다. 저장소를 클론한 직후에는 서브 모듈 디렉토리가 비어있지만 git submodule update를 실행하면 부모가 기억하고 있는 커밋 정보를 기반으로 자식 저장소의 원격 저장소에서 해당 커밋을 가져와 체크아웃하게 된다. 결과적으로, 서브 모듈 디렉토리는 해당 커밋 시점의 코드로 채워지게 된다.
부모 저장소 업데이트
부모 업데이트
서브 모듈 형태로 구성된 부모/자식 저장소도 커밋을 갱신한다. 새로운 자식 저장소를 추가하거나 자식 저장소를 갱신할 때 부모 저장소의 설정 파일과 폴더가 변경되기 때문이다. 따라서 자식 저장소에 코드 수정으로 커밋이 발생하면, 부모에도 자연스럽게 새로운 커밋이 발생한다. 갱신된 부모 저장소 내용을 정기적으로 갱신하여 서브 모듈 상태를 최신으로 유지해야 한다.
부모 저장소로 풀
하위 저장소에 새로운 커밋이 생성되면 메인 저장소는 이를 반영한다. 메인 저장소에는 반영한 하위 저장소의 변경된 내용 때문에 추가 커밋이 발생할 수도 있고 최신 커밋의 의해 서브 모듈이 가리키는 커밋이 바뀌었을 수도 있다. 자신이 메인 저장소를 복제하여 운영하고 있다면, 메인 저장소를 주기적으로 풀(pull) 해야 한다.
$ git pull origin main
하지만, 부모 저장소를 풀했다고 해서 부모 저장소에 종속된 자식 저장소까지 자동으로 갱신되지는 않는다. 다음과 같이 서브 모듈의 업데이트는 별도로 명령어를 실행해 주어야 한다.
$ git submodule update
'Git' 카테고리의 다른 글
참조 기록(reflog) (0) | 2025.04.08 |
---|---|
참조(refs) (0) | 2025.04.08 |
배포 관리 (0) | 2025.03.27 |
커밋 복귀 (0) | 2025.03.25 |
리베이스(rebase) (0) | 2025.03.24 |