본문 바로가기

Better SW Development

[번역] 서브버전 사용자를 위한 머큐리얼(mercurial)이전 가이드

조엘 온 소프트웨어로 유명한 조엘이 hginit.com 이라는 사이트를 만들어서 기고한 글 중, 서브버전 사용하시는 분들을 대상으로 하는 서브버전 재교육에 해당하는 부분을 번역해 봅니다.  hginit.com의 글을 읽고 서브버전에서 머큐리얼로 이전한 입장에서, 혼자가 아닌 함께 가고 싶은 마음에 부족하지만 번역 작업을 해 봅니다. ^^; 분산 저장소를 사용하고자 하시는 분들께 도움이 되었으면 좋겠습니다. 다만, 개인적인 여건상 '내맘대로의 번역'이 될 가능성이 매.우. 높습니다. 혹 어색한 부분이 있더라도 부디 너그러운 마음으로 봐 주시면 감사하겠습니다. 영어에 익숙하신 분은 원문(hginit.com)이 더 편하게 읽히실 수도 있습니다. 그리고 지적하실 부분이 있으시면 알려주세요. 반영하겠습니다.

참고로, 원저작자 조엘
(Joel Spolsky)에게 사전 허락을 받진 않았습니다만 절 비난하거나 고소하진 않으리라 믿으며 번역했습니다. :)

---

서브버전 재교육(Subversion Re-education)


출처 : HGINIT.com

만일 당신이 서브버전(Subversion)을 사용해 왔다면, 머큐리얼(Mercurial)은 혼란스럽다고 느낄 겁니다. 본 튜터리얼은 머큐리얼이 작동하는 방식에 있어 서브버전과 가장 크게 다른 점에 대해 다루고 있습니다. 서브버전을 사용한 적이 없다면, 그냥 다음으로 넘어가길 바랍니다.
.
.
.

내 회사(포그크릭)의 개발자들이 서브버전에서 머큐리얼로 이전을 결정했을때, 난 혼란스러웠다.

우선적으로, 난 왜 우리가 이전하면 안되는지에 대한 갖가지 어리석은 이유를 댔다. "우리는 중앙 서버에 저장소를 유지해야 합니다. 그래야 안전합니다."라고 이야기했다. 하지만 그게 말이지... 내가 틀렸다. 머큐리얼을 사용하면 모든 개발자가 자신의 하드디스크에 전체 저장소의 복사본을 갖게된다. 사실 이 편이 더 안전하다. 게다가, 거의 모든 머큐리얼을 사용하는 팀들은 중앙 저장소도 함께 사용한다. 그리고 이 저장소는 강제로 백업을 할 수도 있고, 세 곳의 보안구역으로 나누어서 각각을 (배틀스타 갤럭티카의)사일런, (스타워즈의) 스톰트루퍼, 그리고 한눈에 홀딱 반할만한 (강아지)래브라두들들(뭐 아니면 당신네 IT부서에 필요한 뭐든지 간에 그걸로)로 완성할 수도 있다.

"분산 버전 컨트롤의 문제점은 너무 쉽사리 브랜치(branch)가 만들어 진다는 점입니다. 그리고 브랜치를 만드는건 항상 문제들을 일으키죠"라고 내가 말했다. 이것도 마찬가지로 내가 틀린걸로 판명되었다. 난 계속 얼굴에 먹칠중이었다. 서브버전에서는 브랜치를 만들면 문제가 생긴다.  왜냐하면, 서브버전은 머지(merge) 작업을 하기 위한 충분한 정보를 저장하지 않기 때문이다.  머큐리얼은 머지작업이 고통 없고 쉽다. 그래서 브랜치를 만드는 것이 흔한일이고 아무런 해가 없다.

그리고는 나는 또 말했다. "좋아요. 머큐리얼을 사용하죠. 하지만 내가 이해할 수 있을거라고는 생각하지 말아주세요."  난 제이콥에게 내가 서브버전에서 일반적으로 사용했던 기능들의 리스트와 그에 해당하는 머큐리얼의 기능을 쪽지로 만들어 달라고 요청했다.

이 시점에서 그 쪽지를 보여줄 수 도 있지만, 난 그러지 않을 생각이다. 그 쪽지는 수 개월간 내 머리속을 엉망으로 만들었기 때문이다.

만약 당신이 서브버전을 쭉 사용해왔다면, 당신의 뇌는 아마 살짝.. 음.. 어떻게 말해야 무례하지 않을려나.. 음.. 당신은 뇌가 손상되었다. 아.. 이건 별로 예의바른게 아니지.. 어.. 당신은 재교육이 조금 필요하다. 난 머큐리얼이 서브버전보다 더 복잡하다고 쭉 생각하면서 6개월동안 뇌가 손상된채로 돌아다녔다. 그렇지만 그건 내가 머큐리얼이 실제로 어떻게 동작하는지 이해하지 못했기때문이다. 그러다가 한번 이해하고 났더니, 와우! 정말 쉽다는걸 알게 되었다.

그래서 난 당신을 위해서 이 튜토리얼을 썼다. 그리고 가급적 서브버전의 관점에서 설명하지 않기 위해서 주의를 기울여서 작성했다. 세상에는 뇌가 손상된 사람들이 이미 충분히 많다. 그래서, (튜터리얼의) 시작 부분에 서브버전으로부터 이전중인 당신같은 사람들을 위한 챕터를 하나 만들었다. 이 챕터에서 당신이 입은 손상을 가능한한 최대한 되돌려서 깨끗한 석판같은 상태에서 머큐리얼을 학습할 수 있도록 노력할 예정이다.

만약 서브버전을 사용해본적이 없다면, 다음 챕터(Ground Up Mercurial)로 넘어가도 무방하다.

그럼 준비되셨남? 오케이. 짧은 퀴즈로 시작해 보자.

질문1. 당신은 단번에 완벽한 코드를 작성합니까?

만약 "네!"라고 답했다면, 당신은 거짓말장이에 사기꾼이다. 탈락이다. 다시 시험보삼.

새로운 코드는 버그투성이다. 그럴듯하게 동작하게 될때까진 시간이 꽤 걸린다. 그러는 동안 팀의 다른 개발자들은 트라우마에 빠질 수도 있다.


다음은 서브버전이 동작하는 방식이다.

- 새로운 코드를 체크인하면, 다른 모든 사람들이 그 코드를 갖게 된다.


당신이 작성하는 새로운 코드들은 (늘 그렇듯) 버그가 있기 때문에, 당신에겐 두 개의 선택지가 있다.

- 버그가 있는 코드를 체크인해서 다른 모든 사람들을 돌아버리게 만든다.
- 버그를 다 제거하기 전까진 체크인을 하지 않는다.


서브버전은 당신에게 항상 이런 딜레마를 준다. 방금 작성한 새로운 코드가 들어있기 때문에 저장소가 버그로 득실대거나, 혹은 새로 작성한 코드는 저장소에 들어 있지 않거나.

(다른) 서브버전 유저들처럼, 우린 이 딜레마에 아주 익숙해져 있다.

서브버전(을 사용하는) 팀의 맴버들은 종종 수 일에서 수 주동안이나 아무것도 체크인을 하지 않곤 한다. 서브버전을 사용하는 팀의 경우, 새로 들어온 신입들은 새로운 코드를 체크인하는걸 끔찍히 두려워하게 된다. 빌드를 깨뜨릴까봐, 혹은 선임 개발자 마이크(Mike)를 열받게 만들까봐, 혹은 어떤 다른 이유로든 말이다. 예전에 한번은, 빌드를 깨드린 어떤 체크인 때문에 마이크가 완전 열이 받아서 인턴사원의 큐비클(=칸막이 사무공간)로 폭풍돌진해 책상위의 물건들을 확 쓸어버리며 "넌 오늘부로 끝이야!"라고 소리를 친적이 있다. (말처럼 잘리진 않았지만, 그 불쌍한 신입은 정말 바지를 적셨다)

체크인에 대한 이런 모든 두려움으로인해 사람들은 수 주 동안 버전 컨트롤의 이점을 사용하지 않고 코드를 작성한다. 그러다 결국 체크인하는 것을 도와줄 선임을 찾아 나서게 된다. 사용 안할거면 버전 컨트롤을 왜 쓰나?

다음은 서브버전 사용시의 삶을 나타내는 간단한 그림이다.


머큐리얼의 경우, 모든 개발자는 각자의 테스트탑안에 살아있는 자신만의 저장소를 갖는다. 


따라서 당신은 개인저장소에 자신의 코드를 커밋할 수 있다. 그리고 원할때는 언제든 버전 컨트롤의 모든 장점을 누릴 수 있다. 코드가 조금이라도 더 개선된 어떤 논리적인 시점에 도달하면, 언제든 커밋 할 수 있다. 견고한 코드가 만들어 졌다면, 새로운 코드를 다른 사람들이 사용할 수 있게 하고 싶을 것이다. 그럼 당신은 변경사항들(changes)을 개인 저장소에서 중앙 저장소로 밀어 넣는다.(=push)  사용할 준비가 되었을 때, 다른 사람들은 중앙저장소에서 (변경사항들을) 끌어올수 있고(=pull), 당신의 코드를 보게 될 것이다.

머큐리얼은 새 코드 커밋이라는 행위와 다른 사람을 괴롭히는 행위를 분리해 놓았다.

그리고 이건 당신이 코드를 커밋(hg com)해도 다른 사람이 당신의 변경된 코드들을 가져가는 일은 발생하지 않는다는 걸 뜻한다. 안정적으로 모든게 잘 동작하는 만족스런 변경사항들이 많이 만들어 졌다면, 그때 해당 변경사항들을 중앙 저장소로 밀어넣으면 된다. 


큰 개념적인 차이점 하나 더

어떻게 모든 길(street)이 각자 이름을 하나씩 가지는 건지 아는가?

글쎄.. 사실, 일본에서는 모든 길이 이름을 갖진 않는다. 일본인들은 보통 길들 사이의 블럭에 번호를 매기고 아주아주 중요한 길만 이름을 붙인다. 서브버전과 머큐리얼 사이에는 이와 유사한 차이점이 있다.

서브버전은 리비전들(revisions)에 대해 생각하는 걸 선호한다. 하나의 리비전은 시간상의 특정 지점에서 전체 파일시스템이 어떻게 보이는지를 나타낸다.

머큐리얼에서는, 체인지셋들(changesets)에 대해서 생각한다. 하나의 체인지셋은 하나의 리비전과 다음 리비전 사이의 변경사항에 대한 간결한 목록이다.


좌측엉덩이, 왼쪽볼기짝 : 차이점이 뭔데?

차이점은 이렇다. :) 당신과 내가 같은 코드를 가지고 작업하고 있다고 한 번 가정해보자. 우린 코드에 대해 브랜치를 딴 다음, 각자의 작업장소로 흩어져서는 무수히 많은 변경사항들을 개별적으로 만들어 낸다. 각자의 코드는 꽤 많은 차이가 나게 된다.

우리가 머지작업을 해야 할때, 서브버전은 각자의 리비전들 - 내가 수정한 코드의 리비전, 당신이 수정한 코드의 리비전 - 을 살펴본다. 그리고 그것들을 거대한 한 덩어리로 두들겨 합칠 방법을 떠올리려 노력하게 된다. 보통은 잘 안된다. "머지작업 충돌"페이지들을 무수히 만들어 내게 되는데, 사실 그건 충돌이 아니고, 그저 서브버전이 우리가 작업한 내용을 이해하지 못하는 것일 뿐이다.

이와 반대로, 머큐리얼을 이용할 경우 우리가 서로 떨어져서 작업하는 동안, 머큐리얼은 일련의 체인지셋들(=변경분량들)을 유지하기 위해 바삐움직인다. 그래서 우리가 서로의 코드를 합쳤으면 할때, 실제로 머큐리얼은 훨씬 더 많은 정보를 갖고 있다. 단순히 최종결과물을 보면서 '어떻게 하면 이걸 하나로 합칠수 있을까'라고 생각하는것이 아니라, 우리 둘이 각자 변경한 것이 무엇인지를 알고 그 변경사항들을 재 적용한다.

이를테면, 만약 내가 어떤 함수를 약간 고치고, 그 함수를 어딘가로 옮겨버린다면, 서브버전은 이 작업단계들을 실제로 기억하지 않는다. 그렇기 때문에 합쳐야 할 시간이 왔을때, 서브버전은 '새로운 함수가 갑자기 하나 나타났군'이라고 생각할 것이다. 반면에서 머큐리얼은 각 변경작업의 단계들을 별도로 분리해 기억할 것이다. 함수 변경됨, 함수 옮겨짐. 그리고 이건 만약 (나와는 별개로 작업하고 있는) 당신이 그 함수를 조금 변경한다면, 훨씬 더 잘 우리의 변경부분들을 성공적으로 머지할 것이라는 걸 의미한다.

머큐리얼은 모든것을 체인지셋 관점으로 생각하기 때문에, 당신은 이들 체인지셋으로 흥미로운 작업들을 하게 된다. 당신은 변경분을 중앙 저장소에 밀어 넣어서(push) 모든 사람들과 (소스)충돌을 일으키는 대신에 어떤 팀 동료에게만 넘겨줄(push)수도 있다.

만약 이 모든게 다소 혼란스럽게 보인다 할지라도, 걱정하지 마시길. 이 튜터리얼을 진행하는 동안, 모든걸 완벽히 이해하게 될 것이다. 지금 알아야 하는 가장 중요한 점은, 머큐리얼은 "리비전"이 아닌 "체인지셋"의 관점으로 생각하기 때문에 서브버전보다 코드 머지를 훨씬 잘 할 수 있다는 점이다.

그리고 그 건 당신이 브랜치를 만드는 것에대해 훨씬 더 편하게 느끼게 될 것이라는 걸 뜻한다. 머지작업이 (더이상) 악몽이 되지 않을 것이다.

재미있는 이야기 하나 들려줄까? 나랑 이야기를 나눠본적이 있는 거의 모든 서브버전 사용 팀들은 똑같은 이야기를 다양한 버전으로 내게 들려줬다. 이 이야기는 너무 흔한이야기라 나는 "서브버전 스토리 #1"이라고 이름 붙여야 했다.

해당 이야기는 이렇다. : 어떤 시점에 팀은 코드 브랜치를 시도한다. 보통 그런식으로 고객에게 제공하는 배포버전은 개발자들이 갖고 노는 버전과는 별개의 브랜치로 분리된다. 그리고 모든 팀들은 내게 이렇게 말했다. "브랜치를 만드는건 문제가 없었어요. 머지를 해야 할 때가 되기 전까진 말이었죠. 그리고 (머지작업은) 정말 악몽이었어요."  5분짜리 절차가 되었어야 할 작업이 6명의 개발자가 컴퓨터 하나를 붙들고
2주에 걸쳐 안정된 빌드(stable build)에서 개발빌드로 버그를 하나하나씩 수작업으로 재반영하는 걸로 끝이 난다.

그러고나선 거의 모든 서브버전 팀들이 내게 이렇게 말했다. 맹세컨데 "다신 이렇게 안할겁니다". 브랜치하는 작업은 이제 끊을려고요. 라고. 그리고 현재 그들은 이렇게 (작업)한다. : 각각의 새로운 기능들은 거대한 #ifdef문 안에 넣는다. 그렇게함으로써 하나의 트렁크(trunk)에서 작업할 수 있다. 디버그가 끝날때까진
고객들은 새로운 코드를 전혀 볼 수가 없다. 솔직히말해서, 그건 좀 웃기는 일이다.

안정화 버전의 코드와 개발코드를 분리하는 것이 바로 소스코드 컨트롤이 의도하는 바다.

당신이 머큐리얼로 전환했을때, 어쩌면 이런 내용을 실감하지 못할수도 있다. 그러나 브랜치가 다시 가능한 상황이 되었을때, (이젠) 두려워할 필요가 없다.

그건 (여러 개의) 팀 저장소들을 가질 수 있고, 거기에서 작은 팀의 개발자들이 새 기능을 함께 작업할 수 있다는 걸 뜻한다. 그리고 완성되었을때 중앙 개발 저장소로 합치면, 잘 동작한다

그건 (또한) QA팀들이 코드를 테스트해 볼 수 있는 QA용 저장소를 가질 수도 있다는 걸 뜻한다. 잘 동작하면, 해당 QA팀은 중앙저장소를 그 코드들을 밀어 넣을 수 있다. 다시말해서, 중앙 저장소는 항상 견고하고 테스트된 코드들을 가진다. 그리고 (마찬가지로 중앙저장소의 코드들은) 잘 동작한다.

그건 (또한) 개별 저장소들에서 여러 실험들을 해 볼 수 있고, 잘 동작한다면 중앙 저장소로 머지해 넣는다. 그리고 만약 동작하지 않는다면, 해당 부분들을 버릴 수 있다. (여전히 중앙저장소의 코드들은) 잘 동작한다.

(역자주) 이런 이유로 서브버전을 사용하는 팀들 중 경험있는 상당수의 팀은 샌드박스(sandbox) 저장소를 따로 운영한다.


마지막 큰 개념상의 차이점 하나

서브버전과 머큐리얼의 주요한 마지막 개념상의 차이점은 사실 큰 건 아니다. 하지만 만약 인식하고 있지 않다면, 걸려 넘어지는 일이 발생할 것이다. 그 내용은 다음과 같다.

서브버전은 기본적으로 파일들에 대해 리비전 관리를 한다. 그런데, 머큐리얼에서는 리비전 관리가 모든 하위 디렉터리를 포함한 디렉토리 전체 대상으로 일어난다.

서브버전에서 당신이 아는 주된 방식은 , 만약 당신이 하위디렉터리로 들어가서 변경한 부분들을 커밋한다면, 오로지 하위 디렉터리와 그 디렉터리 아래에 있는 변경 부분들만 커밋된다는 것이다. 이건 다른 하위 디렉터리 안에 존재하는 어떤 변경 사항들에 대한 커밋을 잠재적으로 깜빡할 수도 있다는 걸 의미한다. 반대로 머큐리얼에서는 항상 모든 명령들이 전체 트리구조에 적용된다. 만약 당신의 코드가 c:\code에 있다면, 당신이 hg commit 명령어를 날렸을때 (당신이 현재) c:\code에 있던 혹은 어떤 하위 디렉터리에 있던지간에, 동일한 효과를 갖는다.

이건 큰 문제는 아니지만, 만약 당신이 회사 전체가 사용하는 단일 거대 저장소에 익숙하다면, 그리고 그 저장소로부터 사람들이 자신이 다뤄야 하는 하위 디렉터리들만을 체크아웃해서 작업하고 있다면, 머큐리얼로 작업하는 건 그닥 좋은 방식이 아니다. 그보다는 각각의 프로젝트를 위한 좀 더 작은 저장소들을 갖는편이 더 낫다.


마무리하며...

이 부분은, 내 말을 말 그대로 그냥 받아들여야 하는 내용이다.

머큐리얼은 서브버전보다 낫다.

팀과 함께 소스코드를 작업하는 더 나은 방식이고,  당신이 소소코드에 대해 작업하는 더 나은 방식이다.

여하튼 머큐리얼이 더 낫다.

그리고 내 말을 기억하길 바란다. 만약 당신이 머큐리얼의 동작 방식을 이해한다면, 그리고 머큐리얼이 동작하는 방식으로 일한다면, 해당 방식과 싸우려고 하지 마라. 그리고 머큐리얼을 사용하면서 예전 서브버전 방식처럼 작업하려고 노력하지 마라. 대신에 머큐리얼이 당신에게 기대하는 방식대로 작업하는걸 배워라. 그러면 행복해지고, 성공하고, 먹고사는데 지장없고, 언제나 (집에서 마음편히) 리모컨으로 TV를 켜보게 될 것이다.

그리고 아마 초반에, 당신은 머큐리얼을 포기하고 서브버전으로 돌아가고 싶은 유혹을 받게 될 것이다. 난 그러리라는걸 안다. 왜냐하면 당신은 마치 외국에서 살고 있는 것처럼 어색하고, 향수병이 생겨서는 모든 종류의 자기합리화에 맞닥드리게 될테니까. 이를테면 디렉터리들 단위로 작업하는 머큐리얼이 디스크공간을 너무 많이 차지할 것이라고 주장하는 식으로 말이다. 하지만 그건 오해다. 실제로는 서브버전의 디렉터리들 보다 공간을 덜 차지한다. (정말이다!)

어쨌든 그리고나서는 당신은 서브버전으로 되돌아갈 것이다. 왜냐하면 서브버전 방식으로 브랜치를 시도했고, 그로인해 혼란을 겪었고, 결국 그다지 잘 동작하지 않았을 테니까. 당신은 저장소들을 복제(=클로닝)함으로써 머큐리얼식 브랜치를 했어야 했다. 서브버전에서 작업했던 식으로가 아니라 말이다. 날 믿어라. 머큐리얼의 작업처리 방식을 배우면 잘 동작할 것이다.

그리고  또 당신은 제이콥 혹은 당신 사무실에 있는 제이콥과 동급의 누군가에게 "서브버전에서 머큐리얼로의 요약명령집"를 만들어 달라고 시킬것이다. 그리고는 hg fetchsvn up과 비슷하다고 생각하면서 세 달쯤을 보내게 될 것이다. 실제로 hg fetch가 하는 일이 무엇인지 알지못한 채로 말이다. 아마 여러일들이 틀어질 것이고, 머큐리얼을 비난하게 될 것이다. 실제로는 머큐리얼이 어떤식으로 동작하는지 이해하지 못한 당신 자신을 비난해야 할 순간마다 말이다.

난 당신이 그러리란걸 안다. 왜냐하면 내가 그랬었기 때문이다.

동일한 실수를 하지마라. 머큐리얼을 배우고, 머큐리얼을 신뢰하고, 그리고 머큐리얼의 작업 처리 방식을 이해해라. 그리고나면 소스 코드 컨트롤에 있는 가장 최근의 모든 버전을 옮기게 될 것이다.

어떤 벤더가 라이브러리를 하나 업데이트 했을때 당신의 경쟁자들이 그로 인해 발생한 모든 머지 충돌을 해결하느라 한 주를 바쁘게 보내는 동안, 당신은 hg merge라고 타이핑하고는 당신 자신에게 이렇게 말하게 될것이다. "오예~ 끝내주는데~ 그냥 바로 되잖아". 그리고나면 아마 마이크는 차분해 질거고, 인턴사원과 담배를 나눠피게 될거다. 머잖아 봄이 올거고, 그러면 근처 대학의 꼬마들은 두꺼운 파카점퍼를 얇은 A&F T셔츠랑 교환하려 할거다. 그리고 삶은 더 나아져 있을 것이다.

이하 hginit.com의 다른 챕터들은 지식을 함께 나누기 위해 노력하고 계신 다른 블로거 분들의 번역기부를 기대해 봅니다. :)

감사합니다.