목공책 하나 들이셔요~

2013년 12월 19일 목요일

[Hg] 2. 팀을 위한 Mercurial 셋팅

이 글은 Joel Spolsky가 저술한 Mercurial 튜토리얼 시리즈 중에서 세번째 글인 "Setting up for a Team"을 번역한 것입니다. 원문은 다음 링크를 참조하세요. http://hginit.com/02.html

Mercurial로 공동 작업을 할 때 가장 보편적인 방법은 개발자 각각의 컴퓨터에 있는 개인 레포지토리에 추가하여 중앙 레포지토리를 셋업하는 겁니다. 중앙 레포지토리는 우리가 만들었던 코드 변경에 대해 같이 모여서 거래하고 협의하는 일종의 미팅 장소라고 보면 됩니다.



가장 빠르고 간단하게 중앙 레포지토리를 만드는 방법은 Mercurial에서 제공하는 웹서버를 이용하는 것입니다. 해야할 것은 hg init으로 레포지토리를 만든 다음 hg serve로 웹을 서비스하는 것입니다. 디폴트 포트는 8000번 입니다.


이 중앙 서버의 이름을 joel.example.com이라고 한다면, 웹브라우저에서 http://joel.example.com:8000 주소로 접근하면 레포지토리의 내용을 볼 수 있습니다.


이 웹서버가 떠 있는 동안 당신은 서버의 레포지토리를 복제(clone)하여 제 컴퓨터로 옮길 수 있습니다. 지금 당장은 이 레포지토리는 비어 있습니다. 그러므로 제가 이를 복제하면 빈 레포지토리가 만들어 집니다.


이제 제가 가장 좋아하는 구아카몰(guacamole) 레서피를 적은 guac라는 파일을 아래와 같이 만듭니다.


이 파일을 레포지토리에 추가하고 커밋함으로서 첫 공식 리비젼을 만듭니다.


커밋을 위한 메시지를 기록합니다.


그리고 이 파일을 약간 수정합니다. 그래서 레포지토리에 히스토리가 만들어 집니다.


변경 내용을 커밋합니다.


여기서 커밋을 할 때 -m 옵션을 쓴 걸 볼 수 있습니다. 이는 hg commit 명령을 내릴 때 바로 커밋 메시지를 입력할 수 있게 하며 별도의 에디터를 띄우지 않아 편리합니다.

자 이제 우리가 어디에 있는지 봅시다. 지금까지 우리는 중앙 레포지토리를 만들었고 그것을 복제하여 제 컴퓨터에 레포지토리를 만들었습니다. 그리고 두번의 변경을 커밋하였습니다. 하지만 이 변경은 제 컴퓨터의 레포지토리에 기록된 것이지 중앙 레포지토리에는 기록되지 않은 것입니다. 그래서 세상은 아래와 같이 보입니다.


이제 hg push 커맨드를 쓸 차례입니다. 이 커맨드는 제 컴퓨터의 레포지토리에 저장된 변화들을 중앙 레포지토리로 옮기는 역할을 합니다.


오 대단합니다. 제대로 동작하지 않은걸로 보입니다. 제가 보안에 대해서 미처 생각하지 못했기 때문에 웹상의 아무라도 이 중앙 레포지토리에 접속할 수 있게 할 뻔 했습니다. 하지만 일단은 외부에서 접속이 가능하도록 설정을 변경하도록 합니다. 이건 중앙 서버의 .hg/hgrc 파일을 수정함으로서 가능합니다.


이런 설정은 당연히 안전하지 않습니다. 하지만 당신이 일하는 곳이 잘 보호된 LAN 환경이고 좋은 방화벽 환경하에 있다면 큰 문제가 되지 않을 수도 있습니다. 보안 설정에 대해서는 좀 더 깊은 내용의 문서를 읽어볼 것을 권합니다.

설정을 변경했음로 서버를 새로 띄워야 합니다.


그리고 이제 다시 푸쉬를 해야 합니다.


예이~ 이제 세상은 이렇게 보일 겁니다.


당신이 어떤 생각을 할 지 알고 있습니다. "어이쿠, 조엘, 이건 이상하잖아요? 아니 왜 레포지토리가 파일이 아니라 변경 내용을 저장하는 거죠? 도대체 guac 파일은 어디에 있나요?"

네 참 이상합니다. 그러나 이게 분산형 버전 컨트롤 시스템이 일하는 방식입니다. 레포지토리는 단지 변경사항들만 잔뜩 쌓아놓고 있습니다. 변경사항들을 투명 필름지라고 상상해 보십시요. 투명 필름을 여러겹 쌓아놓고 제일 위에서 바라보게 되면... 짜쟌~ 하고 현재 버전의 파일을 보게 되는 겁니다. 투명 필름을 한장씩 벗겨내면 한 리비젼씩 옛날 버전을 보게 되는 것이구요.

이제 중앙 레포지토리의 내용을 웹브라우저로 보면 내용이 보이게 됩니다.


당신이 예측했던 그대로일 겁니다.

이제 로즈가 제 일을 도와 레서피를 수정했으면 합니다. 로즈는 테스트 팀에 속해 있습니다. 당신은 그녀에게 새로운 버전의 코드를 전달할 수 있으며, 그녀는 23개의 다른 리눅스 배포판에서 해당 코드가 잘 동작하는지 테스트합니다.


로즈는 hg clone 명령으로 레포지토리의 복사본을 자신의 컴퓨터로 복사해 옵니다. hg clone 명령은 두개의 인자를 받습니다. 하나는 레포지토리의 URL이고 다른 하나는 복제를 해 올 디렉토리의 이름입니다. 그녀는 recipes라는 디렉토리를 지정했습니다.


그녀는 전체 히스토리를 보기 위해 hg log 명령을 사용했습니다. 그러므로 실제로 그녀는 히스토리를 포함한 전체 레포지토리를 다운로드 받은 셈입니다.

로즈는 어떤 변경을 한 다음 그것을 체크인 했습니다.


그리고 그녀는 커밋을 합니다. 이 커밋은 그녀의 컴퓨터 안에 있는 레포지토리에 하는 것이므로 중앙 서버를 필요로 하지 않습니다.


로즈가 코드를 변경하는 동안 저도 제 나름의 코드를 변경하고 있었습니다.


자 이제 저의 변경을 커밋하고 나서 로그를 살펴보면 체인지셋 #2의 로그가 로즈의 것과 다름을 확인할 수 있습니다.


우리의 히스토리는 이제 서로 달라지기 시작했습니다.


하지만 걱정 마세요. 우리는 곧 이런 차이점이 어떻게 하나로 합쳐져서 하바네로 소스의 포테이토 칩을 만들 수 있는지 보게 될 겁니다.

로즈는 중앙 서버와의 연결을 끊은 채로 자신의 변경을 계속 해 나갈 수 있습니다. 자신의 레포지토리에 커밋하고 혹은 복구하는 등 자유롭게 가능합니다. 어느 순간 그녀는 자신의 변경 사항을 모든 이들과 공유하고 싶다는 생각이 듭니다. 이는 외부 세계로 커밋을 함으로서 가능합니다. 그녀는 hg outgoing 이라는 커맨드를 내림으로서 중앙 서버로 보내질 변경 리스트에 대한 정보를 볼 수 있습니다. 이 변화들은 hg push 명령을 내리면 중앙 서버로 보내질 것들입니다.


hg outgoing은 단순하게 중앙 레포지토리에 반영되지 않은 로컬 레포지토리의 변경사항들의 리스트를 보여준다고 생각하면 됩니다.

자 이제 로즈는 그녀의 변경들을 중앙 레포지토리로 푸쉬합니다.


자 이제 세상은 이렇게 보일 겁니다.


자 이제 저에게로 넘어와서 몇잔의 커피를 마시고 드디어 포테이토칩에 대한 변경을 푸쉬할 때입니다.


아! 젠장! 실패입니다. 그런데 메시지를 보셨나요? 강제로 푸쉬하려면 -f 옵션을 쓰라구요? 이건 끔찍한 조언입니다. 절대로 절대로 ! -f 옵션으로 푸쉬하지 마세요. 강제로 푸쉬하는 순간 바로 후회하게 될 겁니다. 그냥 저를 믿으세요.

로즈의 푸쉬는 성공하고 제건 실패한 이유는 포테이토 칩이 구아카몰(guacamole)과 잘 어울리지 않기 때문일 겁니다. 아~ 이건 농담입니다. 저는 단지 당신이 아직 깨어있는지 확인하려고 한겁니다. ^^


푸쉬가 실패한 이유는 우리 둘다 변경을 했기 때문입니다. 그러므로 우리는 병합(merge)이 필요합니다. 그리고 Mercurial은 병합을 할 줄 압니다.

먼저 해야 할 것은 중앙 레포지토리에는 있는데 제 레포지토리에는 없는 변경들을 모두 받아내는 겁니다. 그래야 병합을 할 수 있습니다.


hg pull의 메시지에서 +1 heads 라는 엉뚱한 얘기를 볼 수 있습니다. 이건 3개의 변경 사항이 쌓여 있는 제 레포지토리가 이제 머리 두개인 괴물이 되었다는 의미입니다. 그래서 세상은 이제 머리를 두개를 가진 불안정한 형상이 되었습니다.


저는 두 가지 버전의 guac 파일을 가지고 있게 되었는데 제 버전을 보려면 아래와 같이 합니다.


그리고 로즈의 버전을 보려면 이렇게 합니다.


병합을 하는 것은 저에게 달렸습니다. 그리고 다행히 아주 쉽습니다.


보세요! hg merge 커맨드는 제 레포지토리에 있던 두개의 머리(heads)를 하나로 합쳐 버렸습니다. 이 경우 우리 둘은 파일의 다른 부분을 편집했기 때문에 어떤 충돌도 없이 자연스럽게 양쪽의 변경사항이 하나로 합쳐졌습니다.

아직 커밋 절차가 남았습니다. 커밋은 매우 중요합니다. 만일 병합이 실패하면 저는 복구(revert)하고 다시 병합을 시도할 수 있습니다. 하지만 병합이 성공했기 때문에 저는 커밋을 할 겁니다. 그리고 나서 중앙 레포지토리에 변경사항을 올릴 겁니다.


이제 제 레포지토리와 중앙 레포지토리는 같은 모양이 됩니다.


자 이제 저는 로즈의 변경 사항과 저의 변경 사항 모두를 가졌지만, 아직 로즈는 제 변경 사항을 갖지 못했습니다.

로즈가 새 변경사항을 가져오려면 hg pull을 해야 합니다.


이 싯점에서 약간 이상한 걸 보게 될 겁니다. hg pull로 중앙 레포지토리를 당겨 왔지만 여전히 그녀의 작업파일은 변경되기 전 상태입니다.


보시듯이 그녀는 여전히 또띠야 칩(Tortilla chips)으로 작업하고 있습니다. 또띠야 칩이요.

하지만 그녀는 그녀의 레포지토리에 모든 변경사항을 가지고 있습니다. hg log 를 쳐보면 확인할 수 있습니다.


하지만 이 변경사항들은 그녀의 작업 디렉토리에 반영되지 않은 상태입니다. 그녀는 여전히 체인지셋 #2로 작업하고 있습니다. 당신은 hg parent 커맨드를 통해 현재 작업 디렉토리의 체인지셋을 확인할 수 있습니다.


Mercurial은 우리에게 매우 친절합니다. pull을 통해 당겨온다고 해서 작업하는 파일에 당장 영향을 주는 것은 아니기 때문에 안전합니다. 우리는 다른 사람들이 만든 변경 사항들을 나중에 필요할 때 적용할 수 있습니다.

hg up(date) 커맨드를 인자없이 실행하면 가장 최신의 체인지셋 이름하여 tip 이라는 최상위 체인지셋이 작업 영역이 갱신됩니다. 이 경우는 체인지셋 #4 입니다.


자 이제 그녀는 모든 사람들의 변경 사항이 적용된 최신 버전을 받은 것입니다.

당신이 팀을 이루어 작업을 한다면 워크플로우는 다음과 같을 것입니다.
  1. 만일 당신이 해당 작업을 한지가 꽤 되었다면 먼저 다른 사람이 만든 최신 버전을 가져와야 합니다. 이것은 hg pull 과 hg up 커맨드로 가능합니다.
  2. 당신은 코드를 변경합니다.
  3. 로컬 레포지토리에 커밋합니다.
  4. 당신의 코드가 잘 돌아가고 다른 사람에게 악영향을 미치지 않을 것이라 확신할 때까지 2~3번 과정을 반복합니다.
  5. 다른 사람과 자신의 코드를 공유할 준비가 되었다면
    1. 일단 hg pull로 다른 사람의 변경사항을 모두 가져옵니다.
    2. hg merge 명령으로 당신의 변경 코드와 다른 사람의 변경 코드를 병합합니다.
    3. 병합된 결과가 잘 동작되는지 테스트합니다.
    4. 병합된 결과를 hg commit 합니다.
    5. hg push 로 중앙 레포지토리로 밀어 넣습니다.
스스로 해보세요

이 튜토리얼을 읽고 스스로 해 보세요.

1. 중앙 레포지토리를 설정하고 각 팀 멤버들이 이것을 복제(clone)해서 로컬 레포지토리로 옮기도록 하세요.
2. 중앙 레포지토리로 변경 사항을 푸쉬(push)하세요.
3. 중앙 레포지토리로 부터 변경사항을 가져(pull) 오세요.
4. 다른 사람들이 만든 코드들과 자신의 코드를 병합(merge)해 보세요.

댓글 없음:

댓글 쓰기