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에서 브랜치를 사용하는 기본적인 방법은 두 가지입니다. 각 브랜치를 별도의 저장소에 보관하는 복제된 브랜치와, 각 리비전에 해당 리비전이 속한 브랜치를 기록하는 메타데이터를 보관하는 이름이 지정된 브랜치입니다. 전자는 클라이언트에 더 많은 디스크 공간이 필요하다는 대가로 브랜치를 더 쉽게 구분할 수 있게 합니다. 후자는 브랜치 간 전환을 조금 더 쉽게 해 주지만, 모든 브랜치 이름이 기록에 영구적으로 포함됩니다. [1]

이름이 지정된 브랜치와 복제된 브랜치의 차이점은 다음과 같습니다.

  • 다른 (유지 관리용) 복제본의 태그는 로컬 복제본에서 사용할 수 없습니다.
  • 이름이 지정된 브랜치가 있는 복제본은 더 많은 데이터를 포함하므로 크기가 더 커집니다.

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

기록 관리

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

  • 메인라인 트렁크(및 py3k)와 과거 및 현재 유지보수 브랜치로 축소된 저장소를 “working” 저장소라고 하며, 여기서 개발이 계속됩니다. 이 저장소에는 개발 작업에 필요한 모든 이력이 있으며, 1990년까지 거슬러 올라가 변경 사항으로 소스 파일에 주석을 다는 작업과 그 밖의 일반적인 이력 조사 작업도 포함됩니다.

    해당 저장소의 default 브랜치는 Subversion에서 py3k로 알려진 브랜치인 반면, Subversion 트렁크는 legacy-trunk라는 브랜치 이름으로 계속 유지됩니다. 그러나 Mercurial에서는 이 브랜치가 닫힙니다. 릴리스 브랜치는 major.minor 버전에 따라 이름을 정하며, 예를 들어 3.2와 같습니다.

  • Subversion 저장소(정확히는 해당 저장소의 /python 하위 디렉터리)를 수정 없이 완전히 변환한 저장소를 “historic” 또는 “archive” 저장소라고 하며, 읽기 전용 리소스로 제공할 예정입니다. [2]
  • 활성 기능 브랜치마다 저장소를 하나씩 추가하며, 여기서 “활성”이란 최소 한 명의 핵심 개발자가 해당 브랜치를 제공해 달라고 요청했다는 의미입니다. 이러한 각 저장소에는 기능 브랜치와 메인라인에서 나온 모든 선조 변경 집합(SVN의 trunk 및/또는 py3k에서 비롯됨)이 모두 포함됩니다.

모든 브랜치가 historic 저장소에 있으므로, 필요하다고 판단될 경우 나중에 언제든 별도의 저장소로 추출할 수 있습니다.

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 태그 디렉터리에는 오래된 항목이 많이 들어 있습니다. 이 중 일부는 실제로 완전한 태그가 아니라 저장소의 더 작은 하위 집합만 포함합니다. 모든 릴리스 태그는 유지하고, 그 밖의 태그는 개발자 커뮤니티의 요청에 따라 포함합니다. 태그 명명 체계를 일관되게 만들 것을 제안하며, 형식은 다음과 같습니다: v3.2.1a2.

작성자 매핑

hg에서 일반적으로 사용하는 방식(‘First Last <user@example.org>’ 형식)으로 사용자 이름을 제공하려면, cvs 및 svn 사용자 이름을 실제 이름과 이메일 주소에 매핑하는 작성자 매핑이 필요합니다. 마이그레이션 도구 저장소에 이러한 매핑의 완전한 버전이 있습니다(주소 수집 봇에 주소가 유출되는 것을 방지하기 위해 공개적으로 접근할 수 없습니다). 여기에 있는 이메일 주소는 최신이 아닐 수 있으며, 이는 피할 수 없는 일입니다. 다만 가능한 한 많은 사람이 최신이 아닌 주소를 검토해 주면 좋겠습니다. 현재 버전에도 여전히 일부 인코딩 문제가 있는 것으로 보입니다.

생성: .hgignore

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

현재 Python 저장소에는 이미 .hgignore 파일이 포함되어 있으므로(hg 미러에서 사용하기 위한 것임), 이를 그대로 사용합니다. 파일의 전체 이력을 생성하는 방안도 논의되었지만 비실용적인 것으로 판단되었습니다(비교적 어렵고 얻는 이점은 매우 적으며, 이전 리비전에서는 무시 처리가 덜 중요하기 때문입니다).

저장소 크기

현재 Python 저장소를 아무런 축소 없이 변환한 결과의 크기는 1.9 GB입니다. Subversion 저장소(2.7 GB)보다 작기는 하지만 실용적이지 않습니다.

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

모든 최적화를 수행한 후 working 저장소의 디스크상 크기는 약 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용 구현을 개발하고 배포해야 합니다. 다음 훅이 사용되고 있습니다:

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

hooks repository는 이러한 서버 측 훅을 Mercurial로 포팅한 것과 몇 가지 추가 훅을 포함합니다.

  • 브랜치 헤드 검사: 기존 브랜치에 새 헤드를 생성하는 푸시를 거부하는 훅입니다. 그러면 푸시한 사용자는 초과 헤드를 병합한 후 다시 푸시해야 합니다.
  • 브랜치 검사: 허용된 명명 브랜치에 속하지 않는 모든 변경 집합을 거부하는 훅입니다. 새 유지 보수 브랜치를 생성하려면 이 훅의 허용 목록을 업데이트해야 합니다.
  • 줄 끝 검사: eol extension에 기반하여 잘못된 줄 끝이 있는 파일을 커밋하는 모든 변경 집합을 거부하는 훅입니다. 그러면 커미터의 컴퓨터에서 eol extension을 활성화했을 수도 있는 상태로 해당 커밋을 제거하고 다시 수행해야 합니다.

추가 훅 하나가 유용할 수 있습니다:

  • 기여자 확인: 현재 설정에서는 모든 변경 집합에 커밋 작성자의 사용자 이름이 포함되며, 커밋 작성자는 기여자 계약서에 서명해야 합니다. 등록된 기여자 목록을 유지한다면, 커밋 작성자가 기여자인지 확인하는 훅을 사용해야 할 수도 있습니다. 그러면 해당 훅이 알려지지 않은 기여자의 변경 집합을 포함하는 일련의 리비전을 푸시하는 사용자에게 경고할 수 있습니다.

줄 끝 변환

처음에는 win32text extension로 제공되었던 Mercurial의 줄 끝 변환 지원 부족에 관한 논의로 인해, Subversion의 svn:eol-style 속성과 유사하게 파일별로 줄 끝 규칙을 버전 관리하는 새로운 eol extension이 개발되었습니다. 이 정보는 .hgeol이라는 버전 관리 파일에 보관되며, 이러한 파일은 이미 Subversion 저장소에 체크인되어 있습니다.

일관되지 않은 개행 데이터를 도입하는 모든 변경 집합을 거부하는 훅도 서버 측에 존재합니다(위 참조).

hgwebdir

대체로 기본 설정에 가까운 hgwebdir 설치를 설정해야 합니다. Python 웹사이트와 어울리는 스타일을 고안해야 할 수도 있습니다.

변환된 리비전이 어느 저장소에 들어갔는지와 관계없이 Subversion 리비전을 조회하고 주어진 변경 집합에 적합한 hgweb 페이지로 리디렉션할 수 있는 작은 WSGI 애플리케이션이 작성되었습니다(하나의 큰 Subversion 저장소가 여러 Mercurial 저장소로 변환되기 때문입니다). 또한 16진수 ID로 Mercurial 변경 집합을 조회할 수 있습니다.

roundup

위에서 언급한 조회 스크립트의 URL을 Roundup에 지정하면 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 익스텐션, import/export, bundle/unbundle이 여기서 동일하게 잘 작동합니다.

이 접근 방식을 선택하면 3.x가 분기된 이후의 2.x 이력을 전부 지니지 않아도 되므로, 클론이 그다지 크지 않고 머지도 그다지 복잡하지 않게 됩니다.

Subversion의 미래

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

빌드 식별

Python은 현재 Python 코드가 자신이 실행 중인 Python의 정확한 버전을 알아낼 수 있도록 sys.subversion 튜플을 제공합니다. 현재 버전은 다음과 같은 형태를 띱니다:

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

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

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

저는 리비전 식별자가 hg 리비전 해시의 짧은 버전(예: ‘dd3ebf81af43’)이 되도록 하고, 빌드된 작업 디렉터리가 수정되었을 경우 (‘M’ 대신) ‘+’를 덧붙일 것을 제안합니다. 이는 hg id 명령의 출력을 그대로 반영한 것으로, 바로 이런 용도로 사용하도록 의도된 것입니다. sys.subversion 값도 VCS의 변경을 반영하여 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

각주