Приложение A. Переход на Mercurial

Содержание

A.1. Импорт истории из другой системы
A.1.1. Конвертирование нескольких ветвей
A.1.2. Связь имён пользователей
A.1.3. Очистка дерева
A.1.4. Улучшение эффективности преобразования Subversion
A.2. Переход из Subversion
A.2.1. Философские различия
A.2.2. Краткий справочник
A.3. Полезные советы для новичков

Простой способ прощупать почву с новым инструментом контроля версий, это поэкспериментировать с переключением существующих проектов, а не начинать новый проект с нуля.

В этом приложении мы обсудим, как импортировать историю проекта в Mercurial, и на что обратить внимание, если вы привыкли к другой системе контроля версий.

A.1. Импорт истории из другой системы

Mercurial поставляется с расширением называемым convert, которое может импортировать историю проекта из наиболее популярных систем контроля версий. В то время когда эта книга была написана, оно могло импортировать историю из следующих систем:

  • Subversion

  • CVS

  • git

  • Darcs

  • Bazaar

  • Monotone

  • GNU Arch

  • Mercurial

(Чтобы понять, почему Mercurial поддерживает в качестве источника самого себя, смотрите в разделе Раздел A.1.3, «Очистка дерева».)

Вы можете включить расширение в обычном порядке, отредактировав файл ~/.hgrc.

[extensions]
convert =

Это сделает доступной команду hg convert. Команда проста в использовании. Например, эта команда будет импортировать историю Subversion для Nose unit testing framework в Mercurial.

$ hg convert http://python-nose.googlecode.com/svn/trunk

Расширение convert действует поэтапно. Иными словами, после того как вы выполните hg convert первый раз, запуская его снова вы будете импортировать любые новые ревизии, совершенные после первого запуска. Инкрементные преобразования будут работать только если вы запустите hg convert в том же репозитории Mercurial, который вы использовали, потому что расширение convert сохраняет некоторые частные метаданные не под контролем системы контроля версий, в файле с именем .hg/shamap внутри целевого репозитория.

Если вы хотите начать делать изменения, используя Mercurial, то лучше клонировать дерево, в котором вы будете проводить преобразование и оставить оригинальное дерево для последующий инкрементальных преобразований. Это самый безопасный способ позволяет вытягивать и объединять будущие изменения из исходной системы контроля версий в своём новом активном репозитории Mercurial.

A.1.1. Конвертирование нескольких ветвей

Команда hg convert приведенная выше преобразует только историю ветки trunk репозитория Subversion. Если мы вместо этого используем URL http://python-nose.googlecode.com/svn, Mercurial автоматически обнаружит trunk, tags и branches, которые обычно используют проекты Subversion, и он будет импортировать каждый как отдельную ветвь Mercurial.

По умолчанию, каждая ветка Subversion импортируется в Mercurial с названием ветки. После завершения преобразования, можно получить список имен активных веток в Mercurial репозитории с помощью hg branches -a. Если вы предпочитаете импортировать ветви Subversion без названия, используйте опцию --config convert.hg.usebranchnames=false команды hg convert.

Как только вы преобразовывали свое дерево, если вы хотите следовать обычной для Mercurial практике работы в одном дереве, содержащем одну ветку, можно клонировать одну ветку используя hg clone -r mybranchname.

A.1.2. Связь имён пользователей

Некоторые средства контроля версий сохраняют только короткие имена пользователей при фиксации, и они могут трудно интерпретироваться. Обычно в Mercurial сохраняется имя коммиттера и адрес электронной почты, который является гораздо более полезным для разговора с ними после факта фиксации.

Если вы преобразовываете дерево из системы контроля версий, которая использует короткие имена, можно сопоставить эти имена с длинными эквивалентами, передавая опцию --authors команде hg convert. Этот параметр принимает имя файла, который должен содержать записи следующего вида.

arist = Aristotle <aristotle@phil.example.gr>
soc = Socrates <socrates@phil.example.gr>

Всякий раз, когда convert встретит ревизию с именем пользователя arist в исходном репозитории, он будет использовать имя Aristotle <aristotle@phil.example.gr> в преобразованной для Mercurial ревизии. Если совпадения не найдется, то имя используется дословно.

A.1.3. Очистка дерева

Не все проекты имеют чистую историю. Там может быть каталог, который никогда не должен были проверятся, слишком большие файлы, или целая иерархия, которая должна быть переработана.

Расширение convert поддерживает идею «карты файлов», которая позволяет реорганизовать файлы и каталоги в проекте, при импорте истории проекта. Это полезно не только при импорте истории из других систем контроля версий, но также и для того чтобы подрезать или реорганизовать дерево Mercurial.

Чтобы указать карту файлов, используйте опцию --filemap и укажите имя файла. Карта файлов содержит строки в следующем формате.

# This is a comment.
# Empty lines are ignored.	

include path/to/file

exclude path/to/file

rename from/some/path to/some/other/place

Директива include указывает файл или все файлы в каталоге, которые будут включены в целевой репозиторий. Она также исключает любые другие файлы и директории не включенные явно. Директива exclude указывает файлы или директории, которые будут исключены, а другие прямо не упоминаемые должны быть включены.

Чтобы переместить файлы или каталог из одного места в другое, используйте директиву rename. Если вам необходимо переместить файл или каталог из подкаталога в корневой каталог репозитория, используйте . в качестве второго аргумента директивы rename.

A.1.4. Улучшение эффективности преобразования Subversion

Часто требуется несколько попыток, прежде чем будет получена идеальное сочетание карты пользователей, карты файлов и других параметров конвертации. Преобразование репозитория subversion через протокол доступа похожий на ssh или http может протекать в тысячи раз медленнее, чем Mercurial реально способен работать, из-за задержек в сети. Это делает подбор идеальных настроек преобразования очень тяжелой.

Команда svnsync может значительно ускорить преобразование репозитория Subversion. Она создаёт зеркало только для чтения для репозитория Subversion. Идея заключается в создании локального зеркала вашего Subversion дерева, а затем преобразовании зеркала в Mercurial репозиторий.

Предположим, мы хотим преобразовать репозиторий Subversion для популярного проекта Memcached в Mercurial дерево. Во-первых, мы создаем локальный репозиторий Subversion.

$ svnadmin create memcached-mirror

Далее, мы установим ловушку Subversion необходимую для svnsync.

$ echo '#!/bin/sh' > memcached-mirror/hooks/pre-revprop-change
$ chmod +x memcached-mirror/hooks/pre-revprop-change

Затем мы инициализируем svnsync в этом репозитории.

$ svnsync --init file://`pwd`/memcached-mirror \
  http://code.sixapart.com/svn/memcached

Наш следующий шаг — начинаем процесс зеркалирования svnsync.

$ svnsync sync file://`pwd`/memcached-mirror

Наконец, мы импортируем истории нашего локального зеркала Subversion в Mercurial.

$ hg convert memcached-mirror

Мы можем использовать этот процесс инкрементно, если репозиторий Subversion по-прежнему используется. Мы запускаем svnsync для вытягивания новых изменений в наше зеркало, а затем запускаем hg convert для импорта их в наше дерево Mercurial.

Есть два преимущества двухступенчатого импорта с svnsync. Во-первых, используется более эффективная синхронизация кода Subversion по сети, чем при hg convert, так как меньше данных передаётся по сети. Во-вторых, импорт из локального дерева Subversion настолько быстр, что вы можете изменять ваши установки неоднократно без ожидания сетевых процессов каждый раз.

A.2. Переход из Subversion

Subversion в настоящее время является самой популярной системой контроля версий с открытым исходным кодом. Хотя есть много различий между Mercurial и Subversion, что делает переход от Subversion на Mercurial не особенно трудным. Обе имеют схожие наборы команд и в целом единый интерфейс.

A.2.1. Философские различия

Основное различие между Subversion и Mercurial, конечно то, что Subversion является централизованной, в то время как Mercurial распределённой. Mercurial хранит всю историю проекта на локальном диске, сеть нужна только если вы хотите явно общаться с другим репозиторием. В отличие от Subversion, которая очень мало информации хранит локально, и таким образом, клиент должен связываться со своим сервером для большинства распространенных операций.

Subversion более или менее может обходится без четко определенного понятия ветви: какая-то часть пространства имён сервера объявляется веткой и является предметом конвенции, с программным ограничением доступа. Mercurial обрабатывает репозиторий в качестве единой ветви управления.

A.2.1.1. Набор команд

Поскольку Subversion не знает, что части ее пространства имён в действительности ветви, то относится к большинству команд, как запросу работы над любым каталогом в котором вы сейчас находитесь. Например, если вы запускаете svn log, вы получите историю той части дерева, в которой вы находитесь, а не дерева в целом.

Команды Mercurial ведут себя по-другому, по умолчанию они работают со всем репозиторием. Запустите hg log и он расскажет вам историю всего дерева, в какой бы части рабочей директории вы не находились в данный момент. Если вы хотите увидеть историю одного файла или каталога, просто укажите его имя, например, hg log src.

Из моего собственного опыта, это различие в поведение по умолчанию, скорее всего запутает вас, если у вас есть необходимость часто переключаться между двумя инструментами.

A.2.1.2. Многопользовательская эксплуатация и безопасность

В Subversion, это нормально (хотя и несколько неодобрительно) для нескольких пользователей совместно работать в одной ветке. Если Алиса и Боб работают вместе, и Алиса совершает какое-либо изменений в их общей ветке, Бобу необходимо обновить свою рабочую копию прежде чем он сможет фиксировать свои изменения. Так как в это время он не имеет постоянной записи своих изменений, он может повредить или потерять их в ходе или после обновления.

Mercurial использует модель фиксация-потом-слияние. Боб фиксирует свои изменения локально перед вытягиванием изменений, или отправкой их на сервер, который он разделяет с Алисой. Если Алиса отправит ее изменения перед тем как Боб попытается отправить свои, он не сможет отправить свои изменения пока вытянет ее, не выполнит слияние с ними, и не зафиксирует результат слияния. Если он делает ошибку в процессе слияния, он все еще может вернуться к ревизии, в которой записаны его изменения.

Стоит отметить, что это общие методы работы с этими инструментами. Subversion поддерживает безопасную модели работы-в-своей-собственной-ветке, но это достаточно громоздко на практике и не будет широко использоваться. Mercurial может поддерживать менее безопасный режим, позволяющий вытягивать изменения и объединять их поверх незафиксированных изменений, но это считается в высшей степени необычным.

A.2.1.3. Публикация против локальных изменений

Команда Subversion svn commit немедленно публикует изменения на сервер, где их могут видеть все, кто имеет доступ на чтение.

С Mercurial фиксация всегда локальна, и должна быть опубликована через команду hg push позднее.

Каждый подход имеет свои преимущества и недостатки. Модель Subversion означает, что изменения публикуются и, следовательно могут быть пересмотрены и использованы, немедленно. С другой стороны, это означает, что пользователь должен иметь доступ к фиксации в репозиторий для того, чтобы использовать программное обеспечение в обычном порядке, а доступ к фиксации не легко выдается в большинстве проектов с открытым кодом.

Подход Mercurial позволяет любому, кто может клонировать репозиторий вносить изменения без необходимости каких-либо разрешений, и они могут публиковать свои изменения и продолжать участвовать так как они считают нужными. Различие между фиксацией и публикацией открывает возможность фиксировать изменения на своём ноутбуке и на несколько дней забыть, чтобы потом отправить их, что в редких случаях сотрудник может временно застрять.

A.2.2. Краткий справочник

Таблица A.1. Команды Subversion и их эквиваленты в Mercurial

Subversion Mercurial Примечание
svn add hg add  
svn blame hg annotate  
svn cat hg cat  
svn checkout hg clone  
svn cleanup n/a Очистка не требуется
svn commit hg commit; hg push hg push публикует после фиксации
svn copy hg clone Создание новой ветки
svn copy hg copy Копирование файлов и директорий
svn delete (svn remove) hg remove  
svn diff hg diff  
svn export hg archive  
svn help hg help  
svn import hg addremove; hg commit  
svn info hg parents Показывает какая ревизия сейчас вытянута
svn info hg showconfig paths.parent Показывает вытянутый URL
svn list hg manifest  
svn log hg log  
svn merge hg merge  
svn mkdir n/a Mercurial не отслеживает каталоги
svn move (svn rename) hg rename  
svn resolved hg resolve -m  
svn revert hg revert  
svn status hg status  
svn update hg pull -u  

A.3. Полезные советы для новичков

В некоторых системах контроля версий, печать diff для одного зафиксированной ревизии может быть мучительным. Например, в Subversion, чтобы посмотреть, что изменилось в редакции 104654, вы должны ввести svn diff -r104653:104654. Mercurial устраняет необходимость указания ID-ревизии дважды в общем случае. Для простого просмотра используйте hg export 104654. Для сообщения лога и последующего diff hg log -r104654 -p.

При запуске hg status без каких-либо аргументов, он выдает статус всего дерева, с путями относительно корня репозитория. Это делает сложным копирование имени файла из вывода hg status в командную строку. Если вы укажете имя файла или каталога команде hg status, она будет печатать пути относительно вашего текущего местоположения вместо этого. Таким образом, чтобы получить статус всего дерева с помощью hg status, с путями, которые считаются относительно текущего каталога, а не корня репозитория, укажите вывод команды hg root как параметр для команды hg status. Вы легко можете сделать это следующим образом на Unix-подобной операционной системе:

$ hg status `hg root`