아래 내용은 https://blog.github.com/2016-02-01-working-with-submodules/ 에 포스팅된 글을 번역 및 추가한 것이다.


복잡한 소프트웨어 프로젝트는 다른 프로젝트, 라이브러리 또는 프레임워크에 의존하게 되는 경우가 많다. Git(깃) 은 submodule(서브모듈)을 제공하여 이러한 과정을 돕는다. 서브모듈은 다른 repository(저장소)를 하나의 sub-folder로 추가할 수 있도록 한다.


Git 에서 Submodule을 사용하면 재사용되는 제네릭한 프로젝트들을 부모 프로젝트에서 분리해서 관리하기 쉽고 다른 프로젝트에 적용하기 쉽지만 사용하기가 번잡스러운 부분이 있다. 그래서 아래의 예를 통해 이해해보자.


서브모듈 추가하기


예를 들어 Slingshot(새총) 이라는 프로젝트를 개발중이라고 해보자. 이 프로젝트에는 y-shaped stickrubber-band라는 코드가 있다.


flickr photo shared by young@art under a Creative Commons ( BY ) license


이때, 다른 저장소에는 Rock 이라고 불리는 프로젝트가 있는데 이것은 그냥 일반적인(generic) rock 이라는 라이브러리일 뿐이지만 Slingshot에 적합하다고 가정해 보자.

그래서 slingshot 저장소에 이 rock이라는 저장소를 slingshot의 서브모듈로 추가하기 위해 다음을 입력한다:


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

<추가됨>

이렇게 추가된 서브모듈에 대한 정보는 root 폴더의 .gitmodules 에 아래와 같은 내용이 추가된 것을 확인할 수 있다.


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


또한 .git/config 에도 이 내용이 반영되어있다.


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

</추가됨>


이 시점에서 slingshot 폴더 안에 rock이라는 폴더가 생성되지만 사실 그 안에는 아무것도 존재하지 않는다.


새로운 버전의 깃 에서는 자동으로 내용물을 채우지만 이전 버전에서는 깃에서 rock의 내용을 명시적으로 다운로드해야 한다:


git submodule update --init --recursive


모든것이 잘 되었다면 이 변경점을 커밋하고 rock 폴더를 slingshot 저장소에 추가하게 된다.


깃허브에서는 rock 폴더 아이콘에 작은 표시를 붙여 이것이 서브모듈임을 나타낸다:


screen shot 2016-01-27 at 4 55 10 pm

rock 폴더를 클릭하면 rock 저장소로 이동하게 된다.


이제 rock 저장소를 slingshot 저장소에 추가하였고 rock의 모든 내용들을 slingshot에 포함된 것처럼 사용할 수 있다.

slingshot 저장소에서 실행한 깃 명령어는 "부모 저장소"에서 동작한다. 그리고 rock 폴더 안에서 실행한 명령어는 단지 rock 저장소에서 동작한다.

cd ~/projects/slingshot
git log # log shows commits from Project Slingshot
cd ~/projects/slingshot/rubber-band
git log # still commits from Project Slingshot
cd ~/projects/slingshot/rock
git log # commits from Rock
서브모듈을 사용하는 프로젝트에 참가하기

이제 여러분이 Slingshot 프로젝트에 참가하는 협업자라고 가정해보자. git clone을 사용하여 slingshot 의 내용물을 다운로드하기 시작한다. 이 시점에서  rock 폴더를 들여다보면 아무것도 없는것을 확인할 수 있다.
다시 말하지만 깃은 명시적으로 서브모듈을 다운로드할것을 기대한다. 여기서 git submodule update --init --recursive를 사용할 수도 있지만 아래와 같이 clone 명령어를 변경하여 서브모듈 내용물을 포함하여 다운로드할 수 있다.

git clone --recursive <project url>

서브모듈로 변경


이미 존재하는 서브폴더를 외부에 의존적인 폴더로 변경하는 것은 약간 복잡하다. 다음 예를 보자.


magic roll-back can 이라는 새로운 프로젝트를 시작하기로 했는데 여기에는 rubber-band가 유용하다고 가정하자. slingshot 을 위해 만든 rubber-band를 독립적인 저장소로 분리하고 이것을 두개의 프로젝트에 서브모듈로 추가해야 한다.


먼저 rubber-band 폴더의 내용물을 slingshot에서  추출한다. git filter-branch 명령을 사용하여 rubber-band와 관련된 커밋만을 남겨둘 수 있다. git filter-branch 명령어는 우리의 저장소 이력을 재작성 하여 마치 rubber-band 폴더가 원래 저장소에 포함되지 않은것처럼 보이게 한다. git filter-branch명령어에 대해 더 자세히 알아보려면 다음 글을 참조한다.


slingshot안에 있는 rubber-band 를 자체적인 저장소로 동작하게 하기 위해서 slingshot 의 복사본을 만든다. cp -r 명령어를 사용하여 slingshot의 전체 폴더를 rubber-band 라는 폴더로 재귀 복사 한다.


cd ..
cp -r slingshot rubber-band


rubber-band는 또 다른 slingshot과 동일하지만 이제부터 rubber-band 저장소로부터 git filter-branch 명령어를 실행한다.


cd rubber-band
pwd # (double check before proceeding!)
git filter-branch --subdirectory-filter rubber-band -- --all


이 시점에서 rubber-band 라는 폴더는 slingshot 프로젝트와 유사하게 보이지만 rubber-band 폴더의 파일과 커밋 히스토리만을 갖게 된다.

이 폴더를 slingshot에서 복사하였기때문에 새 저장소는 여전히 slingshot에서 설정한 리모트 트래킹 브랜치(remote tracking branch)를 갖고있다. rubber-bandslingshot 에 푸시(push)하면 안되고 새로운 저장소에 푸시해야한다.


이제 깃허브에서 rubber-band라는 새로운 저장소를 만들고 리모트(remote)를 rubber-band로 업데이트한다. remote origin 이라고 가정하면 아래와 같이 입력한다.


git remote set-url origin https://github.com/<user>/rubber-band


git push를 통해  새로운 "generic rubber-band 모듈"을 퍼블리쉬 하면 rubber-band를 분리하고 이것을 자체적인 저장소로 만들게 된다. 이제 slingshot 저장소에서 기존의 rubber-band 폴더를 삭제해야한다.


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


slingshot을 업데이트하여 rubber-band를 서브모듈로 사용하기 위해 다음을 입력한다.


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

rock을 추가할 때와 같이 저장소 안의 저장소를 갖게 되었다. 부모 저장소인 slingshot 그리고 두개의 "서브" 저장소인 rockrubber-band를 포함하여 세개의 저장소가 되었다.


게다가 slingshot의 히스토리를 들여다보면 rubber-band가 폴더일때 만들었던 커밋들을 재발견 할 수 있다. folder를 삭제하더라도 히스토리가 삭제되는것은 아니다. 이것은 때때로 혼란스러울 수 있는데, rubber-band "자식" 저장소가 기존의 slingshot 커밋의 복사되고 변경된 버전의 사본을 갖고있기 때문이다.


불행하게도 이 시점에 협업자들이 slingshot을 pull 하게 되면 rubber-band 비어있게 된다. 협업자들이 아래 명령어를 실행하여 서브모듈의 모든 내용물을 다운로드하도록 해야한다.


git submodule update --init --recursive


rubber-bandmagic roll-back can에 서브모듈로 추가하고 싶다면 slingshotrock을 추가한것처럼 반복하면 된다.


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


'Computer > git' 카테고리의 다른 글

git 디렉토리 복사 후 복구  (0) 2018.10.10
git 에 사용자 정보 입력하기  (0) 2018.03.29
git 에서 새로운 브랜치 만들기  (0) 2018.02.02
git 의 오래된 항목 삭제하기  (0) 2018.01.22

+ Recent posts