Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 개선 제안 한국어 번역

PEP 385 – Subversion에서 Mercurial로 이전하기

Author:
Dirkjan Ochtman <dirkjan at ochtman.nl>, Antoine Pitrou <solipsis at pitrou.net>, Georg Brandl <georg at python.org>
Status:
Final
Type:
Process
Created:
25-May-2009

Table of Contents

번역·라이선스 안내

이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판

동기

Mercurial DVCS로 전환하기로 결정한 뒤에도 실제 이전 작업은 여전히 수행해야 합니다. Python처럼 규모가 크고 분산된 프로젝트의 버전 관리 시스템과 같은 중요한 인프라의 경우, 이는 상당한 노력이 드는 작업입니다. 이 PEP는 향후 논의를 위해 거쳐야 할 단계들을 기술하려는 시도입니다. 이 문서는 SVN으로의 이전을 논의했던 PEP 347과 다소 비슷합니다.

hg를 최대한 활용하기 위해, (a) svn 메타데이터를 가능한 한 많이 보존하고 (b) 모든 메타데이터를 Mercurial에서 일반적으로 쓰이는 형식으로 변환하는, 충실도 높은 변환을 하고자 합니다. 이렇게 하면 Mercurial용으로 작성된 도구들을 최적으로 사용할 수 있습니다. 이를 위해 초기 변환에는 hgsubversion 소프트웨어를 사용하고자 합니다. 이 hg 확장은 양방향 대응에 사용할 수 있도록 Subversion에서 Mercurial로의 고품질 변환을 제공하는 데 중점을 두고 있으며, 이는 다른 솔루션들처럼 사용 가능한 메타데이터를 많이 버리지 않는다는 뜻입니다.

이러한 변환은 저장소의 내용을 재검토하고 일부 항목이 여전히 가치가 있는지 판단하기에도 좋은 시기로 보입니다. 이러한 취지에서, 이어지는 절들에서는 오래된 메타데이터 일부를 폐기하는 것도 제안합니다.

타임라인

변환 마일스톤의 현재 일정은 다음과 같습니다:

  • 2011-02-24: hg.python.org에서 테스트 저장소 제공

    Subversion 저장소의 모든 커미터에게 테스트 커밋이 허용됩니다(그리고 권장됩니다). 테스트 저장소와 모든 테스트 커밋은 최종 변환이 완료되면 제거됩니다. buildbot, diff-email 및 공백 검사 통합을 테스트하기 위해 테스트 저장소에 서버 측 훅이 설치됩니다.

  • 2011-03-05: 최종 변환(잠정)

    이제 Mercurial에서 관리되는 Subversion 브랜치에 대한 커밋은 차단됩니다. 개발자들은 새 저장소로 전환한 뒤 모든 인프라가 제대로 작동하는 것이 확인될 때까지 Mercurial 저장소에 푸시하지 말아야 합니다.

전환 계획

브랜치 전략

Mercurial에서 브랜치를 사용하는 기본 방식은 두 가지입니다. 하나는 각 브랜치를 별도의 저장소에 보관하는 복제 브랜치(cloned branch)이고, 다른 하나는 각 리비전이 자신이 속한 브랜치를 기록하는 메타데이터를 유지하는 이름 있는 브랜치(named branch)입니다. 전자는 브랜치를 구별하기 더 쉽게 해 주지만, 그 대가로 클라이언트에 더 많은 디스크 공간이 필요합니다. 후자는 브랜치 간 전환을 조금 더 쉽게 해 주지만, 모든 브랜치 이름이 히스토리에 영구적으로 남습니다. [1]

이름 있는 브랜치와 복제 브랜치의 차이점은 다음과 같습니다:

  • 다른 (유지 보수) 클론의 태그는 로컬 클론에서 사용할 수 없습니다
  • 이름 있는 브랜치를 사용하는 클론은 더 많은 데이터를 담고 있으므로 크기가 더 큽니다

릴리스 브랜치에는 이름 있는 브랜치를 사용하고, 기능 브랜치에는 복제 브랜치를 채택할 것을 제안합니다.

히스토리 관리

변환으로 인한 정보 손실을 최소화하기 위해, 변환 결과로 여러 저장소를 제공할 것을 제안합니다:

  • 메인라인 트렁크(및 py3k)와 과거 및 현재의 유지보수 브랜치만 남기도록 정리한 저장소 – 이를 “작업(working)” 저장소라고 부르며, 개발이 계속 이루어지는 곳입니다. 이 저장소에는 개발 작업에 필요한 모든 이력이 들어 있습니다. 여기에는 1990년까지 거슬러 올라가는 변경 사항으로 소스 파일에 주석을 다는 작업(annotate)과 그 밖의 일반적인 이력 탐색 작업도 포함됩니다.

    이 저장소의 default 브랜치는 Subversion에서 py3k로 알려진 브랜치이며, Subversion 트렁크는 legacy-trunk라는 브랜치 이름으로 유지됩니다. 다만 Mercurial에서 이 브랜치는 닫힐 것입니다. 릴리스 브랜치의 이름은 3.2처럼 major.minor 버전을 따릅니다.

  • Subversion 저장소(실제로는 그 /python 하위 디렉터리)를 편집 없이 전체 변환한 저장소 – 이를 “역사(historic)” 또는 “보관(archive)” 저장소라고 부르며, 읽기 전용 자원으로 제공될 것입니다. [2]
  • 활성 기능 브랜치마다 저장소를 하나씩 추가로 둡니다. 여기서 “활성”이란 적어도 한 명의 코어 개발자가 해당 브랜치의 제공을 요청했다는 뜻입니다. 이러한 각 저장소에는 기능 브랜치와 함께 메인라인의 모든 조상 체인지셋(SVN의 trunk 및/또는 py3k에서 온 것)이 포함됩니다.

모든 브랜치가 역사 저장소에 존재하므로, 필요하다고 판명되면 나중에 언제든지 별도의 저장소로 추출할 수 있습니다.

SVN 리비전 번호, Mercurial 체인지셋, SVN 브랜치 이름 간의 최종 리비전 맵은 Misc 디렉터리에 저장된 파일로 제공될 것입니다. 그 형식은 다음과 같습니다:

[...]
88483 e65daae6cf4499a0863cb7645109a4798c28d83e issue10276-snowleopard
88484 835cb57abffeceaff0d85c2a3aa0625458dd3e31 py3k
88485 d880f9d8492f597a030772c7485a34aadb6c4ece release32-maint
88486 0c431b8c22f5dbeb591414c154acb7890c1809df py3k
88487 82cda1f21396bbd10db8083ea20146d296cb630b release32-maint
88488 8174d00d07972d6f109ed57efca8273a4d59302c release27-maint
[...]

태그 변환

SVN tags 디렉터리에는 오래된 것이 많이 들어 있습니다. 이 중 일부는 사실 완전한 태그가 아니며, 저장소의 더 작은 일부분만 담고 있습니다. 모든 릴리스 태그는 유지됩니다. 그 밖의 태그는 개발자 커뮤니티의 요청에 따라 포함될 것입니다. 태그 명명 방식을 v3.2.1a2와 같은 형식으로 일관되게 만들 것을 제안합니다.

작성자 맵

hg에서 일반적으로 쓰이는 방식(‘First Last <user@example.org>’ 형식)으로 사용자 이름을 제공하려면, cvs와 svn 사용자 이름을 실제 이름과 이메일 주소에 대응시키는 작성자 맵이 필요합니다. 마이그레이션 도구 저장소에 이러한 맵의 완전한 버전이 있습니다(주소 수집기에 주소가 유출되는 것을 막기 위해 공개적으로 접근할 수는 없습니다). 그 안의 이메일 주소는 오래되었을 수 있습니다. 이는 어쩔 수 없는 일이지만, 가능한 한 많은 사람이 이를 검토하여 오래된 주소를 찾아 준다면 좋을 것입니다. 현재 버전에는 아직 인코딩 문제도 일부 남아 있는 것으로 보입니다.

.hgignore 생성

.hgignore 파일은 Mercurial 저장소에서 버전 관리 대상이 아닌 파일을 무시하는 데 사용할 수 있습니다. 이는 여러 가지 형태의 패턴 매칭을 사용하여 이루어집니다. 현재 Python 저장소에는 hg 미러 사용을 돕기 위한 기초적인 .hgignore 파일이 이미 포함되어 있습니다.

현재 Python 저장소에는 이미 (hg 미러용) .hgignore 파일이 포함되어 있으므로, 그것을 그대로 사용할 것입니다. 이 파일의 전체 이력을 생성하는 방안도 논의되었지만 비현실적이라고 판단되었습니다(오래된 리비전에서는 무시 기능이 덜 중요하므로, 비교적 어려운 데 비해 얻는 이득이 상당히 적기 때문입니다).

저장소 크기

현재 Python 저장소를 그대로 변환한 결과는 1.9 GB입니다. 이는 Subversion 저장소(2.7 GB)보다 작지만, 실용적이지 않습니다.

작업 저장소에 적용한 정리 작업과, Mercurial 내부 저장소의 배치를 매우 효율적으로 최적화하는 “revlog 재정렬(revlog reordering)”이라는 과정을 통해 크기를 더 다루기 쉬운 수준으로 줄일 수 있습니다.

모든 최적화를 마친 후 작업 저장소의 크기는 디스크상에서 약 180 MB입니다. 클론할 때 네트워크를 통해 전송되는 데이터의 양은 약 80 MB로 추정됩니다.

기타 저장소

svn.python.org의 “projects” 저장소에는 그 밖에도 여러 프로젝트가 호스팅되어 있습니다. “peps” 디렉터리는 메인 Python 저장소와 함께 변환될 것입니다. Richard Tew는 Stackless 저장소도 변환되기를 바란다는 뜻을 밝혔습니다. svn.python.org 저장소의 다른 어떤 프로젝트를 변환해야 합니까?

현재 Jython 저장소 변환을 처음으로 시도해 본 상태입니다. 안타깝게도 hgsubversion의 현재 tip은 어느 지점에서 실패합니다. 조사가 필요한 상태입니다.

Mercurial로 변환되기를 원하는 다른 저장소는 메인 Python 이전이 완료된 후 저에게 알려 주시면, 필요한 사항을 처리해 드리겠습니다.

인프라

hg-ssh

개발자는 현재 구성과 마찬가지로 ssh를 통해 저장소에 접근해야 합니다. 공개 키를 사용하여 사람들에게 공유 hg@ 계정에 대한 접근 권한을 부여할 수 있습니다. 손쉬운 탐색과 읽기 전용 접근을 위해 hg.python.org에 hgwebdir 인스턴스도 설정되어 있습니다. 이 인스턴스는 개발자가 (별도의 저장소에서 개발하는 것이 유리한 장기적인 기능을 위해) 새 클론을 손쉽게 시작할 수 있도록 구성되어 있습니다.

또한 코어 개발자는 공개 저장소를 직접 만들 수 있습니다. 다만 어떤 이름 규칙을 강제할지는 아직 정해지지 않았습니다.:

$ hg init ssh://hg@hg.python.org/sandbox/mywork
repo created, public URL is http://hg.python.org/sandbox/mywork

훅

현재 여러 훅이 사용되고 있습니다. 이 훅들에 상응하는 hg용 훅을 개발하고 배포해야 합니다. 다음과 같은 훅이 사용되고 있습니다:

  • check whitespace: 공백이 Python 코드베이스의 규칙에 맞지 않는 경우 커밋을 거부하는 훅입니다. changegroup에서는 tip만 검사합니다(이를 통해 서드파티 저장소에서 가져온 변경 사항에 대한 정리 커밋이 허용됩니다). 또한 사람들이 클라이언트 측 저장소에서 사용할 수 있는 공백 훅을 제공할 수도 있습니다. 이 훅은 공백 문제에 대해 경고하거나, 변경된 줄의 후행 공백을 잘라내거나, 둘 다 수행할 수 있습니다.
  • push mails: 이메일에는 공개 저장소에 푸시된 각 changeset의 diff가 포함되며, changeset을 푸시한 사용자 이름도 포함됩니다(이는 changeset에 기록된 작성자와 반드시 같지는 않습니다).
  • buildbots: python.org 빌드 마스터는 cpython 저장소에 푸시된 각 changeset을 통지받고, 해당 changeset이 발생한 브랜치에 대해 모든 빌드 슬레이브에서 적절한 빌드를 실행합니다.

hooks repository에는 이러한 서버 측 훅을 Mercurial로 포팅한 것과 함께 몇 가지 추가 훅이 들어 있습니다:

  • check branch heads: 기존 브랜치에 새 head를 생성하는 푸시를 거부하는 훅입니다. 그러면 푸시한 사람은 초과된 head들을 병합한 후 다시 푸시를 시도해야 합니다.
  • check branches: 허용된 이름 있는 브랜치에 속하지 않는 모든 changeset을 거부하는 훅입니다. 새 유지 보수 브랜치를 만들고자 할 때는 이 훅의 화이트리스트를 갱신해야 합니다.
  • check line endings: eol extension을 기반으로, 잘못된 줄 끝 문자를 가진 파일을 커밋하는 모든 changeset을 거부하는 훅입니다. 그러면 해당 커밋을 제거(strip)하고 다시 수행해야 하며, 경우에 따라 커미터의 컴퓨터에서 eol extension을 활성화한 상태로 수행할 수 있습니다.

추가로 한 가지 훅이 유용할 수 있습니다:

  • 기여자 확인: 현재 설정에서는 모든 체인지셋에 커미터의 사용자 이름이 기록되며, 커미터는 기여자 동의서에 서명한 사람이어야 합니다. 등록된 기여자 목록을 유지한다면, 훅을 사용하여 커미터가 기여자인지 확인할 수도 있습니다. 그러면 훅은 알 수 없는 기여자의 체인지셋이 포함된 리비전 묶음을 푸시하는 사용자에게 경고할 수 있습니다.

줄 끝 변환

Mercurial에 줄 끝 변환 지원이 없다는 점(처음에는 win32text extension이 이를 제공했습니다)에 관한 논의를 계기로, Subversion의 svn:eol-style 속성과 유사하게 파일 단위로 줄 끝 규칙을 버전 관리할 수 있는 새로운 eol extension이 개발되었습니다. 이 정보는 .hgeol이라는 버전 관리되는 파일에 보관되며, 이러한 파일이 이미 Subversion 저장소에 체크인되어 있습니다.

일관되지 않은 줄바꿈 데이터를 들여오는 체인지셋을 거부하는 훅도 서버 측에 있습니다(위 내용 참고).

hgwebdir

거의 기본 상태 그대로의 hgwebdir을 설치해야 합니다. Python 웹사이트에 어울리는 스타일을 마련할 수도 있습니다.

Subversion 리비전을 조회하여 해당 체인지셋에 맞는 hgweb 페이지로 리디렉션하는 작은 WSGI 애플리케이션이 작성되었으며, 이 애플리케이션은 변환된 리비전이 어느 저장소에 들어갔는지와 관계없이 동작합니다(하나의 큰 Subversion 저장소가 여러 개의 Mercurial 저장소로 변환되기 때문입니다). 이 애플리케이션은 16진수 ID로 Mercurial 체인지셋을 조회할 수도 있습니다.

roundup

Roundup이 위에서 언급한 조회 스크립트의 URL을 가리키도록 하면 SVN 리비전에 대한 링크가 계속 작동하며, 저장소와 체인지셋 ID를 모두 지정하지 않고도 Mercurial 체인지셋에 대한 링크를 만들 수 있습니다.

이전 후

코드를 받을 수 있는 곳

이전 후에는 hgwebdir이 hg.python.org에 위치하게 됩니다. 이는 많은 조직에서 받아들여진 표준이며, svn.python.org와도 쉽게 대응됩니다. 예를 들어 작업 저장소는 http://hg.python.org/cpython/ 에, 아카이브 저장소는 http://hg.python.org/cpython-archive/ 에 둘 수 있습니다. 쓰기 권한이 필요한 개발자는 ssh를 사용해야 하며, 주소는 ssh://hg@hg.python.org/cpython/ 형태가 될 수 있습니다.

호스트 이름으로 code.python.org도 제안되었습니다. 호스트 이름에 VCS 이름을 사용하면 혼동을 막을 수 있으므로 좋다고 생각합니다. hg.python.org에서는 svn이나 bzr을 사용할 수 없다는 점이 분명해야 합니다.

hgwebdir은 이미 모든 체인지셋에 대해 tarball을 제공할 수 있습니다. 따라서 일일 스냅숏이 필요 없어집니다. 대신 사용자에게 tip.tar.gz를 안내하기만 하면 되며, 그러면 사용자는 최신 버전을 받게 됩니다. 원한다면 buildbot 결과를 활용하여 마지막으로 정상 동작한 체인지셋을 가리키게 할 수도 있습니다.

Python 전용 문서

hg에는 훌륭한 내장 문서(hg help로 볼 수 있음)와 유용한 정보 및 레시피로 가득한 wiki가 있으며, 인기 있는 book(온라인으로 읽을 수 있음)도 있습니다.

이에 더해, 최근 전면 개편된 Python Developer’s Guide에는 이미 Subversion 대신 Mercurial 사용법을 담은 브랜치가 있으며, 온라인 build of this branch도 제공됩니다.

제안하는 워크플로

여러 브랜치 사이에서 패치를 옮기기 위한 두 가지 워크플로를 제안합니다.

2.x 또는 3.x 브랜치 내에서의 마이그레이션에 대해서는, 패치를 항상 그 패치가 적용되는 가장 오래된 브랜치에 먼저 커밋할 것을 제안합니다. 그런 다음, 그 결과로 생성된 체인지셋을 hg merge를 사용하여 해당 시리즈(2.x 또는 3.x) 내의 더 새로운 모든 브랜치로 병합할 수 있습니다. 더 새로운 브랜치에 그대로 적용되지 않는 경우에는 hg revert를 사용하여 새 브랜치 고유의 헤드로 쉽게 되돌리고, 패치의 다른 버전을 적용한 다음(적용할 수 없는 경우라면 아무것도 적용하지 않고), 병합을 커밋할 수 있습니다. 여기서의 전제는 시리즈 내 더 오래된 브랜치의 모든 체인지셋이 결국 그 시리즈 내의 더 새로운 모든 브랜치로 병합된다는 것입니다.

결론적으로, 이 방식은 가장 수월한 병합 절차를 제공합니다. 이는 일반적인 경우, 패치를 실제로 적용하기 전에 그 패치를 적용해야 할 가장 오래된 브랜치가 무엇인지 먼저 생각해야 한다는 뜻입니다. 보안 수정 전용 모드에 있는 더 오래된 브랜치에 적용되는 보안 수정을 제외하면, 그 브랜치는 대개 최신 유지보수 브랜치와 트렁크, 이 두 브랜치 중 하나입니다.

3.x에서 2.7 유지보수 브랜치로 버그 수정을 병합할 때는(2.6과 2.5는 보안 수정 전용 모드에 있으며 이들의 유지보수는 Subversion 저장소에서 계속됩니다), 체인지셋을 병합하지 말고 다른 방법으로 이식(transplant)해야 합니다. 이 경우에는 transplant 확장, import/export, bundle/unbundle이 모두 똑같이 잘 동작합니다.

이 방식을 택하면 3.x가 분기된 이후의 2.x 이력 전체를 떠안지 않아도 되므로, 클론의 크기가 그리 크지 않고 병합도 그리 복잡하지 않습니다.

Subversion의 미래

마이그레이션 후 Subversion 저장소는 어떻게 됩니까? svn 서버에는 CPython 저장소뿐만 아니라 여러 저장소가 있으며, 모든 프로젝트가 마이그레이션을 원하지는 않을 수 있고 다른 프로젝트들의 마이그레이션에 시간이 더 걸릴 수도 있으므로, svn 서버는 아마 한동안 계속 유지될 것입니다. 사람들이 뒤처지지 않도록, 마이그레이션을 마친 프로젝트는 기존 저장소에서 새 이름을 가진 새로운 읽기 전용 저장소로 옮기는 것이 좋을 수 있습니다.

빌드 식별

현재 Python은 Python 코드가 자신이 실행되고 있는 Python의 정확한 버전을 알아낼 수 있도록 sys.subversion 튜플을 제공합니다. 현재 버전은 대략 다음과 같습니다:

  • (‘CPython’, ‘tags/r262’, ‘71600’)
  • (‘CPython’, ‘trunk’, ‘73128M’)

또 다른 값은 C API의 Py_GetBuildInfo()에서 반환되며, Python 코드에서는 sys.version의 일부로 사용할 수 있습니다:

  • ‘r262:71600, Jun 2 2009, 09:58:33’
  • ‘trunk:73128M, Jun 2 2009, 01:24:14’

리비전 식별자는 hg 리비전 해시의 짧은 버전(예: ‘dd3ebf81af43’)으로 하고, 빌드에 사용된 작업 디렉터리가 수정된 경우에는 (‘M’ 대신) ‘+’를 덧붙일 것을 제안합니다. 이는 바로 이러한 용도를 위해 만들어진 hg id 명령의 출력과 같은 형식입니다. VCS 변경을 반영하기 위해 sys.subversion 값의 이름도 sys.mercurial로 바뀝니다.

태그/브랜치 식별자에 대해서는, hg가 현재 체크아웃된 리비전에 태그가 있는지 확인하여 태그가 있으면(‘tip’은 제외합니다) 그 태그를 사용하고, 없으면 브랜치 이름을 사용할 것을 제안합니다. sys.subversion은 다음과 같이 됩니다

  • (‘CPython’, ‘v2.6.2’, ‘dd3ebf81af43’)
  • (‘CPython’, ‘default’, ‘af694c6a888c+’)

그리고 빌드 정보 문자열은 다음과 같이 됩니다

  • ‘v2.6.2:dd3ebf81af43, Jun 2 2009, 09:58:33’
  • ‘default:af694c6a888c+, Jun 2 2009, 01:24:14’

이는 hg의 기본 브랜치 이름이 Subversion의 ‘trunk’가 아니라 ‘default’라는 점과 새로 제안된 태그 형식을 반영한 것입니다.

Mercurial은 최신 태그와, 현재 체인지셋이 그 태그로부터 몇 개의 체인지셋만큼 떨어져 있는지도 알아낼 수 있게 해 주므로, 설명적인 버전 문자열을 만들 수 있습니다:

$ hg parent --template "{latesttag}+{latesttagdistance}-{node|short}\n"
v3.2+37-4b5d0d260e72
$ hg up 2.7
3316 files updated, 0 files merged, 379 files removed, 0 files unresolved
$ hg parent --template "{latesttag}+{latesttagdistance}-{node|short}\n"
v2.7.1+216-9619d21d8198

각주