пятница, 27 ноября 2009 г.

Введение в Mercurial. Часть 2. Основы работы

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

Основные сведения о ревизиях в Mercurial
Как и в большистве существующих систем контроля версий, центральным понятием Mercurial являетя ревизия, которая здесь называется changeset. В связи со спецификой распределенных систем контроля версий невозможно выдать каждой ревизии её номер, поскольку не получится гарантировать его уникальность среди всех существующих репозиториев. Однако  каждая ревизия все таки имеет уникальный идентификатор, в случае Mercurial это 40-значный sha1-хеш, который учитывает все параметры ревизии. Таким образом, у каждой новой ревизии в любом удаленном репозитории будет свой уникальный идентификатор. Использование подобной нумерации ревизий немного пугает начинающих пользователей, особенно переходящих на Mercurial с svn, однако ничего страшного в них нет, и использование тех или иных идентификаторов это просто дело привычки.

Начало работы
Вся работа с системой котроля версий Mercurial происходит с помощью команды hg, и во всех постах посвященных работе непосредственно с Mercurial, я буду приводить именно консольные команды, и консольные способы работы. Безусловно есть и вполне нормальные GUI-клиенты, однако освоение лучше начинать именно с консоли, чтобы лучше понять как именно все работает, и каковы логические и алгоритмические основы взаимодействия с этой системой контроля версий.
Работа с этой системой контроля версий, как, впрочем, и со всеми остальными, начинается с создания репозитория в пустом каталоге файловой системы. Для этого перейдём в выбранный каталог, пусть это будет ~/repos/hgproject, и скажем:
> hg init
По команде «hg init» Mercurial создает репозиторий в текущем каталоге. Если посмотреть на результат работы — мы увидим  каталог «.hg», в которой собственно и хранится вся история работы над проектом.
В принципе, рабочую копию можно хранить в той же папке, где был создан репозиторий, но поскольку мы собираемся знакомится с системой контроля версий, причем с распределенной, то будет лучше создать некое подобие обычной структуры работы над проектом. Для этого создадим каталог, в котором будет располагаться наш проект и перейдем в него, пусть это будет ~/projects.
Теперь нужно получить данные для начала работы над проектом. В общем случае это будет все содержимое некоторого репозитория расположенного где-то на сервере. Для этого перейдем в ~/projects и скомандуем:
> hg clone ~/repos/hgproject
По команде «hg clone» Mercurial «клонирует» репозиторий расположенный по указанному адресу в текущий каталог. При этом к вам попадает именно репозиторий, то есть хранилище, содержащее всю существующую историю изменений, что сильно отличает операцию клонирования от того же checkout в Subversion. Таким образом, у нас уже имеется два репозитория — то есть мы локально получили именно распределенную систему контроля версий. Взаимодействие может происходить с любым имеющимся репозиторием, так как они все равноценны, однако мы назовем репозиторий в каталоге ~/repos/hgproject "центральным", то есть введем конвенцию на взаимодействие с системой. Практически в любом случае работы в команде без подобных конвенций не обойтись.

Работа с локальным репозиторием
Начнем взаимодейтсвовать с полученной структурой репозиториев. С помощью вашего любимого текстового редактора создадим новый файл в каталоге с проектом, пусть для примера это будет readme.txt, и напишем некую строку символов в этот файл. Итак мы уже получили файлы в проекте, которые необходимо хранить в репозитории. Перед тем, как сохранить новый файл в репозитории сначала убедимся в том, что Mercurial его видит, для этого в каталоге с новым файлом выполним:
>hg status
? readme.txt
Mercurial ответил, что он видит файл readme.txt, при этом этот файл пока не находится в системе контроля версий (символ «?» слева от имени файла). По команде status Mercurial выводит состояние рабочей копии в сравнении с состоянием локального репозитория. Для того, чтобы сказать Mercurial, что его необходимо версионировать скажем:
> hg add
adding readme.txt
И ещё раз:
> hg status
A readme.txt
Видим, что слева от имени файла появился символ «А», который означает что файл readme.txt будет добавлен в систему контроля версий при следующем коммите, который мы сейчас и сделаем:
>hg commit
Mercurial запустит текстовый редактор и попросит ввести описание к выполняемому коммиту. Как только вы закроете его все изменения в рабочей копии будут сохранены в локальном репозитории. Убедиться в этом достаточно просто:
>hg log
changeset:   0:8fae369766e9
tag:         tip
user:        mike@mike-notebook
date:        Fri Nov 27 08:58:01 2009 +0300
summary:     Файл readme.txt добавлен в репозиторий
Разберем, что Mercurial выдал в этом сообщении. Changeset — это и есть номер ревизии, который состоит из двух частей: виртуального номера ревизии(записан до «:») и идентификатора (sha1-хеша). Виртуальный номер ревизии призван облегчить жизнь пользователям, и все-таки ввести в эту систему некоторую нумерацию ревизий. Но, как показывает практика использовать этот номер для однозначной идентификации нельзя, так как может привести к путанице в понимании происходящего в репозиториях. Обычно для однозначной идентификации версии достаточно 4-5 шестнадцатеричных цифр идентификатора. Следующей строкой идёт «tag: tip», вообще говоря tip — это обозначение последней ревизии, хотя выбирается это обозначение в различных случаях по различным принципам, в дальнейшем, когда будем рассматривать организацию ветвлений этот момент исследуем более подробно. Значение следующих строк очевидно, и нет необходимости их как-либо комментировать.

Обмен с удаленными репозиториями
А теперь вспомним, что у нас есть ещё некий «центральный» репозиторий, через который, по идее будет происходить взаимодействие с другими членами команды разработки. При этом выполненный коммит был локальным, то есть история изменений была сохранена только в вашем локальном репозитории. Для того, чтобы передать изменения в репозиторий расположенный в ~/repos/hgproject выполним:
> hg push
pushing to ~/repos/hgproject
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
После выполнения этой команды все изменения зафиксированные в локальном репозитории были зафиксированы также и в удаленном. Теперь склонируем репозиторий ещё раз, и посмотрим как происходит обмен ревизиями в Mercurial. Создадим новый каталог ~/projects/hgproj_clone, и склонируем в него наш удаленный репозиторий:
>hg clone ~/repos/hgproject ~/projects/hgproj_clone
updating working directory
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
И уже во вновь склонированном репозитории создадим файл other.txt с помощью вашего любимого текстового редактора.  И снова повторим операции описанные выше:
> hg status
? other.txt
> hg add
adding other.txt
> hg commit
> hg log
changeset:   1:270e49e72f4b
tag:         tip
user:        mike@mike-notebook
date:        Fri Nov 27 10:39:35 2009 +0300
summary:     Записан файл other.txt в другом репозитории


changeset:   0:8fae369766e9
user:        mike@mike-notebook
date:        Fri Nov 27 08:58:01 2009 +0300
summary:     Файл readme.txt добавлен в репозиторий
Видим, что в новом репозитории отражени как изменения сделанные локально, так и изменения сделанные в удаленном репозитории, которые мы ранее отправляли командой push. Теперь воспользуемся еще одной командой:
> hg outgoing
comparing with ~/repos/hgproject
searching for changes
changeset:   1:270e49e72f4b
tag:         tip
user:        mike@mike-notebook
date:        Fri Nov 27 10:39:35 2009 +0300
summary:     Записан файл other.txt в другом репозитории
По команде hg outgoing Mercurial выводит список ревизий которые есть в вашем локальном репозитории, но которых нет в «центральном». Отправим появившиеся ревизии в «центральный» репозиторий известным нам способом:
> hg push
pushing to ~/repos/hgproject
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
Итак, в «центральном репозитории две ревизии. Теперь научимся забирать обновления из центрального репозитория. Для этого перейдём в каталог с первым клоном, то есть в ~/projects/hgproject, и скажем:
> hg incoming
comparing with ~/repos/hgproject
searching for changes
changeset:   1:270e49e72f4b
tag:         tip
user:        mike@mike-notebook
date:        Fri Nov 27 10:39:35 2009 +0300
summary:     Записан файл other.txt в другом репозитории
Команда «hg incoming» выдает список ревизий, которые есть в удаленном репозитории, но отсутствуют в локальном. А затем получим эти ревизии, для чего скажем:
> hg pull
pulling from ~/repos/hgproject
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
(run 'hg update' to get a working copy)
Команда «hg pull» получает ревизии из удаленного репозитория, и добавляет их в локальный, таким образом, изменения из нашего «центрального» репозитория были перемещены в  локальный репозиторий. Но они остались только в репозитории, локальная копия осталась нетронутой. Для того, чтобы обновить локальную копию скажем:
> hg update
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
Если посмотреть на состояние рабочей копии, то она соответствует состоянию рабочей копии в репозитории ~/projects/hgproj_clone, а состояние хранилища во всех трех репозиториях одинаково.

Ну и напоследок просто необходимо сказать о ещё одной команде. «hg help», как вы уже, наверное, догадались выводит некоторый набор подсказок по работе с утилитами Mercurial. А при использовании в виде «hg help [command]» выводит подсказку о приемах работы с указанной командой. Причем это именно краткая подсказка, если вам требуется подробное описание, то лучше всего обратиться к документации, которая имеется в абсолютно свободном доступе и вполне неплохого качества.
Итак мы познакомились с основными приемами и командами работы с распределенной системой контроля версий Mercurial. Главным отличием, проявившихся на данном этапе, от централизованных систем контроля версий является наличие полной копии всего репозитория у каждого пользователя, что приводит к двухступенчатой системе взаимодействия с хранилищами (commit-push/pull-update). Такая двухступенчатая система требует некоторого привыкания, однако она вполне понятна и логична, и, на самом деле, достаточно проста в использовании. На этом я заканчиваю этот раздел. В следующем разделе мы рассмотрим наиболее интересные аспекты взаимодействия с Mercurial, а именно ветвления (branching) и слияния (merging).
Progg it

6 комментариев:

  1. Хех, тёзко! Продолжай цикл, отлично пишешь!

    ОтветитьУдалить
  2. В статье ничего не сказано про файл настроек (hgrc), в котором нужно прописать пользователей для commit'ов (и вероятно что-то еще).

    Где лучше создавать этот файл в Windows? (help предлагает несколько вариантов...)

    ОтветитьУдалить
  3. Хорошая, доходчивая и понятная статья. Большое спасибо.

    ОтветитьУдалить
  4. День добрый всем. Тоже наткнулся на проблему с файл настроек (hgrc) при выполнении , текст ошибки abort: .
    Решение есть на .
    Я делал так: в папке <.hg> есть файл в конец добавить:

    [ui]
    editor=notepad
    username=firstname.lastname@mail.com

    Username походу можно любой. Может автор добавит в примечание.
    Отличная статья. Большое спасибо автору.

    ОтветитьУдалить
  5. Извиняюсь парсер сел теги)).
    День добрый всем. Тоже наткнулся на проблему с файл настроек (hgrc) при выполнении "hg commit", текст ошибки abort: "no username supplied (see "hg help config")".
    Решение есть на "http://stackoverflow.com/questions/2329023/mercurial-error-abort-no-username-supplied".
    Я делал так: в папке ".hg" есть файл "hgrc" в конец добавить:

    [ui]
    editor=notepad
    username=firstname.lastname@mail.com

    Username походу можно любой. Может автор добавит в примечание.
    Отличная статья. Большое спасибо автору.

    ОтветитьУдалить
  6. не понятно то место в котором рассказан процесс клонирования удаленного репозитория в локальный ... как-то мыльно там всё

    ОтветитьУдалить