Source

hgbook-ru / ru / appA-svn.xml

Full commit
<!-- vim: set filetype=docbkxml shiftwidth=2 autoindent expandtab tw=77 : -->

<appendix id="svn">
  <?dbhtml filename="migrating-to-mercurial.html"?>
<title>Переход на Mercurial</title>

  <para id="x_6e1">Простой способ прощупать почву с новым инструментом контроля версий, это поэкспериментировать с переключением существующих проектов, а не начинать новый проект с нуля.</para>

  <para id="x_6e2">В этом приложении мы обсудим, как импортировать историю проекта в Mercurial, и на что обратить внимание, если вы привыкли к другой системе контроля версий.</para>

  <sect1>
    <title>Импорт истории из другой системы</title>

    <para id="x_6e3">Mercurial поставляется с расширением называемым <literal>convert</literal>, которое может импортировать историю проекта из наиболее популярных систем контроля версий. В то время когда эта книга была написана, оно могло импортировать историю из следующих систем:</para>
    <itemizedlist>
      <listitem>
	<para id="x_6e4">Subversion</para>
      </listitem>
      <listitem>
	<para id="x_6e5">CVS</para>
      </listitem>
      <listitem>
	<para id="x_6e6">git</para>
      </listitem>
      <listitem>
	<para id="x_6e7">Darcs</para>
      </listitem>
      <listitem>
	<para id="x_6e8">Bazaar</para>
      </listitem>
      <listitem>
	<para id="x_6e9">Monotone</para>
      </listitem>
      <listitem>
	<para id="x_6ea">GNU Arch</para>
      </listitem>
      <listitem>
	<para id="x_6eb">Mercurial</para>
      </listitem>
    </itemizedlist>

    <para id="x_6ec">(Чтобы понять, почему Mercurial поддерживает в качестве источника самого себя, смотрите в разделе <xref linkend="svn.filemap"/>.)</para>

    <para id="x_6ed">Вы можете включить расширение в обычном порядке, отредактировав файл <filename>~/.hgrc</filename>.</para>

    <programlisting>[extensions]
convert =</programlisting>

    <para id="x_6ee">Это сделает доступной команду <command>hg convert</command>. Команда проста в использовании. Например, эта команда будет импортировать историю Subversion для Nose unit testing framework в Mercurial.</para>

    <screen><prompt>$</prompt> <userinput>hg convert http://python-nose.googlecode.com/svn/trunk</userinput></screen>

    <para id="x_6ef">Расширение <literal>convert</literal> действует поэтапно. Иными словами, после того как вы выполните <command>hg convert</command> первый раз, запуская его снова вы будете импортировать любые новые ревизии, совершенные после первого запуска. Инкрементные преобразования будут работать только если вы запустите <command>hg convert</command> в том же репозитории Mercurial, который вы использовали, потому что расширение <literal>convert</literal> сохраняет некоторые частные метаданные не под контролем системы контроля версий, в файле с именем <filename>.hg/shamap</filename> внутри целевого репозитория.</para>

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

    <sect2>
      <title>Конвертирование нескольких ветвей</title>

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

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

      <para id="x_70a">Как только вы преобразовывали свое дерево, если вы хотите следовать обычной для Mercurial практике работы в  одном дереве, содержащем одну ветку, можно клонировать одну ветку используя <command>hg clone -r mybranchname</command>.</para>
    </sect2>

    <sect2>
      <title>Связь имён пользователей</title>

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

      <para id="x_6f1">Если вы преобразовываете дерево из системы контроля версий, которая использует короткие имена, можно сопоставить эти имена с длинными эквивалентами, передавая опцию <option>--authors</option> команде <command>hg convert</command>. Этот параметр принимает имя файла, который должен содержать записи следующего вида.</para>

      <programlisting>arist = Aristotle &lt;aristotle@phil.example.gr&gt;
soc = Socrates &lt;socrates@phil.example.gr&gt;</programlisting>

      <para id="x_6f2">Всякий раз, когда <literal>convert</literal> встретит ревизию с именем пользователя <literal>arist</literal> в исходном репозитории, он будет использовать имя <literal>Aristotle &lt;aristotle@phil.example.gr&gt;</literal> в преобразованной для Mercurial ревизии. Если совпадения не найдется, то имя используется дословно.</para>
    </sect2>

    <sect2 id="svn.filemap">
      <title>Очистка дерева</title>

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

      <para id="x_6f4">Расширение <literal>convert</literal> поддерживает идею <quote>карты файлов</quote>, которая позволяет реорганизовать файлы и каталоги в проекте, при импорте истории проекта. Это полезно не только при импорте истории из других систем контроля версий, но также и для того чтобы подрезать или реорганизовать дерево Mercurial.</para>

      <para id="x_6f5">Чтобы указать карту файлов, используйте опцию <option>--filemap</option> и укажите имя файла. Карта файлов содержит строки в следующем формате.</para>

      <programlisting># This is a comment.
# Empty lines are ignored.	

include path/to/file

exclude path/to/file

rename from/some/path to/some/other/place
</programlisting>

      <para id="x_6f6">Директива <literal>include</literal> указывает файл или все файлы в каталоге, которые будут включены в целевой репозиторий. Она также исключает любые другие файлы и директории не включенные явно. Директива <literal>exclude</literal> указывает файлы или директории, которые будут исключены, а другие прямо не упоминаемые должны быть включены.</para>

      <para id="x_6f7">Чтобы переместить файлы или каталог из одного места в другое, используйте директиву <literal>rename</literal>. Если вам необходимо переместить файл или каталог из подкаталога в корневой каталог репозитория, используйте <literal>.</literal> в качестве второго аргумента директивы <literal>rename</literal>.</para>
    </sect2>

    <sect2>
      <title>Улучшение эффективности преобразования Subversion</title>

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

      <para id="x_70c">Команда <ulink url="http://svn.collab.net/repos/svn/trunk/notes/svnsync.txt"><command>svnsync</command></ulink> может значительно ускорить преобразование репозитория Subversion. Она создаёт зеркало только для чтения для репозитория Subversion. Идея заключается в создании локального зеркала вашего Subversion дерева, а затем преобразовании зеркала в Mercurial репозиторий.</para>

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

      <screen><prompt>$</prompt> <userinput>svnadmin create memcached-mirror</userinput></screen>

      <para id="x_70e">Далее, мы установим ловушку Subversion необходимую для <command>svnsync</command>.</para>

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

      <para id="x_70f">Затем мы инициализируем <command>svnsync</command> в этом репозитории.</para>

      <screen><prompt>$</prompt> <userinput>svnsync --init file://`pwd`/memcached-mirror \
  http://code.sixapart.com/svn/memcached</userinput></screen>

      <para id="x_710">Наш следующий шаг &emdash; начинаем процесс зеркалирования <command>svnsync</command>.</para>

      <screen><prompt>$</prompt> <userinput>svnsync sync file://`pwd`/memcached-mirror</userinput></screen>

      <para id="x_711">Наконец, мы импортируем истории нашего локального зеркала Subversion в Mercurial.</para>

      <screen><prompt>$</prompt> <userinput>hg convert memcached-mirror</userinput></screen>
      
      <para id="x_712">Мы можем использовать этот процесс инкрементно, если репозиторий Subversion по-прежнему используется. Мы запускаем <command>svnsync</command> для вытягивания новых изменений в наше зеркало, а затем запускаем <command>hg convert</command> для импорта их в наше дерево Mercurial.</para>

      <para id="x_713">Есть два преимущества двухступенчатого импорта с <command>svnsync</command>. Во-первых, используется более эффективная синхронизация кода Subversion по сети, чем при <command>hg convert</command>, так как меньше данных передаётся по сети. Во-вторых, импорт из локального дерева Subversion настолько быстр, что вы можете изменять ваши установки неоднократно без ожидания сетевых процессов каждый раз.</para>
    </sect2>
  </sect1>

  <sect1>
    <title>Переход из Subversion</title>

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

    <sect2>
      <title>Философские различия</title>

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

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

      <sect3>
	<title>Набор команд</title>

	<para id="x_6fb">Поскольку Subversion не знает, что части ее пространства имён в действительности ветви, то относится к большинству команд, как запросу работы над любым каталогом в котором вы сейчас находитесь. Например, если вы запускаете <command>svn log</command>, вы получите историю той части дерева, в которой вы находитесь, а не дерева в целом.</para>

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

	<para id="x_6fd">Из моего собственного опыта, это различие в поведение по умолчанию, скорее всего запутает вас, если у вас есть необходимость часто переключаться между двумя инструментами.</para>
      </sect3>

      <sect3>
	<title>Многопользовательская эксплуатация и безопасность</title>

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

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

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

      <sect3>
	<title>Публикация против локальных изменений</title>

	<para id="x_701">Команда Subversion <command>svn commit</command> немедленно публикует изменения на сервер, где их могут видеть все, кто имеет доступ на чтение.</para>

	<para id="x_702">С Mercurial фиксация всегда локальна, и должна быть опубликована через команду <command>hg push</command> позднее.</para>

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

	<para id="x_704">Подход Mercurial позволяет любому, кто может клонировать репозиторий вносить изменения без необходимости каких-либо разрешений, и они могут публиковать свои изменения и продолжать участвовать так как они считают нужными. Различие между фиксацией и публикацией открывает возможность фиксировать изменения на своём ноутбуке и на несколько дней забыть, чтобы потом отправить их, что в редких случаях сотрудник может временно застрять.</para>
      </sect3>
    </sect2>

    <sect2>
      <title>Краткий справочник</title>

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

  <sect1>
    <title>Полезные советы для новичков</title>

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

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

    <screen><prompt>$</prompt> <userinput>hg status `hg root`</userinput></screen>
  </sect1>
</appendix>

<!--
local variables: 
sgml-parent-document: ("00book.xml" "book" "appendix")
end:
-->