브랜치와 수술

서브트리

서브트리는 다른 저장소를 내 저장소의 디렉터리 안으로 복사해 와요. 그다음부터 그 파일들은 실제로 거기 있어요. 평범한 git clone이 그것들을 가져오고, git checkout은 다른 파일과 똑같이 그것들을 옮기며, 그 디렉터리가 다른 데서 왔다는 걸 아무도 몰라도 돼요.

바로 그 점이 서브모듈과의 차이 전부예요. 서브모듈은 포인터만 저장하고, --recurse-submodules와 자기만의 체크아웃, 그리고 헷갈리지 않게 관리해야 할 자기만의 detached HEAD를 요구하죠.

⌘K → 서브트리.

히스토리에서 발견된 벤더링 디렉터리와, Gitcito가 그것에 대해 기억하는 출처

아무도 말해 주지 않는 함정

git은 서브트리에 대한 목록을 아무것도 기록하지 않아요. 서브모듈에는 모든 URL과 경로가 적힌 .gitmodules가 있어요. 서브트리에는 아무것도 없고, 가져오기를 수행한 커밋에 붙은 git-subtree-dir: 트레일러 하나뿐이에요.

그래서 어떤 저장소가 서브트리를 품고 있으면서도 그게 어디서 왔는지 알아낼 방법을 전혀 주지 않을 수 있어요. Gitcito는 할 수 있는 만큼은 해요.

  • 목록은 그 트레일러들을 읽어 히스토리에서 찾아내요. 누가 어떤 도구로 추가한 서브트리든 다 나타나요.
  • 출처 저장소와 ref는 Gitcito가 이 저장소의 git 설정에 기억해 둬요. 히스토리에서 발견된 서브트리는 그 항목들이 비어 있는 상태로 시작하는데, 한 번 채워 넣으면 그때부터 풀과 푸시가 동작해요.

기억된 값은 .git/config의 gitcito.subtree.* 아래에 살아서, 저장소에는 남지만 클론으로 따라가지는 않아요. 잊기는 그 값을 지우고 다른 건 건드리지 않아요.

추가하기

항목 의미
디렉터리 어디에 놓일지, 예를 들어 vendor/parser. 아직 존재하지 않아야 해요
출처 저장소 URL 또는 디스크상의 경로
브랜치 또는 태그 무엇을 가져올지
스쿼시 히스토리 전체 대신 커밋 하나로 들여오기

이유가 없다면 스쿼시는 켠 채로 두세요. 끄면 그 라이브러리의 커밋 하나하나가 내 로그에 영원히 섞여 들어가고, git log는 더 이상 내 프로젝트에 관한 것이 아니게 돼요.

함께 살아가기

동작 무엇을 실행하는지
풀 git subtree pull — 업스트림 변경이 내 디렉터리로 머지되어 들어와요
푸시 git subtree push — 그 디렉터리 아래의 내 로컬 변경이 출처로 돌아가요
분리 git subtree split -b <branch> — 그 디렉터리만의 히스토리를 브랜치로 뽑아내요. 파일은 루트에 놓인 채로요

분리는 알아 둘 값어치가 있어요. 벤더링된 디렉터리를 다시 독립 저장소의 히스토리로 되돌리는 일이고, 서브트리가 서브트리이길 그만두는 방법이 바로 이거예요.

알아 둘 만한 한계

  • 푸시는 느려요. 매번 그 디렉터리의 히스토리를 처음부터 다시 계산하거든요. 큰 저장소에서는 즉시가 아니라 수 초에서 수 분이 걸리고, Gitcito는 기다리는 것밖에 할 수 없어요.
  • 풀은 머지예요. 그래서 어떤 머지와도 마찬가지로 충돌할 수 있고, 그러면 충돌 해결기에 도착하게 돼요.
  • git subtree는 git 내장 명령이 아니라 contrib 스크립트예요. 최소한으로 구성된 git 설치본에는 없을 수 있어요. Gitcito는 "'subtree' is not a git command"를 그대로 전달하는 대신 그 사실을 분명히 말해 줘요.
  • 스쿼시된 히스토리는 나중에 되돌릴 수 없어요. 그 커밋들은 애초에 가져와지지 않았거든요.
  • Gitcito는 서브모듈을 서브트리로, 또는 그 반대로 변환하지 않아요.

함께 보기: 머지와 리베이스 · UI로 하는 배관 작업

GitHub에서 이 번역 개선하기