작업 tools/git

git 서브모듈: 추가하기, 변경하기,삭제하기

yztech 2021. 9. 26. 08:36
반응형

서브 모듈 추가하기

아래와 같은 2개의 별개 코드를 포함한 프로젝트를 생성하고자 할 경우,

  • shot 프로젝트
    • stick 코드
    • band 코드

다른 저장소에 있는paper이라는 프로젝트를 shot 저장소에 서브모듈로 추가하려고 할 경우, 아래와 같이 git submodule add <repository> [path]을 사용하여 submodule을 add하면 됩니다.

git submodule add https://github.com/<user>/paper paper

git status를 확인해보면, .gitmodulepaper폴더가 추가된 것을 확인할 수 있고, .gitmodule 에는 git에서 관리되는 서브모듈에 정보가 들어있고, 아래 내용이 추가됩니다.

[submodule "paper"]
    path = paper
    url = https://github.com/<user>/paper.git
    branch = master

.git/config 에도 아래 내용이 추가됩니다.

[submodule "paper"]
    url = https://github.com/<user>/paper.git

이 때 shot에는 paper라 폴더가 생성되지만, 그 안에는 아무것도 없기 때문에, submodule update를 사용하여 paper의 내용을 명시적으로 다운로드합니다 (새버전 git에서는 자동 다운로드합니다)

git submodule update --init --recursive

모든 것이 잘 되었다면, 변경점을 커밋하고 paper폴더를 shot저장소에 추가합니다.

gitHubpaper폴더 아이콘에 작은 표시를 붙여 이것이 서브모듈임을 나타냅니다.

서브모듈로 변경하기

magician 이라는 신규 프로젝트를 시작하기로 했는데, 여기서 band가 유용하다고 가정합니다.
shot을 위해 만든 band를 독립적인 저장소로 분리한 후, 두 개의 프로젝트에 서브로 추가해 보겠습니다.

bandshot에서 추출하려면, git filter-branch 명령으로 band관련된 커밋만 남길 수 있습니다.
이는 저장소 이력을 재작성하여 band가 원래 저장소에 포함되지 않은 것처럼 보이게 합니다.
(참고: https://help.github.com/articles/splitting-a-subfolder-out-into-a-new-repository/)

1. A이름의 local 저장소 생성

shot안의 band를 자체 저장소로 동작하게 하기 위해 shot복사본을 band이름으로 생성합니다.

cd ..
cp -r shot band

2. A관련 폴더 및 히스토리만 추출

이제 band 폴더의 파일과 커밋 히스토리만 남깁니다.
사용 방법은 git filter-branch --subdirectory-filter <folder name> <branch name> 입니다.

cd band
git filter-branch --subdirectory-filter band -- --all

3. A 이름의 remote 저장소 생성 및 update

github에서 band라는 새로운 저장소를 만들고 remote를 band로 update합니다.

git remote -v
git remote set-url origin https://github.com/<user>/band
git push -u origin master

4. 원본 저장소에서 A 폴더 삭제

shot저장소에서 band폴더를 삭제한다

git rm -r band
git commit -m "Remove band (preparing for submodule)"

5. A를 부모 저장소에 submodule로 추가

shotband를 서브모듈로 만듭니다

git submodule add https://github.com/<user>/band band
git commit -m "band submodule"

이제, 부모 저장소인 shot', 두개의 서브 저장소인paperband`를 포함한 세개의 저장소가 됩니다.

shot 히스토리를 보면, band가 폴더일때 만들었던 커밋들이 남아있습니다.
즉, 폴더를 삭제하더라도 히스토리가 삭제되지 않습니다.

submodule을 잘못 생성한 경우,

삭제는 deinit 명령으로 해당 모듈을 초기화하고, rm 명령으로 해당 폴더를 삭제후, git rm 명령으로 git에서도 해당 폴더를 제거합니다.

git submodule deinit -f band
rm -rf .git/modules/band
git rm -f band

submodule을 최신 버전으로 update한후, master를 push

cd band
git pull
git status
git add band
git commit -m "updated band"
git push

협업시 주의할 점은

이 시점에 협업자들이 shot을 pull하게 되면, band는 비어있게 됩니다.
따라서, 협업자들이 아래 명령을 실행하여, 서브모듈 내 모든 내용을 다운로드해야 합니다.

git submodule update --init --recursive

bandmagician에 서브모듈로 추가하고 싶다면 shotpaper을 추가한 것처럼 반복하면 됩니다.

cd ~/projects/magician
git submodule add https://github.com/<user>/band band
git commit -m "band submodule"
git submodule update --init --recursive

부모 repo에서 자식 프로젝트 작업시 주의할 점은

자식 프로젝트 작업후, 리모트에 커밋하지 않고 git submodule update하면,
부모 repo가 참조하는 커밋으로 체크아웃되어, 작업 내용이 삭제됩니다!!
커밋만 하고 푸시하지 않은 상태라면, 로컬 커밋에서 찾을 수 도 있습니다/
하지만, 별도 브랜치가 없으면 찾기 어려게 됩니다.

따라서, 부모 repo에서 자식 프로젝트 작업시, 반드시 별도 브랜치를 따서 작업할 것을 추천합니다.

submodule상태 확인

submoudle status명령은 현재 sub 모듈이 가리키는 커밋 상태를 확인합니다.

git submodule status
반응형