Git Submodule

Git Submodule 은 하나의 Git 저장소 안에 또 다른 Git 저장소를 포함시킬 수 있도록 하는 기능이다. 이는 외부 라이브러리, 공통 모듈, 또는 서드파티 코드 등을 독립적으로 유지하며 주 저장소와 연동하여 사용하는 데 활용된다.

서브모듈은 특정 커밋을 참조하는 방식으로 작동하며, 주 저장소 (부모 저장소) 와 서브모듈 저장소 (자식 저장소) 간의 명확한 경계를 유지한다.

복잡한 프로젝트 구조에서 모듈화를 실현하고, 공통 코드의 버전 동기화 및 유지관리를 용이하게 한다.

핵심 개념

Git Submodule은 한 Git 저장소 (부모 저장소) 내에 다른 Git 저장소 (자식 저장소) 를 현재 저장소의 하위 디렉토리로 포함시키는 방식이다. 서브모듈은 다른 외부 저장소의 특정 커밋을 가리키는 주 저장소 내의 기록이다. 서브모듈은 매우 정적이며 특정 커밋만 추적한다.

목적

Git 서브모듈의 주요 목적은 다음과 같다:

  1. 코드 재사용: Git 서브모듈은 참조를 통해 다른 Git 저장소를 포함할 수 있게 해준다. 공유 코드가 필요한 일반적인 사용 사례에 적합하다.
  2. 외부 의존성 관리: 코드 저장소는 종종 외부 코드에 의존합니다. 서브모듈은 외부 코드의 버전 기록을 통합하고 추적할 수 있게 해준다.
  3. 모듈식 개발: 서브모듈을 사용하면 코드베이스를 더 작고 관리하기 쉬운 부분으로 나눌 수 있다.

필요성

Git 서브모듈은 다음과 같은 상황에서 특히 필요하다:

  1. 외부 구성 요소나 하위 프로젝트가 너무 빠르게 변경되거나 향후 변경 사항이 API 를 손상시킬 수 있을 때, 안전을 위해 코드를 특정 커밋에 고정할 수 있다.
  2. 코드 중복을 피하면서 여러 프로젝트에서 동일한 코드베이스를 사용할 때
  3. 다른 원격 저장소에 저장된 여러 프로젝트와 라이브러리에 의존하는 프로젝트를 복제할 때, 단일 로컬 저장소에 이러한 모든 의존성을 포함해야 할 필요가 있다.

주요 기능

  1. 특정 커밋 참조: 서브모듈은 부모 프로젝트에 지정된 정확한 커밋에 의해 추적되며, 브랜치나 참조, 또는 다른 심볼릭 참조가 아니다.
  2. 독립적 이력 유지: 서브모듈은 자체 Git 저장소로서 자신만의 이력을 가지며, 부모 저장소와는 별개로 관리된다.
  3. 버전 고정: 서브모듈은 부모 저장소에서 특정 커밋을 가리켜 의존성 버전을 고정한다.
  4. 선택적 업데이트: 서브모듈은 부모 저장소에서 명시적으로 업데이트 명령을 실행할 때만 업데이트된다.

역할

Git 서브모듈은 다음과 같은 역할을 수행한다:

  1. 의존성 관리자: 외부 코드 의존성을 효과적으로 관리한다.
  2. 모듈 통합자: 여러 독립적인 코드베이스를 단일 프로젝트로 통합한다.
  3. 버전 컨트롤러: 외부 의존성의 특정 버전을 고정하여 안정성을 보장한다.
  4. 코드 공유 촉진자: 여러 프로젝트 간에 코드 재사용을 용이하게 한다.

특징

  1. 정적 참조: 서브모듈은 매우 정적이다. 서브모듈을 이용해 특정 커밋을 추적하며, 브랜치나 참조가 아닌 단일 커밋을 가리킨다.
  2. 독립적인 저장소: Git 서브모듈은 기술적으로 완전한 기능을 갖춘 표준 Git 저장소이다. 다른 부모 Git 저장소 내에 위치한다는 것만이 차이점이다.
  3. .gitmodules 파일: 저장소에 서브모듈을 추가하면 새로운.gitmodules 파일이 생성된다. 이 파일은 서브모듈 프로젝트의 URL 과 로컬 디렉토리 간의 매핑에 대한 메타데이터를 포함한다.
  4. 명시적 초기화 및 업데이트: 서브모듈은 git clone 후 명시적으로 초기화하고 업데이트해야 한다.

핵심 원칙 및 작동 원리

핵심 원칙

  1. 분리된 이력: 서브모듈과 부모 저장소는 각각 독립적인 커밋 이력을 유지한다.
  2. 명시적 참조: 부모 저장소는 서브모듈의 특정 커밋을 명시적으로 참조한다.
  3. 수동 동기화: 서브모듈의 변경사항은 부모 저장소에 수동으로 동기화해야 한다.
  4. 최소 침해: git-meta 의 배후에 있는 원칙 중 하나는 " 일반 " Git 에서 가능한 한 적게 벗어나는 것이다. 가능한 경우 바닐라 Git 명령어를 사용하고, Git 의 기본 분산 모델을 유지하고자 했다.

작동 원리

Git 서브모듈의 작동 원리는 다음과 같다:

  1. 서브모듈 추가: git submodule add <url> <path> 명령어로 서브모듈을 추가하면, Git 은 지정된 URL 에서 저장소를 클론하고 지정된 경로에 배치한다.
  2. 프로젝트 폴더에 .gitmodules 파일이 생성된다.
  3. 참조 저장: 부모 저장소는 서브모듈의 현재 커밋 ID 를 저장하며, 이 정보는 부모 저장소의 커밋에 포함된다.
  4. 클론 및 초기화: 서브모듈이 있는 저장소를 클론할 때, 서브모듈 코드는 자동으로 함께 클론되지 않는다. ‘git submodule init’ 과 ‘git submodule update’ 명령어를 사용하여 서브모듈을 초기화하고 코드를 가져와야 한다.
  5. 상태 추적: 부모 저장소의 관점에서, Git 은 ‘src/common’ 과 같은 마운트 포인트 경로가 가상 파일인 것처럼 취급하며, 이 파일의 내용은 체크아웃되어야 하는 서브모듈의 커밋 해시이다.
  6. 업데이트 메커니즘: 서브모듈이 업데이트되면, 부모 저장소는 새로운 커밋 ID 를 가리키도록 업데이트되어야 한다.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 서브모듈 추가 
git submodule add https://github.com/example/repo.git lib/SubmoduleRepo/

MainRepo/
 ├── .gitmodules
 ├── lib/
 │    └── SubmoduleRepo/ (Git repo)
 
# 초기화 및 업데이트 
git submodule update --init --recursive
  • .gitmodules 에 Submodule 경로와 URL 기록
  • Submodule 은 해당 커밋을 기준으로 checkout 됨
  • git submodule update, git submodule init, git submodule sync 등 명령어로 관리

구성 요소

Git 서브모듈 시스템의 주요 구성 요소는 다음과 같다:

  1. 부모 저장소 (Parent Repository): 다른 Git 저장소를 포함하는 주 저장소이다.
  2. 서브모듈 저장소 (Submodule Repository): 부모 저장소 내에 포함된 독립적인 Git 저장소이다.
  3. .gitmodules 파일:.gitmodules 파일은 부모 저장소의 서브모듈에 대한 정보를 포함하는 설정 파일이다. 각 서브모듈에 대해 부모 저장소 내의 상대적인 " 마운트 포인트 " 경로와 Git 원격 URL 을 포함한다.
  4. 커밋 참조 (Commit Reference): 부모 저장소에 저장된 서브모듈의 특정 커밋을 가리키는 참조이다.
  5. Git 명령어 및 도구: git submodule 명령어와 그 하위 명령어들 (add, init, update, foreach 등)
graph TD
A[부모 저장소] --> B[.gitmodules 파일]
B --> C[서브모듈 경로]
C --> D[외부 저장소 커밋 참조]

아키텍처

Git 서브모듈의 아키텍처는 계층적 저장소 구조를 기반으로 한다:

1
2
3
4
5
6
7
8
부모_저장소/
├── .git/               # 부모 저장소의 Git 디렉토리
│   ├── config          # 로컬에서 Submodule 의 Git 설정이 저장되는 위치    
├── .gitmodules         # 서브모듈 설정 파일
├── 일반_파일들/         # 부모 저장소의 파일들
└── 서브모듈_디렉토리/    # 서브모듈의 경로
    ├── .git            # 서브모듈의 Git 디렉토리 (실제로는 참조 파일)
    └── 서브모듈_파일들/  # 서브모듈의 파일들

서브모듈의 .git 디렉토리는 실제로는 부모 저장소의 .git/modules/ 디렉토리 내 해당 서브모듈의 Git 데이터를 가리키는 참조 파일이다. 이렇게 함으로써 서브모듈이 부모 저장소 내에 존재하면서도 독립적인 Git 저장소로 기능할 수 있다.

Submodule 명령어

Submodule 생성 및 추가

1
2
3
4
# Submodule 추가
$ git submodule add <저장소 URL> <경로>
# 특정 브랜치를 submodule로 추가
$ git submodule add -b <branch_name> <repository_url> [path]

Submodule 이 있는 프로젝트 클론

1
2
3
4
5
6
7
# Submodule이 있는 프로젝트 클론
$ git clone <저장소 URL>
$ git submodule init
$ git submodule update

# 또는 한번에 클론
$ git clone --recurse-submodules <저장소 URL>

Submodule 상태 및 정보 확인

1
2
3
4
5
6
7
8
# 상태 확인
$ git submodule status

# 변경사항 확인
$ git diff --submodule

# 상세 로그 확인
$ git diff --submodule=log

Submodule 업데이트

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 기본 업데이트
$ git submodule update --remote

# 병합 옵션 포함 업데이트
$ git submodule update --remote --merge

# 특정 서브모듈만 업데이트
$ git submodule update --remote --merge <path>

# 재귀적 업데이트
$ git submodule update --init --recursive

Submodule 일괄 명령 실행

1
2
3
4
5
6
7
8
# 기본 형식
$ git submodule foreach '<git command>'

# 예시: 새 브랜치 생성
$ git submodule foreach 'git checkout -b featureA'

# 예시: 상태 확인
$ git submodule foreach 'git status'

Submodule 설정관리

1
2
3
4
5
6
7
# URL 동기화
$ git submodule sync
$ git submodule sync --recursive

# URL 변경 후 업데이트
$ git submodule sync
$ git submodule update --remote --merge

Submodule 제거

1
2
3
# 서브모듈 제거 과정
$ git submodule deinit <path>
$ git rm <path>

.gitmodules 파일

Git 서브모듈 설정을 저장하는 설정 파일로 프로젝트 루트 디렉토리에 위치한다.
서브모듈이 저장될 경로를 지정하여 주 저장소의 어느 위치에 서브모듈이 있는지 명확히 하고, 서브모듈이 참조할 원격 저장소의 URL 을 지정하여, 서브모듈을 업데이트하거나 클론할 때 올바른 원격 저장소와 연결되도록 한다. 또한, 주 저장소와 서브모듈의 설정이 일관되도록 하여 git submodule sync 와 같은 명령어로 서브모듈의 원격 URL 을 쉽게 업데이트할 수 있다.

.gitmodules 파일은 다음 명령어를 통해 Submodule 을 추가할 때 자동으로 생성된다:

1
git submodule add https://github.com/example/my-lib.git libs/my-lib

옵션 없이 기본적으로 커밋 기준으로 Submodule 이 참조되며, 위 명령 실행 시 .gitmodules 파일과 함께 .git/config 에도 설정이 복사된다.

Submodule 설정 변경 시 주의할 점

  1. .gitmodules 변경 후에는 반드시 다음을 수행해야 한다:

    1
    
    git submodule sync
    
  2. 이후 로컬 설정도 갱신해야 동기화된다:

    1
    
    git submodule update --init --recursive
    
  3. 브랜치를 따라가도록 설정한 경우에도 --remote 를 명시적으로 사용해야 최신 상태를 가져온다:

    1
    
    git submodule update --remote
    
  4. Private 저장소인 경우에는 url 에 SSH 주소 (git@github.com:…) 사용을 권장한다.

  5. .gitmodules.git/config 간 동기화 상태를 수시로 점검해야 한다.

  6. 추적 브랜치 + CI/CD 자동화를 함께 구성하는 것이 효율적이다.

주요 설정 항목

1
2
3
4
5
6
7
# 기본 형식
[submodule "<name>"]
    path = <로컬 경로>
    url = <원격 저장소 URL>
    branch = <추적할 브랜치>
    update = <업데이트 전략>
    ignore = <무시 설정>
  • [submodule "<name>"]: Submodule 의 식별자
    프로젝트 내에서 고유한 이름이어야 한다.
  • path: Submodule 이 저장될 경로.
    주 저장소의 루트에서 상대 경로로 지정되며, Submodule 이 이 위치에 체크아웃된다.
    기존 경로와 충돌하지 않도록 주의한다.
  • url: Submodule 의 원격 저장소 주소
    HTTPS / SSH URL 사용 가능
    접근 권한 있는 URL 사용
  • branch: Submodule 이 추적할 원격 브랜치 지정
    생략 시 기본값은 master/main
    접근 권한 있는 URL 사용
  • update: Submodule 업데이트 시 사용할 전략 지정.
    팀의 작업 방식에 맞는 전략 선택
1
2
3
4
5
	# 가능한 값들: 
	update = merge # merge 전략 사용 (로컬 변경사항 유지) 
	update = rebase # rebase 전략 사용 
	update = checkout # 강제로 원격 버전으로 체크아웃 (기본값) 
	update = none # 자동 업데이트 하지 않음
  • ignore: Submodule 의 변경사항 추적 방식 설정
    프로젝트 요구사항에 따라 신중히 선택
1
2
3
4
5
	# 가능한 값들:
	ignore = none           # 모든 변경사항 추적 (기본값)
	ignore = dirty          # 수정된 내용 무시
	ignore = untracked     # 추적되지 않는 파일 무시
	ignore = all           # 모든 변경사항 무시

여러 Submodule 설정 예시 (.gitmodules)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
[submodule "libs/auth-lib"]
    path = libs/auth-lib
    url = git@github.com:example/auth-lib.git
    branch = develop

[submodule "libs/ui-lib"]
    path = libs/ui-lib
    url = https://github.com/example/ui-lib.git
    branch = main

[submodule "tools/ci-utils"]
    path = tools/ci-utils
    url = https://github.com/example/ci-utils.git
    branch = release

설정 파일 구조

저장소 디렉토리 구조 예시
1
2
3
4
5
6
7
root/
├── .gitmodules
├── libs/
   ├── auth-lib/       # develop 브랜치 추적
   └── ui-lib/         # main 브랜치 추적
└── tools/
    └── ci-utils/       # release 브랜치 추적

클론 및 동기화 명령어

1
2
3
4
5
6
7
8
# 초기 Submodule 초기화
git submodule init

# 모든 서브모듈을 지정된 커밋으로 체크아웃
git submodule update

# 브랜치 추적을 위한 원격 상태로 업데이트 (필요시)
git submodule update --remote --merge

.git/config 내 동기화 확인

.git/config 에서 각 Submodule 이 추적할 브랜치를 반영해야 한다:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
[submodule "libs/auth-lib"]
    url = git@github.com:example/auth-lib.git
    branch = develop

[submodule "libs/ui-lib"]
    url = https://github.com/example/ui-lib.git
    branch = main

[submodule "tools/ci-utils"]
    url = https://github.com/example/ci-utils.git
    branch = release

git submodule sync 명령어로 .gitmodules.git/config 간 설정 불일치를 해결한다.

자동 업데이트 스크립트 예시 (CI/CD 또는 로컬용)

1
2
3
4
5
6
7
8
9
#!/bin/bash

echo "[INFO] 모든 서브모듈 최신화 및 병합"
git submodule foreach '
  echo "[INFO] 업데이트 중: $name"
  git checkout $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo main)
  git fetch origin
  git merge origin/$(git config -f $toplevel/.gitmodules submodule.$name.branch || echo main)
'

실무 적용 시 고려사항

항목설명
브랜치 동기화 명시적 관리Submodule 은 기본적으로 특정 커밋을 고정하므로 자동 추적이 되지 않음. --remote 플래그 필요.
의존 모듈 변경 시 정책Submodule 변경사항 커밋 후 상위 저장소에도 해당 SHA 커밋을 반드시 반영해야 함.
충돌 해결 전략Submodule 충돌 시에는 해당 디렉토리로 진입하여 직접 해결 후, 다시 상위 저장소에서 git add 및 커밋.

추가 옵션

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[submodule "complete-example"]
    path = lib/complete
    url = https://github.com/org/complete-lib.git
    branch = main
    update = merge
    ignore = dirty
    
    fetchRecurseSubmodules = on-demand
    shallow = true
    registered = true
    template = path/to/template
    remote = origin
    pushRemote = push-origin
    fetchJobs = 4
    active = true

성능 최적화가 필요할 때

  • fetchRecurseSubmodules: 서브모듈의 재귀적 페치 (fetched recursively) 설정을 제어하는 옵션으로 필요한 서브모듈만 페치하여 페치 속도를 최적화할 수 있다.
    • true: 항상 서브모듈까지 fetch
    • false: 서브모듈 fetch 하지 않음
    • on-demand: 필요할 때만 fetch
  • shallow: 서브모듈을 얕은 클론 (최소 커밋만 가져오는 방식) 으로 클론할 때 설정으로 전체 히스토리가 아닌 최신 커밋만 클론하여, 네트워크 트래픽을 줄이고 속도를 높인다.
  • fetchJobs: 페치 작업에 사용할 병렬 작업 (job) 수를 설정하는 옵션으로 여러 병렬 작업을 통해 페치 속도를 높이며, 특히 대규모 리포지토리에서 네트워크 성능과 페치 효율성을 높이는 데 유리하다.

복잡한 워크플로우 관리

  • template: Submodule 디렉토리에 대한 템플릿 디렉토리를 지정하는 옵션으로, Submodule 초기화 시 이 템플릿의 파일들이 복사된다. 특정 디렉토리와 파일을 템플릿으로 적용하여 새로운 프로젝트 초기화 시 일관성을 유지할 수 있다.
  • remote: Submodule 의 원격 저장소 URL 을 지정한다. 복수의 원격이 있을 때 각 서브모듈이 연결할 원격을 명확히 설정한다.
  • pushRemote: push 할 원격 저장소를 지정한다. 서브모듈이나 리포지토리에서 기본 push 원격을 변경할 수 있어, 배포용 또는 협업용 원격을 명확히 구분할 수 있다.

보안 설정

  • registered: 현재 Submodule 이 Git 에 등록되어 있는지 나타내는 옵션으로 Submodule 의 관리 상태를 확인할 때 사용한다. 서브모듈이 Git 에 등록되어 있는지 표시하여, 프로젝트 관리자가 서브모듈의 상태를 확인할 수 있다.
  • active: Submodule 의 활성화 여부로, 서브모듈이 활성화 상태인지 표시하여, 필요한 서브모듈만 활성화할 수 있게 해준다.

대규모 프로젝트

  • fetchRecurseSubmodulesMaxCount: 재귀적으로 서브모듈을 가져올 때 최대 깊이를 지정하는 옵션으로 서브모듈 깊이를 제한하여 페치 속도와 성능을 최적화할 수 있다.

장점과 단점

구분항목설명
✅ 장점코드 재사용여러 프로젝트에서 동일한 코드를 중복 없이 사용할 수 있습니다.
버전 고정컴포넌트나 하위 프로젝트가 너무 빠르게 변경되거나 향후 변경 사항이 API 를 깨뜨릴 경우, 안전을 위해 코드를 특정 커밋에 고정할 수 있습니다.
독립적 이력각 서브모듈은 자체 커밋 이력을 유지하므로, 복잡한 기능을 모듈식으로 개발할 수 있습니다.
모듈식 구조대규모 프로젝트를 더 작은 구성 요소로 분리하여 관리할 수 있습니다.
보안 강화모노레포에 비해 더 안전하며, 서브모듈에 대한 접근을 특정 사용자나 팀으로 제한할 수 있습니다.
⚠ 단점복잡한 워크플로우서브모듈 사용은 표준 Git 워크플로우보다 추가적인 명령어와 단계가 필요합니다.
학습 곡선팀원들이 서브모듈 개념과 작업 방식을 이해하는 데 시간이 필요합니다.
명시적 업데이트 필요Git 은 서브모듈 콘텐츠를 기본적으로 다운로드하지 않으므로, 팀원들이 ‘git submodule update’ 와 같은 명령어를 실행해야 합니다.
충돌 해결 복잡성서브모듈 충돌은 해결하기 어려울 수 있으며, 특히 양쪽 저장소 모두에서 동일한 파일이 수정된 경우 더욱 그렇습니다.
디버깅 어려움오류가 부모 저장소에서 발생했는지 서브모듈에서 발생했는지 파악하기 어려울 수 있습니다.

실무 적용 예시

상황적용 방법이점
클라이언트 - 서버 아키텍처클라이언트와 서버가 모두 필요로 하는 데이터 모델을 별도의 ‘common’ 저장소로 분리하여 서브모듈로 포함코드 중복 방지 및 모델 변경 시 동기화 용이
프레임워크 통합자주 사용하는 프레임워크나 라이브러리를 서브모듈로 추가특정 버전 고정으로 안정성 확보 및 필요 시 커스터마이징 가능
마이크로서비스 아키텍처각 마이크로서비스를 서브모듈로 관리개별 서비스의 독립성 유지하면서 전체 시스템 통합 관리
플러그인 시스템플러그인을 서브모듈로 관리코어 시스템과 플러그인 간 명확한 경계 설정
다중 언어 프로젝트언어별 코드베이스를 별도 서브모듈로 관리언어별 개발 환경 최적화 및 팀 분업 용이
모노리포 대안메인 저장소는 모든 코드를 관리하고 패키지는 각 서브모듈로 관리하여 변경 추적 용이모노리포의 복잡성 없이 모듈식 구조 유지

실무에서 효과적으로 적용하기 위한 고려사항 및 주의할 점

고려 사항설명
.gitmodules 관리 철저서브모듈 경로, URL 변경 시 설정 파일과 로컬 설정 동기화 필요
CI/CD 파이프라인 반영서브모듈 초기화 (init) 및 갱신 (update) 절차 자동화 필요
접근 권한 및 인증 문제 처리Private 저장소인 경우 SSH 키 또는 PAT 토큰 사용 고려

CI/CD 워크플로우 서브모듈 통합 방법

필수 조건:

  • 서브모듈 저장소에 대한 읽기 권한 보유
  • .gitmodules 파일에 HTTPS URL 사용 권장
  • GitHub 에서는 persist-credentials: true 설정 필요

📌 중요 팁:

GitHub Actions 에서 서브모듈 활용

GitHub Actions 에서 서브모듈을 사용하는 워크플로우는 다음과 같이 구성할 수 있다:

  • GitHub Actions 에서 actions/checkout@v3submodules: true 옵션으로 Submodule 을 자동 초기화한다.

.github/workflows/build.yml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
name: CI with Submodules

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout repository with submodules
      uses: actions/checkout@v4
      with:
        submodules: true  # ✅ 공개 서브모듈 체크아웃 가능
	    token: ${{ secrets.GITHUB_TOKEN }}  # ⚠️ 필수 아님 (자동 적용됨)
        
    # 빌드 단계
    - name: Build project
      run: |
        mkdir build && cd build
        cmake ..
        make
        
    # 테스트 단계
    - name: Run tests
      run: |
        cd build
        ctest
        
    # 배포 단계
    - name: Deploy
      if: github.ref == 'refs/heads/main'
      run: |
        echo "Deploying to production…"

주요 옵션 설명

옵션설명필수 여부
submodules: true1 단계 깊이의 서브모듈 체크아웃필수
submodules: recursive중첩된 모든 서브모듈 체크아웃선택
token상위 저장소와 다른 조직의 서브모듈 접근 시 필요조건부

주의 사항

  • SSH 키 충돌ssh-key 와 token 을 동시에 사용 시 오류 발생 가능
  • 퍼포먼스 저하: 불필요한 token 지정 시 실행 시간 15~20% 증가
  • 히스토리 관리fetch-depth: 0 추가 시 전체 커밋 내역 다운로드
GitLab CI/CD 에서 서브모듈 활용

GitLab CI/CD 에서는 다양한 환경 변수를 통해 서브모듈을 구성할 수 있다:
GitLab 에서는 수동으로 initupdate 를 해줘야 한다.

.gitlab-ci.yml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
image: alpine:latest

variables:
  # 서브모듈 전략 설정 (normal 또는 recursive)
  GIT_SUBMODULE_STRATEGY: recursive
  # HTTPS 강제 사용 (GitLab 서버에 있는 서브모듈에 유용)
  GIT_SUBMODULE_FORCE_HTTPS: "true"
  # 서브모듈 클로닝 깊이 제어
  GIT_SUBMODULE_DEPTH: 1

stages:
  - build
  - test
  - deploy

build:
  stage: build
  script:
    - echo "Building with submodules…"
    - ls -la
    # 서브모듈 디렉토리 확인
    - ls -la submodule-dir/
    # 빌드 명령 실행
    - ./build.sh
  artifacts:
    paths:
      - dist/

test:
  stage: test
  script:
    - echo "Running tests…"
    - ./run-tests.sh

deploy:
  stage: deploy
  script:
    - echo "Deploying application…"
  only:
    - main

GitLab CI/CD 에서는 GIT_SUBMODULE_STRATEGY 변수를 normal 또는 recursive 로 설정하여 서브모듈을 가져오도록 러너에 지시할 수 있다.

CI/CD 파이프라인에서 서브모듈 최적화 전략
  1. 캐싱 활용:

    1
    2
    3
    4
    5
    6
    7
    8
    
    # GitHub Actions 예시
    - name: Cache submodules
      uses: actions/cache@v3
      with:
        path: |
          .git/modules
          path/to/submodule
        key: ${{ runner.os }}-submodules-${{ hashFiles('.gitmodules') }}
    
  2. 얕은 클론 사용:

    1
    2
    3
    4
    5
    6
    
    # GitHub Actions 예시
    - name: Checkout with shallow submodules
      uses: actions/checkout@v3
      with:
        submodules: 'recursive'
        fetch-depth: 1
    
  3. 선택적 서브모듈 업데이트:

    1
    2
    3
    
    # GitLab CI 예시
    variables:
      GIT_SUBMODULE_PATHS: "submodule1 submodule2"  # 특정 서브모듈만 동기화
    

Private Submodule 인증 전략

방식설명설정 예시
SSH 키Git 서버에 SSH 공개 키를 등록하고, git@github.com:… 형식 사용.ssh/config 에 호스트 등록
Personal Access Token (PAT)HTTPS 사용 시 사용자 이름 대신 토큰 사용https://<TOKEN>@github.com/owner/repo.git
Deploy Key특정 저장소만 접근 가능한 공개키 (주로 read-only)공개키를 Submodule 저장소에 배포

SSH 키 기반 접근

  1. SSH 키 생성:

    1
    
    ssh-keygen -t ed25519 -f submodule-key
    

    생성된 키는 기본적으로 ~/.ssh/id_ed25519~/.ssh/id_ed25519.pub 로 저장된다.

  2. 공개키 내용을 복사

    1
    
    cat ~/.ssh/id_ed25519.pub
    

    이 값을 복사해서 GitHub 에 등록해야 한다.

  3. 공개키 (.pub 파일 내용) 등록:

    1. GitHub
      • GitHub 접속 후 우측 상단 프로필 > Settings
      • 왼쪽 메뉴에서 SSH and GPG keys 클릭
      • New SSH key 클릭
      • 제목 (Title) 입력 후, 위에서 복사한 공개키를 Key 입력란에 붙여넣기
      • Add SSH key 클릭
    2. GitLab
      • 서브모듈 저장소 Deploy Keys 에 추가
      • GitLab: 프로젝트 설정 → 저장소 → Deploy Keys
  4. Git Submodule 주소를 SSH 형태로 설정

    1
    
    git submodule add git@github.com:your-org/private-repo.git path/to/submodule
    
    • HTTPS 주소로 추가할 경우 인증 문제 발생
    • 반드시 git@github.com:… 형태의 SSH 주소 사용해야 함
  5. CI/CD 환경 설정:

    1
    2
    3
    4
    5
    
    - name: Checkout with submodules
      uses: actions/checkout@v4
      with:
        submodules: recursive
        ssh-key: ${{ secrets.SUBMODULE_SSH_KEY }}  # 프라이빗 키 등록	    
    
  6. SSH Agent 에 개인키 등록

    1
    2
    
    eval "$(ssh-agent -s)"
    ssh-add ~/.ssh/id_ed25519
    

    자동으로 Agent 에 등록해두면 Git 명령어 실행 시 자동 인증된다.
    또는, ~/.ssh/config 파일을 사용해 호스트별 키 지정이 가능하다.

    1
    2
    3
    4
    5
    6
    
    # ~/.ssh/config
    Host github-submodule
      HostName github.com
      User git
      IdentityFile ~/.ssh/id_rsa_submodule
      IdentitiesOnly yes
    

GitHub Actions, CI/CD 등 자동화 환경에서 사용할 때

  • Repository secrets 또는 Deploy Key 등록이 필요하다.
  • Repository secrets
    • 프라이빗 키 (Private Key) 전체를 GitHub 저장소의 Settings > Secrets and variables > Actions에서 시크릿 (Secret) 으로 등록한다.
    • 워크플로에서 ${{ secrets.시크릿이름 }} 형태로 참조해 사용한다.
    • 보통 여러 저장소를 다루거나, 다양한 환경에서 자동화가 필요한 경우 사용한다.
  • Deploy Key
    • 공개키 (Public Key) 를 GitHub 저장소의 Settings > Deploy Keys에 등록한다.
    • 프라이빗 키 (Private Key) 는 CI/CD 서버 또는 Actions 런너에 저장해 사용한다.
    • Deploy Key 는 저장소 단위로 접근 권한을 부여하며, 읽기 또는 쓰기 권한을 선택할 수 있다.
    • 한 Deploy Key 는 하나의 저장소에만 사용할 수 있다 (여러 저장소에 중복 등록 불가).

Personal Access Token(PAT) 활용

  1. PAT 생성:

    • GitHub/GitLab 설정에서 적절한 권한을 가진 토큰 생성
    • 최소 repo 범위 권한 필요 (비공개 저장소 접근용)
  2. GitHub Actions 워크플로우 예시:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    name: CI with Private Submodules (PAT)
    
    on:
      push:
        branches: [ main ]
    
    jobs:
      build:
        runs-on: ubuntu-latest
        steps:
        - name: Checkout code with submodules
          uses: actions/checkout@v3
          with:
            submodules: 'recursive'
            token: ${{ secrets.ACCESS_TOKEN }}  # PAT를 사용
    
        - name: Build and test
          run: |
            # 빌드 및 테스트 명령
    
  3. 서브모듈 URL 구성 예시:

    1
    2
    3
    
    [submodule "lib/component"]
        path = lib/component
        url = https://github.com/organization/private-repo.git
    

주의 사항:

  • PAT 는 환경 변수로 관리 (절대 코드 내 노출 금지)
  • GitHub Actions 에서는 secrets.GITHUB_TOKEN 자동 인증 지원

여러 서브모듈에 대한 개별 인증 전략

각 서브모듈마다 별도의 SSH 키를 사용해야 하는 경우, 다음과 같은 방식으로 접근할 수 있다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
steps:
  - name: Checkout main repo
    uses: actions/checkout@v3
    with:
      submodules: false  # 서브모듈 체크아웃 안 함
      
  # 서브모듈 A 체크아웃
  - name: Checkout submodule A
    env:
      SSHK: ${{ secrets.SUBMODULE_A_KEY }}
    run: |
      mkdir -p $HOME/.ssh
      echo "$SSHK" > $HOME/.ssh/ssh.key
      chmod 600 $HOME/.ssh/ssh.key
      export GIT_SSH_COMMAND="ssh -i $HOME/.ssh/ssh.key"
      git submodule update --init -- path/to/submodule_a
      
  # 서브모듈 B 체크아웃
  - name: Checkout submodule B
    env:
      SSHK: ${{ secrets.SUBMODULE_B_KEY }}
    run: |
      mkdir -p $HOME/.ssh
      echo "$SSHK" > $HOME/.ssh/ssh.key
      chmod 600 $HOME/.ssh/ssh.key
      export GIT_SSH_COMMAND="ssh -i $HOME/.ssh/ssh.key"
      git submodule update --init -- path/to/submodule_b

최적화하기 위한 고려사항 및 주의할 점

Git 서브모듈을 사용할 때 성능 최적화를 위한 고려사항은 다음과 같다:

  1. 서브모듈 깊이 제한: 서브모듈 내에 서브모듈이 중첩된 깊은 계층 구조는 초기화 및 업데이트 시간을 크게 늘릴 수 있으므로 가능한 한 얕은 계층 구조를 유지한다.

  2. 선택적 서브모듈 사용: 모든 서브모듈을 항상 업데이트하는 대신, 필요한 서브모듈만 초기화하여 시간을 절약한다.

    1
    2
    
    git submodule init path/to/needed/submodule
    git submodule update path/to/needed/submodule
    
  3. 병렬 처리 활용: 여러 서브모듈을 동시에 업데이트하여 시간을 절약한다.

    1
    
    git submodule update --init --recursive --jobs=8
    
  4. 얕은 클론 고려: 거대한 이력이 있는 서브모듈의 경우 얕은 클론으로 다운로드 크기와 시간을 줄인다.

    1
    
    git submodule update --init --depth=1
    
  5. 캐시 활용: Git 의 캐시 기능을 활용하여 반복적인 작업 속도를 향상시킨다.

    1
    
    git config --global core.preloadindex true
    
  6. 대규모 모노레포 성능 개선: 인덱스 버전을 4 로 업그레이드하면 경로 이름을 압축하여 인덱스 크기를 30%~50% 줄이고 작업 속도를 향상시킬 수 있다.

  7. 파일 시스템 모니터링: 파일 시스템 모니터 (FSMonitor) 는 전체 작업 디렉토리를 검색하지 않고 검색 크기를 줄여 git status 와 같은 명령어의 속도를 높일 수 있다.

  8. 서브모듈 대신 다른 대안 고려: 특정 상황에서는 서브모듈 대신 패키지 관리자나 모노레포 도구가 더 나은 성능을 제공할 수 있다.

최신 동향

주제항목설명
AI 통합AutoMergeLLM 기반 충돌 자동 해결
서브모듈 간소화향상된 명령어Git 2.42.0 이상 버전에서는 서브모듈 작업을 간소화하는 새로운 기능들이 도입되어 작업 복잡성이 줄어들었습니다.
모노레포 통합혼합 접근법대규모 프로젝트 관리에서 Git 서브모듈과 모노레포를 함께 사용하는 혼합 접근법이 인기를 얻고 있습니다.
성능 최적화파일 시스템 모니터링Git 의 내장 파일 시스템 모니터 도구가 모노레포 및 서브모듈 성능을 크게 향상시킵니다.
자동화 도구CI/CD 통합서브모듈 초기화, 업데이트, 동기화를 자동으로 처리하는 CI/CD 파이프라인 플러그인이 표준화되고 있습니다.
보안 강화접근 제어서브모듈에 대한 세분화된 접근 제어를 지원하는 도구들이 늘어나고 있습니다.

주목해야 할 기술

주제항목설명
서브모듈 오케스트레이션통합 관리 도구여러 서브모듈을 통합적으로 관리하고 동기화하는 고급 도구들이 개발되고 있습니다.
인텔리전트 업데이트선택적 서브모듈 업데이트변경된 서브모듈만 지능적으로 감지하고 업데이트하는 도구가 등장하고 있습니다.
IDE 통합시각적 서브모듈 관리주요 IDE 들이 Git 서브모듈을 시각적으로 관리할 수 있는 고급 기능을 제공하여 복잡한 명령어 사용 없이도 서브모듈 관리가 가능해지고 있습니다.
충돌 해결 자동화AI 기반 서브모듈 충돌 해결머신러닝과 AI 를 활용하여 서브모듈 충돌을 자동으로 감지하고 해결 방안을 제안하는 도구들이 개발되고 있습니다.
분산 서브모듈P2P 서브모듈 동기화피어 투 피어 방식으로 서브모듈을 동기화하여 중앙 서버 의존성을 줄이는 기술이 발전하고 있습니다.

앞으로의 전망

주제항목설명
하이브리드 모델서브모듈 - 모노레포 통합서브모듈과 모노레포의 장점을 결합한 하이브리드 접근 방식이 주류가 될 것으로 예상됩니다.
자동화 발전지능형 서브모듈 관리AI 와 자동화 기술을 활용한 더욱 스마트한 서브모듈 관리 도구가 등장할 것입니다.
Git 확장성 개선대규모 서브모듈 성능 향상GitHub 의 Project Cyclops 와 같은 프로젝트를 통해 대규모 서브모듈 및 모노레포 성능이 크게 향상될 것입니다.
분산 개발 최적화원격 작업 효율성글로벌 분산 팀에서 서브모듈을 효율적으로 사용할 수 있는 도구와 프로세스가 발전할 것입니다.
클라우드 네이티브 통합클라우드 환경 최적화클라우드 네이티브 환경에서 서브모듈을 더욱 효율적으로 활용할 수 있는 도구들이 등장할 것입니다.

추가 학습 하위 주제

카테고리주제설명
고급 서브모듈 기술서브모듈 브랜치 추적Git 1.8.2 이상에서 서브모듈이 특정 브랜치를 추적하도록 설정하는 방법
서브모듈 내부 작동 원리Git 서브모듈의 내부 구현 및 작동 원리에 대한 깊은 이해
충돌 해결 전략서브모듈 충돌 발생 시 효과적인 해결 전략 및 도구
통합 및 자동화CI/CD 파이프라인 통합지속적 통합 및 배포 환경에서 서브모듈을 효율적으로 관리하는 방법
자동화 스크립트 개발서브모듈 작업을 간소화하는 맞춤형 스크립트 및 도구 개발
서브모듈 후크 활용Git 훅을 사용하여 서브모듈 작업을 자동화하는 방법
소프트웨어 아키텍처모듈 단위 설계 및 저장소 구조화저장소 구조화 전략으로 Submodule 을 활용한 모듈화 방법론 학습
마이크로서비스마이크로서비스 아키텍처에서 서브모듈 활용
모노레포 설계대규모 코드베이스의 효과적인 구조화 전략
실무 패턴서브모듈 패턴 및 안티패턴실무에서 효과적인 서브모듈 사용 패턴과 피해야 할 안티패턴
마이그레이션 전략기존 저장소를 서브모듈 구조로 마이그레이션하는 전략
대규모 프로젝트 관리수십, 수백 개의 서브모듈을 가진 대규모 프로젝트 관리 방법
대안 및 비교서브모듈 vs 모노레포서브모듈과 모노레포 접근 방식의 심층 비교 및 적절한 선택 기준
서브모듈 vs 패키지 관리자서브모듈과 언어별 패키지 관리자 (npm, pip 등) 비교
서브트리 vs 서브모듈Git 서브트리와 서브모듈의 비교 및 적절한 사용 상황
인증 및 접근 제어Private Submodule 인증 방식토큰, SSH, OAuth 등 접근 인증 방식 학습
보안 (Security)인증 키 관리 및 노출 방지.gitmodules 에 포함된 인증 정보 보안 관리 필요성
협업 개발코드 리뷰서브모듈이 포함된 프로젝트의 효과적인 코드 리뷰 전략
팀 구성 및 역할서브모듈 기반 프로젝트에서의 팀 구성 및 역할 분담
문서화서브모듈 구조와 워크플로우의 효과적인 문서화 방법
성능 최적화Git 성능 튜닝대규모 저장소와 서브모듈의 Git 성능 최적화 기법
분산 환경 최적화글로벌 분산 팀에서 서브모듈 사용 최적화
클라이언트 성능Git 클라이언트 도구의 서브모듈 성능 최적화

용어 정리

용어설명
Fast-Forward병합 없이 브랜치 포인터 이동
.git/modules서브모듈 메타데이터 저장 위치
.gitmodulesSubmodule 의 경로 및 URL 정보를 저장하는 구성 파일
SubtreeSubmodule 의 대안으로, 하위 프로젝트를 통합하여 히스토리 유지가 쉬운 방식
git-subrepoSubmodule 보다 유연하게 외부 저장소를 통합할 수 있는 도구
부모 저장소 (Parent Repository)서브모듈을 포함하는 주 Git 저장소
서브모듈 (Submodule)다른 Git 저장소 내에 포함된 독립적인 Git 저장소
분리된 HEAD(Detached HEAD)브랜치가 아닌 특정 커밋을 직접 가리키는 상태로, 서브모듈은 기본적으로 이 상태로 체크아웃됨
서브모듈 참조부모 저장소가 서브모듈의 특정 커밋을 가리키는 참조
모노레포 (Monorepo)여러 프로젝트가 단일 저장소 내에 함께 있는 구조
브랜치 추적Git 1.8.2 부터 지원되는 서브모듈이 특정 브랜치를 추적하는 기능
shallow clone전체 이력이 아닌 최신 커밋만 가져오는 얕은 클론 방식
재귀적 업데이트–recursive 플래그를 사용하여 중첩된 서브모듈까지 모두 업데이트하는 방식
Deploy Key특정 저장소 전용으로 등록한 SSH 공개 키 (보통 read-only)
PAT (Personal Access Token)GitHub 등의 API 인증을 위한 토큰, HTTPS 로 인증할 때 사용
submodules: recursiveGitHub Actions 에서 모든 하위 서브모듈까지 자동 clone 하는 옵션
SubtreeGit 저장소 통합 방식 중 하나로, 외부 저장소 내용을 직접 포함하여 사용

참고 및 출처