Из-за того что Mercurial и Git обладают похожей моделью ветвления, а также из-за того что Git несколько более гибок, перенос репозитория из Mercurial в Git довольно прост; можете использовать инструмент hg-fast-export
, который можно найти здесь:
$ git clone https://github.com/frej/fast-export.git
Первым делом нужно получить полную копию интересующего Mercurial репозитория:
$ hg clone <remote repo URL> /tmp/hg-repo
Следующим шагом создадим файл соответствия авторов.
Mercurial менее строг к данным об авторстве коммитов, так что придётся слегка навести порядок.
Вот однострочный скрипт на bash
, который генерирует заготовку:
$ cd /tmp/hg-repo
$ hg log | grep user: | sort | uniq | sed 's/user: *//' > ../authors
Пройдёт несколько секунд, в зависимости от размера репозитория, и вы получите файл /tmp/authors
со следующим содержимым:
bob
bob@localhost
bob <[email protected]>
bob jones <bob <AT> company <DOT> com>
Bob Jones <[email protected]>
Joe Smith <[email protected]>
В примере выше, один и тот же человек (Боб) вносил изменения под пятью различными именами, лишь одно из которых правильное, а одно и вовсе не соответствует формату Git.
hg-fast-export
позволяет быстро исправить ситуацию, преобразовав каждую строку в правило: "<input>"="<output>"
, где <input>
преобразуется в <output>
.
Строки <input>
и <output>
могут содержать экранированные последовательности, поддерживаемые кодировкой python string_escape
.
Если файл сопоставлений авторов коммитов не содержит соответствующего <input>
, то значение будет передано Git без модификации.
Если же все имена выглядят хорошо, этот файл и вовсе не потребуется.
В нашем примере мы хотим чтобы файл выглядел так:
"bob"="Bob Jones <[email protected]>"
"bob@localhost"="Bob Jones <[email protected]>"
"bob <[email protected]>"="Bob Jones <[email protected]>"
"bob jones <bob <AT> company <DOT> com>"="Bob Jones <[email protected]>"
Аналогичные файлы применяются для переименования веток и тегов, когда сохранённое в 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
задаёт файл с соответствиями между авторами.
Скрипт пробегается по наборам изменений Mercurial и преобразует их в скрипт для fast-import
в Git (мы поговорим об этом инструменте чуть позже).
Процесс конвертации займёт некоторое время (хотя и намного меньше, чем при конвертации по сети), а мы пока можем наблюдать за подробным выводом в консоли:
$ /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
Вот, собственно, и всё. Все Mercurial теги были преобразованы в теги Git, а ветки и закладки — в ветки Git. Теперь можно отправить репозиторий на новый Git сервер:
$ git remote add origin git@my-git-server:myrepository.git
$ git push origin --all