Jujutsu VCS (JJ)

15년 정도 Git을 주력 형상관리 도구로 사용해 왔습니다. 하드웨어 엔지니어치고는 정말 오랫동안 사용해 온 셈이죠. 주변에서 다들 CVS나 SVN, Perforce에 머물러있을 때도, 혼자서는 Git으로 로컬에서 버전 관리를 해왔습니다.

github이 생기고 bitbucket이 몰락하며 mercurial에 대한 인기도도 사라지면서 점점 git이 대세가 되었습니다. 그러면서 자연스레 저는 주변 팀원들에게 git 문제가 있으면 물어보게되는 go-to person이 되었죠.

덕분에 마벨에서는 Git 강의도 하고, 인프라를 Git + Jenkins CI로 전환하는 걸 주도하기도 했습니다.

구글에 입사하고 나니 내부는 유명한 piper를 쓰고 있더군요. 그런데 그 위에 git 인터페이스를 입혀서 사용할 수 있었습니다. 거기에 mercurial 인터페이스를 사용할 수도 있어서, 내부는 mercurial용 인터페이스와 외부 저장소는 git (gerrit)을 사용해 왔습니다.

Mercurial 인터페이스를 만들던 팀에서 Jujutsu라는 형상관리 도구를 만들었더군요. 기존 도구를 개발 중단하고, Jujutsu (이하 JJ)로 전환하는 게 목표라고 하더군요. 나온지는 조금 되었는데, 전환된다는 소식에 사용해 보기 시작했습니다.

알고보니 이미 오픈소스로 공개를 해서 Git 저장소에서도 사용할 수가 있더군요. 그래서 하나의 도구로 구글 내부 Piper와 외부 Gerrit에 모두 쓸 수 있다기에 도전해 보았습니다.

사용한 지 하루도 채 지나지 않아 JJ의 매력에 푹 빠졌습니다. 제가 Git + Gerrit을 사용하면서 가장 불편했던 점을 확실히 해결해 주더군요.

Git의 불편한 점 하나는 Gerrit에 CL (changelist)을 여러개 사슬로 묶어서 리뷰를 할 때 중간 CL을 수정하기가 쉽지 않다는 점이었습니다. Commit 1->2->3 이렇게 3개가 Gerrit에 업로드 되어있다면 1번이나 2번을 수정하려면 3에서 새로운 커밋을 하나 만들어서 (4라고 가정) rebase -i로 커밋 4를 1번이나 2번 바로 다음으로 옮긴다음 squash나 fixup으로 합쳐야 했습니다. 그렇지 않으면 commit 1이나 2의 브랜치로 바로 switch하고 수정을 하면 따라가는 CL은 여전히 예전 레퍼런스를 참조하고 있어서 tree view에서 분기가 발생하게 됩니다. Rebase할 때 브랜치가 정의되어 있으면 이전 브랜치는 남아있고 새로운 브랜치만 rebase가 되는게 기본값인데 이건 --update-refs 옵션으로 자동으로 branch reference를 업데이트 해 줄수 있어서 크게 문제는 되지 않습니다.

JJ에서는 이 모든 과정을 JJ가 자동으로 합니다. commit 1을 수정하고 싶으면 commit 1을 edit하고 저장하면 바로 commit 2, 3이 자동으로 rebase됩니다.

이 rebase과정에서 git의 불편한 점이 하나 더 생기는데요. 만일 rebase중에 conflict이 발생하면, 바로 그 자리에서 해결해야지만 다음 과정으로 진행할 수 있게 됩니다. 그래서 branch를 머지하거나 많이 분기되어버린 변경점을 rebase한다면 중간 중간 계속 conflict을 해결하기 위해 작업을 해 줘야 합니다. 이 과정이 두세번 반복되면 어디에서 어떻게 고쳐졌는지 흐름을 파악을 못해서 다시 시작해야 하는 경우도 여러번 있었습니다.

JJ는 conflict이 발생하면 그대로 진행이 됩니다. conflict조차 하나의 상태라 rebase를 하면서 conflict이 생기면 해당 커밋에 conflict이라고 표시하고 계속 rebase를 진행합니다. 마지막 rebase가 다 끝나고 conflict 파일을 resolve하면 알아서 해당 커밋의 conflict 상태를 해결하고, 그 다음 따라오는 커밋을 모두 rebase를 합니다. 그래서 제게는 rebase과정이 무척이나 깔끔하게 끝난다는 느낌이 들더라구요. 실제로도 피로도도 확 줄어들기도 하구요.

그 외에 몇가지 제 기준으로 편리한 점도 있기는 합니다. commit이 더이상 SHA로 관리되는게 아니라 change ID로 관리되어, 아무리 해당 커밋을 변경해도 change id는 유지됩니다. Gerrit의 Change-Id 와 동일한 개념인데요. 이것 덕분에, branch를 만들 이유가 거의 사라집니다. 가끔 bookmark (branch와 동일한 개념)를 만들 때도 있긴 하지만 대부분은 그냥 change id 그대로 놔두고 change id를 왔다 갔다 하며 작업합니다. 처음엔 어색하게 느껴졌는데 제개는 훨씬 직관적이더군요. 동시에 작업하는 가지수가 10개를 넘어간다면 좀 복잡하게 느껴질 수도 있긴 합니다. 그때는 bookmark로 git과 비슷하게 관리하는 게 나을 것 같습니다.

JJ는 backend로 git 저장소를 사용하기 때문에, 현재 git을 사용하고 있다면 혼자서만 jj를 사용하고 다른 팀원은 여전히 git을 사용할 수 있습니다. svn -> git, darc, hg 로 변경하려면 모두 같이 바꾸어야 했는데, 그게 큰 장벽이었죠. 그 부분을 잘 고려한 것 같습니다.

댓글