일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- Heap
- jpa
- pod
- application properties
- properties
- spring boot
- property
- evicted
- xms
- 글또
- liveness probe
- java
- Java Virtual Machine
- startup probe
- logback
- Xmx
- configmap
- readiness probe
- diskpressure
- k8s
- OOM
- Probe
- ORM
- JVM
- Kubernetes
- 회고
- Today
- Total
여우발개발
내가 Git Submodule 써보니까 쉽던데? 본문
배경
MSA 환경에서 여러 프로젝트를 개발하다 보면 자연스럽게 공통되는 코드들이 생긴다.
이런 중복들을 줄이기 위해 공통되는 코드들을 하나의 라이브러리로 묶고, 이를 JAR 형태로 Maven 레포지토리에 배포해 사용하고 있었다.
다음은 공통 모듈로 분리해 사용했던 주요 항목들이다.
- 공통 응답 및 예외 처리
- 모든 프로젝트에서 동일한 형식으로 사용하는
BaseResponse
- 서비스에서 발생하는
RuntimeException
을 처리할@RestControllerAdvice
,@ExceptionHandler
- 모든 프로젝트에서 동일한 형식으로 사용하는
- 공통 entity
- 서비스 간에 공유되는 entity를 별도 모듈로 관리 (예: service, admin, batch 등)
JAR로 공통 모듈을 관리하는 방식은 재사용성을 높이는 데 도움이 되었지만, 몇 가지 어려움도 있었다.
버전 관리
라이브러리가 JAR 형태로 패키징되어 배포되다 보니, 특정 버전에 어떤 코드가 포함되어 있는지 정확하게 파악하기 어렵다.
배포 시점에 Git 태그를 수동으로 추가하긴 했지만, 실수하거나 누락되는 경우가 발생할 수 있다.
디버깅 불편함
라이브러리로 묶여 있는 코드의 경우, 문제가 생겼을 때 그 내부 흐름을 파악하거나 로그를 따라가기가 훨씬 어렵다. 실제 서비스에 적용한 후 문제가 발생했을 때, 해당 라이브러리 버전을 기준으로 다시 빌드하고 로컬에서 테스트하는 과정이 번거롭고 시간이 오래 걸린다.
이러한 문제를 해결하기 위해서 git에서 제공하는 submodule 기능을 이용할 수 있다.
submodule을 통해 공통 코드를 외부 라이브러리 형태가 아닌, 하나의 Git 프로젝트에서 직접 관리할 수 있다.
Git Tools - Submodules
Git - 서브모듈
gitmodules 파일에 있는 URL은 조건에 맞는 사람이면 누구든지 Clone 하고 Fetch 할 수 있도록 접근할 수 있어야 한다. 예를 들어 다른 사람이 Pull을 하는 URL과 라이브러리의 작업을 Push 하는 URL이 서로
git-scm.com
프로젝트를 수행하다 보면 다른 프로젝트를 함께 사용해야 하는 경우가 종종 있다.
함께 사용할 다른 프로젝트는 외부에서 개발한 라이브러리라던가 내부 여러 프로젝트에서 공통으로 사용할 라이브러리일 수 있다.
이런 상황에서 자주 생기는 이슈는 두 프로젝트를 서로 별개로 다루면서도 그 중 하나를 다른 하나 안에서 사용할 수 있어야 한다는 것이다.Git의 서브모듈은 이런 문제를 다루는 도구다. Git 저장소 안에 다른 Git 저장소를 디렉토리로 분리해 넣는 것이 서브모듈이다. 다른 독립된 Git 저장소를 Clone 해서 내 Git 저장소 안에 포함할 수 있으며 각 저장소의 커밋은 독립적으로 관리한다.
- Git submodule : 하나의 git 저장소 안에 다른 git 저장소를 디렉토리로 추가해 모듈처럼 사용할 수 있는 기능
상황을 하나 가정하자.
- 유저에게 데이터를 보여주는 service
- 데이터를 관리하는 admin
- 정기적으로 대량의 데이터 작업을 수행하는 batch
이 세 프로젝트들은 동일한 DB 테이블을 공유한다.
만약 테이블이 변경돼 entity class를 변경해야 한다면, 각 프로젝트에서 entity class를 각각 수정해야 한다. 귀찮은 건 둘째치고 여러 항목들을 바꾸다가 누락될 수도 있다.
이때 Git Submodule을 사용하면, 모든 프로젝트가 동일한 코드를 참조하게 되어 중복 작업을 줄이고, 변경 사항을 손쉽게 반영할 수 있다.
Git Submodule 시작하기
처음부터 submodule을 포함해서 프로젝트를 만들 필요는 없다.
프로젝트 운영 중 컴포넌트 간 중복되는 부분이 생기면 그때 모듈화해도 되고, 초기 설계 단계에서 중복 발생할 부분이 확실하다면 미리 분리해두는 것도 좋다.
처음 submodule을 등록하는 경우 아래의 순서를 따르면 된다.
Git submodule 등록하기
1. 서브모듈 용 Git repository 생성
모듈화 할 코드를 관리할 새로운 git repository를 생성한다.
2. 메인 프로젝트에 서브모듈 추가
## git bash
$ git submodule add {1번에서 만든 submodule로 사용할 git Repo url} {submodule을 추가할 폴더}
# 예시
JSY@DESKTOP MINGW64 /d/Development/SourceCodes/foxtodo (master)
$ git submodule add https://github.com/JSY/api-exception-handler api-exception-handler
submodule이 잘 추가되었다면 프로젝트 루트에 .gitmodules
파일이 생긴 것을 확인할 수 있다.
[submodule "api-exception-handler"]
path = api-exception-handler
url = https://github.com/DEVSYJ/api-exception-handler
▼ submodule 추가 시 인증 에러가 발생한다면?
Git Submodule을 추가하려고 할 때 인증 에러가 발생할 수 있다.
$ git submodule add https://github.com/JSY/api-exception-handler api-exception-handler
Cloning into 'D:/Development/SourceCodes/foxtodo/api-exception-handler'...
Logon failed, use ctrl+c to cancel basic credential prompt.
Username for 'https://github.com': theusername
remote: Write access to repository not granted.
fatal: unable to access 'https://github.com/JSY/api-exception-handler/': The requested URL returned error: 403
fatal: clone of 'https://github.com/JSY/api-exception-handler' into submodule path 'D:/Development/SourceCodes/foxtodo/api-exception-handler' failed
주로 발생하는 문제는 인증 방식이나 접근 권한과 관련된 것들인데, 아래 방법들을 시도해 보자.
(아래는 github 기준으로 설명했다. gitlab 등에서도 비슷한 오류가 발생할 수 있다.)
- HTTPS 사용 중이라면 토큰 인증 필요
- GitHub은 비밀번호 인증을 지원하지 않기 때문에, Personal Access Token (PAT)을 사용해야 한다.
- [토큰 생성 방법]
- GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic) → Generate new token
- repo 권한만 선택해서 토큰 생성
- 인증창에서 비밀번호 대신 토큰 입력
- SSH 방식 사용
- HTTPS 대신 git@github.com:사용자명/레포명.git 형식의 SSH URL을 사용
- 로컬에 SSH 키가 없다면 생성해서 GitHub에 등록 필요
▼ .gitmodules에 정의한 submodule의 url을 변경할 경우 (SSH 방식 변경 포함)
submodule의 git repo가 변경 된 경우 아래 커맨드를 실행해 로컬 설정을 동기화해야한다.
# copy the new URL to your local config
$ git submodule sync --recursive
# update the submodule from the new URL
$ git submodule update --init --recursive
3. git commit & push
.gitmodules
파일과 submodule 디렉토리를 commit하고 push해야 origin에 반영될 수 있다.
말했듯이 git submodule은 하나의 Git 저장소 안에 다른 Git 저장소를 디렉토리로 추가하는 개념이다.
submodule을 추가하면, 메인 프로젝트는 해당 submodule을 특정 커밋 해시로 고정된 상태로 추적하게 된다.
위 사진에서 api-exception-handelr
라는 submodule을 커밋하면, foxtodo
라는 main project는 api-exception-handelr
의 d7f5005c~ 커밋을 submodule의 수정사항으로써 추적하게 된다.
git submodule 이 등록되어있는 repository pull 하기
누군가가 프로젝트에 submodule을 등록해두었다면, 다른 개발자도 해당 submodule을 함께 받아야 제대로 프로젝트를 사용할 수 있다.
하지만 일반적인 git clone
시 submodule 디렉토리는 빈 상태로 받아지게 된다.
clone 시 submodule까지 함께 받기
git clone 시에 아래처럼 --recurse-submodules
옵션을 사용하면 submodule까지 한 번에 clone된다. (중첩된 submodule 포함)
$ git clone --recurse-submodules {main project git url}
이미 clone한 경우 수동으로 submodule 초기화
이미 main project를 받은 상황이라면 아래 명령어로 submodule을 초기화해야 한다.
# local configuration file 초기화
$ git submodule init
# submodule fetch 및 check out
$ git submodule update
위의 두 명령어를 한방에 해결하는 명령어도 있다. 중첩된 submodule이 있다면 반드시 --recursive
옵션을 붙여야 제대로 초기화된다.
$ git submodule update --init --recursive
새로 프로젝트를 시작하는 사람이 submodule 초기화를 빠뜨리면 프로젝트 실행이 안 될 수 있으니, README.md
에 위 내용을 명시해두자.
Tip! Gradle Multi Module로 등록하기
추가한 submodule을 Gradle multi module로 함께 사용하고 싶다면, 기존에 multi module을 구성할 때와 동일한 방식으로 설정하면 된다.
settings.gradle
에 include만 잘 추가해주면 일반 모듈처럼 의존성 관리도 가능하다.
/* setting.gradle */
rootProject.name = '{main project name}'
include ':{git submodule project name}'
// 예시
rootProject.name = 'foxtodo'
include ':api-exception-handler'
/* build.gradle */
dependencies {
...
implementation project(':{git submodule project name}')
...
}
// 예시
dependencies {
...
implementation project(':api-exception-handler')
...
}
Git Submodule과 함께 작업하기 (with IntelliJ)
위 과정을 통해 프로젝트에 submodule이 제대로 등록되었다면 개발 환경 구성이 완료된다.
이제 submodule에 변경사항이 생겼을 경우 이를 어떻게 관리하는지 알아보자.
IntelliJ에서의 작업을 기준으로 설명한다.
Submodule 변경사항 관리하기
submodule의 상태를 command로 관리할 수도 있지만, IntelliJ의 UI를 활용하면 훨씬 쉽게 관리할 수 있다. 만약 커맨드로 사용하고 싶다면 위에 링크를 첨부한 git 사이트 내에서 확인할 수 있다.
Submodule 변경사항 fetch
IntelliJ에서는 일반적인 프로젝트와 동일하게 Submodule의 fetch 및 pull 작업을 지원한다.
Fetch 버튼을 눌렀을 때 submodule을 함께 fetch, pull 하는 옵션을 추가해서 명령어를 호출해주기 때문에 전체 프로젝트의 상태를 한 번에 관리할 수 있다.
[foxtodo] git -c credential.helper= -c core.quotepath=false -c log.showSignature=false fetch origin --recurse-submodules=no --progress --prune
[api-exception-handler] git -c credential.helper= -c core.quotepath=false -c log.showSignature=false fetch origin --recurse-submodules=no --progress --prune
Submodule 변경사항 확인
fetch가 되었다면 submodule의 원격 브랜치에 새로운 커밋이 생긴 것을 확인할 수 있다.
Submodule 변경사항 pull(update)
fetch된 내용에서 update를 하는 것도 main project와 크게 다르지 않다.
update가 잘 되었다면 local branch가 원격 branch와 sync된 것을 확인할 수 있다.
Submodule 변경사항 commit, push
Submodule은 메인 프로젝트 내부에 있지만 별도의 Git 저장소다.
수정이 필요한 경우, Submodule 디렉토리에서 바로 commit/push할 수 있으며, 독립된 프로젝트처럼 다룰 수 있다.
단, 동일한 Submodule을 사용하는 다른 프로젝트에서의 local repository는 다르므로 주의해야 한다.
main project 내의 submodule 변경사항을 commit하는 것도 크게 다르지 않다.
IntelliJ에서 commit 메뉴를 확인하면 main project, submodule 변경사항이 같이 보여지는데, commit을 하게 되면 연결된 repository에 각자 commit되게 된다.
push 역시 동일하게 진행할 수 있다.
Main Project에서 Submodule 관리하기
submodule에 대한 변경사항을 관리하는 법은 앞에서 알아봤다.
이제 main project에서 submodule을 어떻게 추적하고 반영하는지 알아보자.
main project는 submodule을 일반 파일처럼 직접 다루는 게 아니라, submodule의 특정 커밋을 가리키는 포인터로 관리한다.
따라서 submodule 내부에서 최신 커밋을 pull하거나 수정한 뒤엔 그 상태를 main project에서 커밋해줘야 한다.
submodule의 commit hash가 변경되면, main project의 변경사항으로 감지된다.
해당 변경사항을 commit & push하면 새로운 submodule 버전을 참조하게 된다.
마무리
이 글은 git submodule을 써본 이후에 팀원에게 추천했다가, 사용하기 어렵다는 피드백을 받고나서 작성한 글이다.
나는 엄청 잘 쓰고 있는데? 알고보니 커맨드로 submodule을 업데이트 하고 계셨다. 어려울법도 하다...
Git Submodule은 잘만 사용한다면 공통 모듈을 여러 프로젝트에서 효율적으로 관리할 수 있게 도와주는 좋은 기능이다.
초기 설정과 사용 방식이 조금 익숙치 않을 수 있지만 익숙해지면 모듈화와 코드 재사용 면에서 많은 이점을 느낄 수 있으니 이 글이 도움이 되면 좋겠다.
'Backend' 카테고리의 다른 글
Spring이 application property를 인식하는 방식 (6) | 2024.11.09 |
---|---|
JVM Heap 크기 설정 (7) | 2024.10.27 |