Mercurial과 Git의 버전은 개념이 아주 비슷하다. 그리고 사실은 Git이 좀 더 유연해서 Mercurial 프로젝트를 Git 프로젝트로 변환하는 작업은 아주 쉽다. "hg-fast-export" 라는 툴을 사용하며 아래와 같이 내려 받는다.
$ git clone https://github.com/frej/fast-export.git우선 처음 할 일은 변환할 Mercurial 저장소 전체를 Clone 하는 일이다.
$ hg clone <remote repo URL> /tmp/hg-repo변환에 사용할 저자 매핑 파일을 하나 작성한다.
Mercurial의 Changeset에 적는 저자 정보의 형식은 Git에 비해 자유롭기 때문에 한 번 정리하는 것이 좋다.
저자 매핑 파일은 아래와 같은 한 라인으로 된 bash 명령을 사용한다.
$ cd /tmp/hg-repo
$ hg log | grep user: | sort | uniq | sed 's/user: *//' > ../authors프로젝트 크기에 따라 다르겠지만 위 명령을 실행하면 아래와 같은 매핑 파일이 생성된다.
bob
bob@localhost
bob <bob@company.com>
bob jones <bob <AT> company <DOT> com>
Bob Jones <bob@company.com>
Joe Smith <joe@company.com>예제를 보면 Bob 이라는 한 사람은 적어도 네 가지의 다른 저자 정보를 Changeset에 기록했다. 어떤 정보는 Git에서 쓸 수 있지만 어떤 정보는 Git에서 쓰기에 적절치 않다.
Hg-fast-export 에서는 "<input>"="<output>" 규칙을 사용하여 <input> 을 <output> 에 매핑할 수 있다.
<input> 과 <output> 문자열에는 Python의 string_escape 인코딩을 사용하는 이스케이프 문자열을 사용할 수 있다.
<input> 에서 찾을 수 없는 문자열을 만나는 경우 Git은 그 저자 내용을 변경하지 않고 그대로 사용한다.
물론 저자 정보가 모든 Changeset에 제대로 입력돼있다면 이런 변환 과정을 거치지 않아도 된다.
예제에서는 아래와 같이 저자 정보를 수정한다.
"bob"="Bob Jones <bob@company.com>"
"bob@localhost"="Bob Jones <bob@company.com>"
"bob <bob@company.com>"="Bob Jones <bob@company.com>"
"bob jones <bob <AT> company <DOT> com>"="Bob Jones <bob@company.com>"이와 같은 매핑 규칙을 Mercurial에서 사용하고 있지만 Git에서 사용하기 불가능한 브랜치나 태그이름에 대해서도 같은 방식으로 적용할 수 있다.
다음은 Git 저장소를 새로 만들고 변환 스크립트를 실행한다.
$ git init /tmp/converted
$ cd /tmp/converted
$ /tmp/fast-export/hg-fast-export.sh -r /tmp/hg-repo -A /tmp/authors-r 옵션으로 변환할 Mercurial 저장소의 위치를 지정하고 -A 옵션으로 저자 매핑 파일의 위치를 지정한다. (브랜치는 -B, 태그는 -T)
hg-fast-export.sh 스크립트는 Mercurial Changeset을 분석하여 Git의 "fast-import"에(곧 자세히 설명한다) 쓰는 스크립트를 생성한다.
명령을 실행하면 아래와 같이 보여준다.
$ /tmp/fast-export/hg-fast-export.sh -r /tmp/hg-repo -A /tmp/authors
Loaded 4 authors
master: Exporting full revision 1/22208 with 13/0/0 added/changed/removed files
master: Exporting simple delta revision 2/22208 with 1/1/0 added/changed/removed files
master: Exporting simple delta revision 3/22208 with 0/1/0 added/changed/removed files
[…]
master: Exporting simple delta revision 22206/22208 with 0/4/0 added/changed/removed files
master: Exporting simple delta revision 22207/22208 with 0/2/0 added/changed/removed files
master: Exporting thorough delta revision 22208/22208 with 3/213/0 added/changed/removed files
Exporting tag [0.4c] at [hg r9] [git :10]
Exporting tag [0.4d] at [hg r16] [git :17]
[…]
Exporting tag [3.1-rc] at [hg r21926] [git :21927]
Exporting tag [3.1] at [hg r21973] [git :21974]
Issued 22315 commands
git-fast-import statistics:
---------------------------------------------------------------------
Alloc'd objects: 120000
Total objects: 115032 ( 208171 duplicates )
blobs : 40504 ( 205320 duplicates 26117 deltas of 39602 attempts)
trees : 52320 ( 2851 duplicates 47467 deltas of 47599 attempts)
commits: 22208 ( 0 duplicates 0 deltas of 0 attempts)
tags : 0 ( 0 duplicates 0 deltas of 0 attempts)
Total branches: 109 ( 2 loads )
marks: 1048576 ( 22208 unique )
atoms: 1952
Memory total: 7860 KiB
pools: 2235 KiB
objects: 5625 KiB
---------------------------------------------------------------------
pack_report: getpagesize() = 4096
pack_report: core.packedGitWindowSize = 1073741824
pack_report: core.packedGitLimit = 8589934592
pack_report: pack_used_ctr = 90430
pack_report: pack_mmap_calls = 46771
pack_report: pack_open_windows = 1 / 1
pack_report: pack_mapped = 340852700 / 340852700
---------------------------------------------------------------------
$ git shortlog -sn
369 Bob Jones
365 Joe Smith상당히 많은 Changeset을 Git 커밋으로 변환했다. Mercurial 저장소의 모든 태그는 Git Tag로 변환되고 브랜치, 북마크은 Git 브랜치로 변환된다. 이제 서버 저장소를 만들고 Push 하면 된다.
$ git remote add origin git@my-git-server:myrepository.git
$ git push origin --all