Introduction To Mercurial Phases (Part I)
원문: http://www.logilab.org/blogentry/88203
Logilab을 대표해 Mercurial 2.1에 상태(phases)라는 새 핵심 기능을 넣으려고 많은 노력을 기울였습니다. 상태는 체인지셋을 공유했는지 또는 공유해야 하는지 추적하는 시스템입니다. (예를 들어 확장 기능인 mq나 rebase로) 이력을 변경할 때 흔히 하는 실수를 막는데 도움이 되므로 분명히 모든 사용자에게 이익입니다. 여기서 설명하는 개념은 머큐리얼(Mercurial)에서 이력을 간단하면서도 안전하게 다시 쓰는 강력한 기법에 대한 첫 걸음입니다.
이 시리즈는 모두 3회로 나눠 게재하며 다음 내용을 설명합니다.
- 상태가 머큐리얼 사용자에게 어떻게 도움이 되는지
- 상태를 제어하는 방법
- 이전 버전 머큐리얼과 상태를 지원하는 새 버전을 함께 쓰는 방법
이력을 다시 쓸 때 많이 하는 실수 막기
DVCS에서 이력을 다시 쓰는 건 일반적입니다. 하지만 잘못된 방법으로 했을 때 얻는 결과인 중복 이력(duplicated history)은 가장 흔한 오류입니다. 상태는 이력을 더 안전하게 다시 쓰기 위한 개념입니다. 이를 위해 머큐리얼 2.1에서는 이력에서 (영원히 변하지 않을 것으로 기대하는) ‘과거’ 부분과 (현재 변경하고 있는) ‘현재’ 부분을 구별합니다. 즉 이력에서 오래되고 바뀌지 않는 부분을 공개(public), 바뀌는 부분을 초안(draft)이라고 합니다.
간단한 예를 통해 살펴 보겠습니다.
새 머큐리얼 사용자가 저장소를 복제합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
babar@Chessy ~ $ hg clone http://hg.celesteville.com/palace requesting all changes adding changesets adding manifests adding file changes added 2 changesets with 2 changes to 2 files updating to branch default 2 files updated, 0 files merged, 0 files removed, 0 files unresolved babar@Chessy ~/palace $ cd palace babar@Chessy ~/palace $ hg log --graph @ changeset: 1:2afbcfd2af83 | tag: tip | user: Celeste the Queen <Celeste@celesteville.com> | date: Wed Jan 25 16:41:56 2012 +0100 | summary: We need a kitchen too. | o changeset: 0:898889b143fb user: Celeste the Queen <Celeste@celesteville.com> date: Wed Jan 25 16:39:07 2012 +0100 summary: First description of the throne room |
저장소에는 이미 체인지셋이 몇 개 있으며 사용자는 내용을 고친 후 커밋합니다.
1 2 3 4 |
babar@Chessy ~/palace $ echo The wall shall be Blue >> throne-room babar@Chessy ~/palace $ hg ci -m 'Add wall color' babar@Chessy ~/palace $ echo In the middle stands a three meters round table >> kitchen babar@Chessy ~/palace $ hg ci -m 'Add a table in the kichen' |
하지만 새 체인지셋을 원격 저장소로 보내려 할 때 다른 개발자가 먼저 그 저장소로 보낸 것이 있다는 것을 알게 됩니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
babar@Chessy ~/palace $ hg push pushing to http://hg.celesteville.com/palace searching for changes abort: push creates new remote head bcd4d53319ec! (you should pull and merge or use push -f to force) babar@Chessy ~/palace $ hg pull pulling from http://hg.celesteville.com/palace searching for changes adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files (+1 heads) (run 'hg heads' to see heads, 'hg merge' to merge) babar@Chessy ~/palace $ hg log --graph o changeset: 4:0a5b3d7e4e5f | tag: tip | parent: 1:2afbcfd2af83 | user: Celeste the Queen <Celeste@celesteville.com> | date: Wed Jan 25 16:58:23 2012 +0100 | summary: Some bedroom description. | | @ changeset: 3:bcd4d53319ec | | user: Babar the King <babar@celesteville.com> | | date: Wed Jan 25 16:52:02 2012 +0100 | | summary: Add a table in the kichen | | | o changeset: 2:f9f14815935d |/ user: Babar the King <babar@celesteville.com> | date: Wed Jan 25 16:51:51 2012 +0100 | summary: Add wall color | o changeset: 1:2afbcfd2af83 | user: Celeste the Queen <Celeste@celesteville.com> | date: Wed Jan 25 16:41:56 2012 +0100 | summary: We need a kitchen too. | o changeset: 0:898889b143fb user: Celeste the Queen <Celeste@celesteville.com> date: Wed Jan 25 16:39:07 2012 +0100 summary: First description of the throne room |
참고: 지금부터는 있음직하지 않은 상황입니다. 머큐리얼에 익숙치 않은 사용자라도 이런 사소한 상황에 혼란스러워 하지 않을 정도로 머큐리얼은 매우 간단합니다. 하지만 상태에 초점을 맞추기 위해 예를 단순하게 합니다.
최근에 이 머큐리얼 초보자는 ‘재배치(rebase)’와 한 줄로 나열한 이력(linear history)의 이점에 대한 멋진 글을 읽었으므로 이력을 병합하지 않고 다시 쓰기로 맘 먹습니다. 재배치에 대한 멋진 도움말을 읽기도 했지만 이 초보자는 막상 사용할 때는 실수를 합니다. 즉 원격 체인지셋인 0a5b3d7e4e5f:”Some bedroom description.” 을 자신이 변경한 체인지셋 위에 재배치하기로 한 거죠. 이전 버전 머큐리얼에서는 이런 실수를 허용했기에 체인지셋 0a5b3d7e4e5f:”Some bedroom description.”이 중복으로 생기는 문제가 있었습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
babar@Chessy ~/palace $ hg rebase -s 4 -d 3 babar@Chessy ~/palace $ hg push pushing to http://hg.celesteville.com/palace searching for changes abort: push creates new remote head bcd4d53319ec! (you should pull and merge or use push -f to force) babar@Chessy ~/palace $ hg pull pulling from http://hg.celesteville.com/palace searching for changes adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files (+1 heads) (run 'hg heads' to see heads, 'hg merge' to merge) babar@Chessy ~/palace $ hg log --graph @ changeset: 5:55d9bae1e1cb | tag: tip | parent: 3:bcd4d53319ec | user: Celeste the Queen <Celeste@celesteville.com> | date: Wed Jan 25 16:58:23 2012 +0100 | summary: Some bedroom description. | | o changeset: 4:0a5b3d7e4e5f | | parent: 1:2afbcfd2af83 | | user: Celeste the Queen <Celeste@celesteville.com> | | date: Wed Jan 25 16:58:23 2012 +0100 | | summary: Some bedroom description. | | o | changeset: 3:bcd4d53319ec | | user: Babar the King <babar@celesteville.com> | | date: Wed Jan 25 16:52:02 2012 +0100 | | summary: Add a table in the kichen | | o | changeset: 2:f9f14815935d |/ user: Babar the King <babar@celesteville.com> | date: Wed Jan 25 16:51:51 2012 +0100 | summary: Add wall color | o changeset: 1:2afbcfd2af83 | user: Celeste the Queen <Celeste@celesteville.com> | date: Wed Jan 25 16:41:56 2012 +0100 | summary: We need a kitchen too. | o changeset: 0:898889b143fb user: Celeste the Queen <Celeste@celesteville.com> date: Wed Jan 25 16:39:07 2012 +0100 summary: First description of the throne room |
더 복잡한 조직에서 이는 매우 흔한 실수이며 심지어 크고 성공적인 프로젝트이거나 다른 DVCS를 쓰더라도 마찬가지입니다. 머큐리얼 새 버전에서는 사용자가 더 이상 이런 실수를 할 수 없습니다. 잘못된 방법으로 재배치를 하려 할 때 결과는 다음과 같습니다.
1 2 3 |
babar@Chessy ~/palace $ hg rebase -s 4 -d 3 abort: can't rebase immutable changeset 0a5b3d7e4e5f (see hg help phases for details) |
올바른 방법으로 재배치를 하면 잘 동작합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
babar@Chessy ~/palace $ hg rebase -s 2 -d 4 babar@Chessy ~/palace $ hg log --graph @ changeset: 4:139ead8a540f | tag: tip | user: Babar the King <babar@celesteville.com> | date: Wed Jan 25 16:52:02 2012 +0100 | summary: Add a table in the kichen | o changeset: 3:0d1feb1bca54 | user: Babar the King <babar@celesteville.com> | date: Wed Jan 25 16:51:51 2012 +0100 | summary: Add wall color | o changeset: 2:0a5b3d7e4e5f | user: Celeste the Queen <Celeste@celesteville.com> | date: Wed Jan 25 16:58:23 2012 +0100 | summary: Some bedroom description. | o changeset: 1:2afbcfd2af83 | user: Celeste the Queen <Celeste@celesteville.com> | date: Wed Jan 25 16:41:56 2012 +0100 | summary: We need a kitchen too. | o changeset: 0:898889b143fb user: Celeste the Queen <Celeste@celesteville.com> date: Wed Jan 25 16:39:07 2012 +0100 summary: First description of the throne room |
위 내용을 설명하면 다음과 같습니다.
- Celeste가 변경한 체인지셋 0a5b3d7e4e5f은 원격 저장소에서 가져온 것이므로 공개(public) 상태로 설정됐습니다. 공개 상태는 변경할 수 없습니다.
- (0d1feb1bca54, 139ead8a540f로 재배치한) 체인지셋 f9f14815935d와 bcd4d53319ec는 커밋 후 다른 저장소로 보내지 않았으므로 초안(draft) 상태입니다. 공개 상태와 달리 초안 상태는 변경할 수 있습니다.
전체 내용을 하나씩 자세히 살펴 보겠습니다. 상태에 주목하세요.
1 2 3 4 5 |
babar@Chessy ~ $ cat >> ~/.hgrc << EOF [ui] username=Babar the King <babar@celesteville.com> logtemplate='[{phase}] {desc} ({node|short})\\n' EOF |
첫째, 공개 서버에서 복제한 체인지셋은 공개입니다.
1 2 3 4 5 6 |
babar@Chessy ~ $ hg clone --quiet http://hg.celesteville.com/palace babar@Chessy ~/palace $ cd palace babar@Chessy ~/palace $ hg log --graph @ [public] We need a kitchen too. (2afbcfd2af83) | o [public] First description of the throne room (898889b143fb) |
둘째, 새로 커밋한 체인지셋은 초안 상태입니다.
1 2 3 4 5 6 7 8 9 10 11 12 |
babar@Chessy ~/palace $ echo The wall shall be Blue >> throne-room babar@Chessy ~/palace $ hg ci -m 'Add wall color' babar@Chessy ~/palace $ echo In the middle stand a three meters round table >> kitchen babar@Chessy ~/palace $ hg ci -m 'Add a table in the kichen' babar@Chessy ~/palace $ hg log --graph @ [draft] Add a table in the kichen (bcd4d53319ec) | o [draft] Add wall color (f9f14815935d) | o [public] We need a kitchen too. (2afbcfd2af83) | o [public] First description of the throne room (898889b143fb) |
셋째, 공개 서버에서 가져온 체인지셋은 공개입니다.
1 2 3 4 5 6 7 8 9 10 11 |
babar@Chessy ~/palace $ hg pull --quiet babar@Chessy ~/palace $ hg log --graph o [public] Some bedroom description. (0a5b3d7e4e5f) | | @ [draft] Add a table in the kichen (bcd4d53319ec) | | | o [draft] Add wall color (f9f14815935d) |/ o [public] We need a kitchen too. (2afbcfd2af83) | o [public] First description of the throne room (898889b143fb) |
참고: 재배치를 해도 상태는 그대로 유지합니다.
1234567891011 babar@Chessy ~/palace $ hg rebase -s 2 -d 4babar@Chessy ~/palace $ hg log --graph@ [draft] Add a table in the kichen (139ead8a540f)|o [draft] Add wall color (0d1feb1bca54)|o [public] Some bedroom description. (0a5b3d7e4e5f)|o [public] We need a kitchen too. (2afbcfd2af83)|o [public] First description of the throne room (898889b143fb)
마지막으로, 일단 공개 서버로 보내고 나면 체인지셋은 (변경할 수 없는) 공개 상태가 됩니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
babar@Chessy ~/palace $ hg push pushing to http://hg.celesteville.com/palace searching for changes adding changesets adding manifests adding file changes added 2 changesets with 2 changes to 2 files babar@Chessy ~/palace $ hg log --graph @ [public] Add a table in the kichen (139ead8a540f) | o [public] Add wall color (0d1feb1bca54) | o [public] Some bedroom description. (0a5b3d7e4e5f) | o [public] We need a kitchen too. (2afbcfd2af83) | o [public] First description of the throne room (898889b143fb) |
요약하면 다음과 같습니다.
- 다른 저장소와 교환한 체인지셋은 공개 상태이며 변경할 수 없습니다.
- 커밋한 체인지셋은 다른 저장소로 보내기 전까지 초안 상태입니다.
- 사용자 입장에서는 상태를 걱정할 필요가 없습니다. 상태는 인식하지 못하는 사이에 자연스럽게 이동합니다.
완전하지 않은 이력을 교환하지 못하도록 하기
공개 상태에서는 사용자가 의도하지 않게 공개 이력을 다시 쓰는 경우를 막아 줍니다. 이것으로도 좋지만 상태를 사용하면 한 발짝 더 나아갈 수 있습니다. 상태를 사용하면 처음부터 의도치 않게 이력을 공개하는 것을 막을 수 있습니다. 이를 위한 세 번째 상태가 있는데 바로 비공개(secret) 상태입니다. 이 비공개 상태와 멋지게 통합되어 있는 mq 확장 기능을 사용해 설명하겠습니다.
mq 확장 기능을 활성화합니다.
1 2 3 4 5 6 7 8 9 10 11 |
babar@Chessy ~/palace $ vim ~/.hgrc babar@Chessy ~/palace $ cat ~/.hgrc [ui] username=Babar the King <babar@celesteville.com> [extensions] # enable the mq extension included with Mercurial hgext.mq= [mq] # Enable secret phase integration. # This integration is off by default for backward compatibility. secret=true |
(일반적인 커밋이 아니라) 새 패치를 비공개로 만듭니다.
1 2 3 4 5 6 7 8 9 10 11 |
babar@Chessy ~/palace $ echo A red carpet on the floor. >> throne-room babar@Chessy ~/palace $ hg qnew -m 'add a carpet' carpet.diff babar@Chessy ~/palace $ hg log --graph @ [secret] add a carpet (3c1b19d5d3f5) | @ [public] Add a table in the kichen (139ead8a540f) | o [public] Add wall color (0d1feb1bca54) | … |
이 비공개 체인지셋은 outgoing
과 push
명령을 사용할 때 포함하지 않습니다.
1 2 3 4 5 6 7 8 |
babar@Chessy ~/palace $ hg outgoing comparing with http://hg.celesteville.com/palace searching for changes no changes found (ignored 1 secret changesets) babar@Chessy ~/palace $ hg push pushing to http://hg.celesteville.com/palace searching for changes no changes found (ignored 1 secret changesets) |
게다가 다른 사용자가 볼 수도 없습니다.
1 2 3 4 5 |
celeste@Chessy ~/palace $ hg incoming ~babar/palace/ comparing with ~babar/palace searching for changes [public] Add wall color (0d1feb1bca54) [public] Add a table in the kichen (139ead8a540f) |
상태 이동은 mq 확장 기능에서 처리하며 qfinish
를 하면 체인지셋은 초안 상태가 됩니다.
1 2 3 4 5 6 7 8 9 |
babar@Chessy ~/palace $ hg qfinish . babar@Chessy ~/palace $ hg log --graph @ [draft] add a carpet (2afbcfd2af83) | o [public] Add a table in the kichen (139ead8a540f) | o [public] Add wall color (0d1feb1bca54) | … |
그리고 qimport
를 하면 체인지셋은 다시 비공개가 됩니다.
1 2 3 4 5 6 7 8 9 |
babar@Chessy ~/palace $ hg qimport -r 2afbcfd2af83 babar@Chessy ~/palace $ hg log --graph @ [secret] add a carpet (2afbcfd2af83) | o [public] Add a table in the kichen (139ead8a540f) | o [public] Add wall color (0d1feb1bca54) | … |
당연히 공개 체인지셋에 qimport
를 사용할 수 없습니다.
1 2 |
babar@Chessy ~/palace $ hg qimport -r 139ead8a540f abort: revision 4 is not mutable |
다음 글에서는 상태 이동을 제어하는 방법에 대해 자세히 설명합니다.