Содержание
Прекомпилированные пакеты Mercurial доступны для каждой популярной операционной системы. Это позволяет вам начать использование Mercurial на вашем компьютере немедленно.
Лучшей версией Mercurial для windows является TortoiseHg, который можно найти на сайте http://tortoisehg.org. Этот пакет не имеет внешних зависимостей, он «просто работает». Он позволяет использовать командную строку и графический пользовательский интерфейс.
Ли Канти публикует инсталлятор mercurial для mac os x на http://mercurial.berkwood.com.
В силу того, что каждый дистрибутив Linux использует свои собственные менеджеры пакетов, а также стратегии и темпы разработки, трудно дать подробную инструкции по установке Mercurial. Версия Mercurial, которую вы получите очень зависит от того, насколько активен тот, кто занимается созданием пакетов для вашего дистрибутива.
Чтобы не усложнять процесс, я сфокусируюсь на установке Mercurial из командной строки в наиболее популярных дистрибутивах Linux. Большинство из них располагают менеждерами пакетов с графическим интерфейсом, что позволит вам установить Mercurial нажатием одной кнопки. Пакет для установки называется mercurial
.
SunFreeWare, на http://www.sunfreeware.com , предоставляет готовые пакеты Mercurial.
Для начала выполним команду hg version, чтобы удостовериться, что Mercurial установлен правильно. Какая версия на самом деле — неважно, главное, что она вообще что-то выводит.
$
hg version
Mercurial Distributed SCM (version 2.0) (see http://mercurial.selenic.com for more information) Copyright (C) 2005-2011 Matt Mackall and others This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
У Mercurial есть встроенная справка. Очень сложно переоценить ее наличие, особенно когда ваша работа остановилась из-за того, что вы не можете вспомнить как выполнить какую-то команду. Если Вы застопорились, просто выполните hg help, и на экран выведется краткий список команд с описанием назначения каждой из них. Если же вы еще и укажите конкретную команду (см. ниже), выведется подробная информация именно о ней.
$
hg help init
hg init [-e CMD] [--remotecmd CMD] [DEST] create a new repository in the given directory Initialize a new repository in the given directory. If the given directory does not exist, it will be created. If no directory is given, the current directory is used. It is possible to specify an "ssh://" URL as the destination. See "hg help urls" for more information. Returns 0 on success. options: -e --ssh CMD specify ssh command to use --remotecmd CMD specify hg command to run on the remote side --insecure do not verify server certificate (ignoring web.cacerts config) use "hg -v help init" to show more info
Для большей детализации выполните hg help -v
. Опция -v
- сокращение от --verbose
, заставит Mercurial выводить больше информации, чем обычно.
В Mercurial все происходит внутри репозитория. Репозиторий проекта содержит все файлы, которые «относятся» к проекту, а также историю изменений этих файлов.
В репозитории нет никакой магии, это просто каталог в файловой системе, который Mercurial обрабатывает особым образом. Вы можете переименовать или удалить репозиторий в любое время через командную строку или вашим собственным файловым менеджером.
Копирование репозитория кое-чем отличается. Хотя вы можете скопировать репозиторий как обычный каталог, лучше использовать встроенную команду Mercurial. Она называется hg clone, потому что создает идентичную копию существующего репозитория.
$
hg clone http://hg.serpentine.com/tutorial/hello
destination directory: hello requesting all changes adding changesets adding manifests adding file changes added 5 changesets with 5 changes to 2 files updating to branch default 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
Одно из преимуществ использования hg clone в том, что как мы видим выше, она позволяет клонировать репозитории по сети. Другим является то, что она запоминает, откуда мы его клонировали. Скоро мы убедимся, что это полезно, когда мы захотим принести новые изменения из другого репозитария.
Если клонирование прошло успешно, то у вас должен появится каталог под названием hello
. В нем должны быть какие-то файлы.
$
ls -l
total 0 drwxr-x--- 3 slava slava 100 Feb 2 14:10 hello$
ls hello
Makefile hello.c
У файлов в нашем репозитории то же самое содержимое и история, как и в исходном.
Каждый репозиторий Mercurial полон, самодостаточнен и независим. Он содержит свою собственную копию файлов проекта и их историю. Склонированный репозиторий помнит, откуда он был склонирован, но не общается с тем репозиторием, да и ни с каким другим тоже, до тех пор пока вы ему не скажете.
Это означает, что вы можете свободно экспериментировать с вашим репозиторием. Это безопасно, потому что ваш репозиторий — «закрытая песочница», изменения в котором не повлияют ни на что, кроме него самого.
Когда мы более пристально присмотримся к репозиторию, мы увидим, что он содержит каталог под названием .hg
. Это место, где Mercurial хранит все метаданные репозитория.
$
cd hello
$
ls -a
. .. .hg Makefile hello.c
Содержание каталога .hg
и его подкаталогов является собственностью Mercurial. Со всеми остальными файлами и каталогами в репозитории мы можем делать что угодно.
Строго говоря, каталог .hg
— это и есть «настоящий» репозиторий, а все остальные файлы и каталоги рядом с ним называются рабочим каталогом. Разницу запомнить довольно просто — репозиторий содержит всю историю вашего проекта, в то время как рабочий каталог содержит слепок вашего проекта в определенной точке истории.
Самое первое, что вы захотите сделать с новым, неизвестным репозиторием — изучить его историю. Команда hg log предназначена как раз для этого.
$
hg log
changeset: 4:2278160e78d4 tag: tip user: Bryan O'Sullivan <bos@serpentine.com> date: Sat Aug 16 22:16:53 2008 +0200 summary: Trim comments. changeset: 3:0272e0d5a517 user: Bryan O'Sullivan <bos@serpentine.com> date: Sat Aug 16 22:08:02 2008 +0200 summary: Get make to generate the final binary from a .o file. changeset: 2:fef857204a0c user: Bryan O'Sullivan <bos@serpentine.com> date: Sat Aug 16 22:05:04 2008 +0200 summary: Introduce a typo into hello.c. changeset: 1:82e55d328c8c user: mpm@selenic.com date: Fri Aug 26 01:21:28 2005 -0700 summary: Create a makefile changeset: 0:0a04b987be5a user: mpm@selenic.com date: Fri Aug 26 01:20:50 2005 -0700 summary: Create a standard "hello, world" program
По умолчанию, эта команда выводит краткую информацию о каждом изменении в проекте, которое было зафиксировано. В терминологии Mercurial мы называем эти зафиксированные события ревизией (changeset), потому что она может содержать изменения в различных файлах.
hg log выводит записи со следующими полями:
changeset
(ревизия). Она состоит из десятичного числа, двоеточия и строки шестнадцатеричных цифр. Это идентификаторы ревизии. Строка шестнадцатеричных цифр представляет собой уникальный идентификатор: та же строка шестнадцатеричных цифр будет обозначать этот набор изменений в каждой копии этого хранилища. Номер короче и проще напечатать, чем строку шестнадцатеричных цифр, но он не является уникальным: это же число в двух различных копиях репозитория могут иметь различные ревизии.
user
(пользователь). Идентификатор человека, создавшего ревизию. Там может находится все, что угодно, но чаще это имя человека и адрес электронной почты.
date
. Дата и время, когда была создана ревизия, а также часовой пояс, в котором она была создана. (Дата и время приведены относительно этого часового пояса, они указывают сколько времени было для того, кто создал ревизию)
summary
. Первая строка комментария к ревизии, который оставил её автор.
Некоторые наборы изменений, таких, как первая, имеют поле tag
(тэг). Теги это еще один способ идентифицировать набор изменений, придав ему легкое для запоминания имя. (Тег с названием tip
специальный: он всегда относится к новейшему изменению в репозитарии.)
По умолчанию hg log выводит очень общие сведения, с отсутствием множества деталей.
Рисунок 2.1, «Графическое представление истории репозитория hello
» содержит графическое представление истории репозитория hello
, что слегка облегчает понимание того, в каком направлении «развивается» его история. Мы будем возвращаться к этому рисунку в этой и следующей главах.
Английский язык печально известен своей небрежностью, а компьютерная наука имеет обширную историю неразберихи в терминах (зачем один термин, если можно использовать четыре). В контроле версий есть множество слов и фраз, означающих одно и то же. Если речь идет об истории в Mercurial, вы увидите, что слово «changeset» (набор изменений), обычно сокращается до «change», или (при письме), до «cset», а иногда «changeset» называют «revision» (ревизия) или «rev».
Не важно, какое слово вы используете для концепции «ревизии», идентификатор, по которому вы ссылаетесь на «определенную ревизию» имеет гораздо большее значение. Вспомните, что ревизия
в выводе команды hg log идентифицируется номером и шестнадцатеричной строкой.
Это различие очень важно. Если вы отправите кому-нибудь письмо с упоминанием «ревизии 33», существует большая вероятность, что их ревизия 33 будет совсем другой. Причиной этого является то, что номер ревизии зависит от порядка, в котором ревизии попадают в репозиторий, и нет никакой гарантии, что одни и те же изменения произойдут в одинаковом порядке в различных репозиториях. Три изменения А, Б и В
запросто могут появится в одном репозитории в порядке 0,1,2
, а в другом — 0,2,1
.
Mercurial использует номера ревизий исключительно для удобства. Если вам нужно обсудить с кем-то конкретную ревизию, или по какой-то другой причине ссылаться на нее (в багтрекере, например), используйте шестнадцатеричный идентификатор.
Чтобы ограничить вывод команды hg log до одной ревизии, используйте опцию -r
(или --rev
). Вы можете использовать или номер ревизии или ее идентификатор, а также запросить ревизий столько, сколько вам захочется.
$
hg log -r 3
changeset: 3:0272e0d5a517 user: Bryan O'Sullivan <bos@serpentine.com> date: Sat Aug 16 22:08:02 2008 +0200 summary: Get make to generate the final binary from a .o file.$
hg log -r 0272e0d5a517
changeset: 3:0272e0d5a517 user: Bryan O'Sullivan <bos@serpentine.com> date: Sat Aug 16 22:08:02 2008 +0200 summary: Get make to generate the final binary from a .o file.$
hg log -r 1 -r 4
changeset: 1:82e55d328c8c user: mpm@selenic.com date: Fri Aug 26 01:21:28 2005 -0700 summary: Create a makefile changeset: 4:2278160e78d4 tag: tip user: Bryan O'Sullivan <bos@serpentine.com> date: Sat Aug 16 22:16:53 2008 +0200 summary: Trim comments.
Если вы хотите увидеть историю нескольких ревизий, но не хотите просматривать их все, можете указать диапазон, как бы выражая мысль: «Мне нужны все ревизии от А
до Б
включительно».
$
hg log -r 2:4
changeset: 2:fef857204a0c user: Bryan O'Sullivan <bos@serpentine.com> date: Sat Aug 16 22:05:04 2008 +0200 summary: Introduce a typo into hello.c. changeset: 3:0272e0d5a517 user: Bryan O'Sullivan <bos@serpentine.com> date: Sat Aug 16 22:08:02 2008 +0200 summary: Get make to generate the final binary from a .o file. changeset: 4:2278160e78d4 tag: tip user: Bryan O'Sullivan <bos@serpentine.com> date: Sat Aug 16 22:16:53 2008 +0200 summary: Trim comments.
Mercurial учитывает порядок, в котором ревизии были указаны, так что hg log -r 2:4 выводит ревизии 2,3 и 4. Тогда как hg log -r 4:2 — 4,3 и 2.
В то время как информация, которую выводит hg log полезна, если вы знаете что ищете, вам может понадобиться полное описание изменений или список измененных файлов, если вы хотите узнать та ли это ревизия, что вам нужна. Команда hg log с аргументом -v
(--verbose
) предоставит вам такую возможность.
$
hg log -v -r 3
changeset: 3:0272e0d5a517 user: Bryan O'Sullivan <bos@serpentine.com> date: Sat Aug 16 22:08:02 2008 +0200 files: Makefile description: Get make to generate the final binary from a .o file.
Если вы хотите видеть описание и то как изменялось содержимое, добавьте опцию -p
(или --patch
). Будет показываться содержание изменений в едином diff (если вы никогда не видели формат унифицированного diff раньше, см. Раздел 12.4, «Понимание патчей»).
$
hg log -v -p -r 2
changeset: 2:fef857204a0c user: Bryan O'Sullivan <bos@serpentine.com> date: Sat Aug 16 22:05:04 2008 +0200 files: hello.c description: Introduce a typo into hello.c. diff -r 82e55d328c8c -r fef857204a0c hello.c --- a/hello.c Fri Aug 26 01:21:28 2005 -0700 +++ b/hello.c Sat Aug 16 22:05:04 2008 +0200 @@ -11,6 +11,6 @@ int main(int argc, char **argv) { - printf("hello, world!\n"); + printf("hello, world!\"); return 0; }
Давайте сделаем перерыв в изучении команд Mercurial и обсудим шаблоны работы с ними. Это будет вам полезно, когда мы продолжим наше турне.
Mercurial имеет простой и последовательный подход в работе с опциями, которые вы можете передавать командам. Это следует из соглашений по опциям, которые являются общими для современных Linux и Unix систем.
Каждая опция имеет длинное имя. К примеру, как мы уже видели, команда hg log принимает параметр --rev
.
Также большинство опций имеют короткие имена. Вместо --rev
можно использовать -r
. Не все опции имеют короткие имена, потому как некоторые из них просто редко используются.
Длинные опции начинаются с двух тире (--rev
), а короткие начинаются с одного (-r
).
Имена опций и их применение в командах согласовано. Например, все команды, позволяющие указывать ID или номер ревизии принимают оба аргумента -r
и --rev
.
При использовании коротких опций, вы можете печатать их вместе. Например, команда hg log -v -p -r 2 может быть записана в виде hg log -vpr2.
В примерах в этой книге я использую короткую запись аргументов, а не длинную. Это всего лишь дело моего вкуса, так что не ищите в этом скрытого смысла.
Большинство выводящих какую-то информацию команд выдадут большее количество информации, если им передать опцию -v
(или --verbose
), или меньшее, если передать опцию -q
(или --quiet
).
Так как мы уже умеем просматривать историю в Mercurial, можно заняться внесением изменений и их изучением.
Первое, что необходимо сделать — изолировать наш эксперимент в его собственном репозитории. Для этого используется команда hg clone, но так как у нас уже есть копия репозитория локально, то мы можем клонировать её вместо клонирования по сети. Это действие значительно быстрее, а кроме того, в большинстве случаев использует меньше места на диске[1].
$
cd ..
$
hg clone hello my-hello
updating to branch default 2 files updated, 0 files merged, 0 files removed, 0 files unresolved$
cd my-hello
Кстати говоря, хорошей идеей является хранение «нетронутой» копии удалённого репозитория, который можно использовать для создания временных клонов для получения «песочниц» для каждой задачи, над которой вам хочется поработать. Это позволяет вам работать над множеством задач одновременно, изолированных друг от друга до завершения и вашей готовности их интегрировать. Потому как локальные клоны настолько «дёшевы», что их создание и уничтожение в любое удобное время практически не несёт накладных расходов.
В нашем хранилище my-hello
, мы имеем файл hello.c
— классическую программу «Hello, World».
$
cat hello.c
/* * Placed in the public domain by Bryan O'Sullivan. This program is * not covered by patents in the United States or other countries. */ #include <stdio.h> int main(int argc, char **argv) { printf("hello, world!\"); return 0; }
Давайте отредактируем этот файл чтоб он печатал на выходе вторую строку.
# ... edit edit edit ...$
cat hello.c
/* * Placed in the public domain by Bryan O'Sullivan. This program is * not covered by patents in the United States or other countries. */ #include <stdio.h> int main(int argc, char **argv) { printf("hello, world!\"); printf("hello again!\n"); return 0; }
Команда Mercurial hg status покажет, что Mercurial знает о файлах в репозитории.
$
ls
Makefile hello.c$
hg status
M hello.c
hg status выводит информацию не обо всех файлах, а только об изменённых: это строка, начинающаяся с буквы «M
» для hello.c
. Пока вы не укажете это специально, hg status не будет выводить информацию про файлы, которые не изменились.
«M
» показывает, что Mercurial оповещен о модификации hello.c
. Мы не уведомляли Mercurial о том, что изменили файл ни перед, ни после окончания работы, он способен самостоятельно находить изменения.
Иногда мало просто знать только о факте изменения файла, и мы предпочли бы знать, какие точно изменения были сделаны. Для этого используется команда hg diff.
$
hg diff
diff -r 2278160e78d4 hello.c --- a/hello.c Sat Aug 16 22:16:53 2008 +0200 +++ b/hello.c Thu Feb 02 14:10:17 2012 +0000 @@ -8,5 +8,6 @@ int main(int argc, char **argv) { printf("hello, world!\"); + printf("hello again!\n"); return 0; }
Объяснение патчей | |
---|---|
Напомню, что нужно посмотреть Раздел 12.4, «Понимание патчей», если вы не знаете, как читать вывод команды выше. |
Мы можем изменять файлы, собирать и тестировать изменения и использовать команды hg status, hg diff для анализа изменений, пока мы не будем удовлетворены ими и не достигнем естественной точки, когда захочется записать проделанную работу в новую ревизию.
Команда hg commit позволяет создать новую ревизию. Для простоты, мы будем называть этот процесс «сделать коммит» или «закоммитить».
В первый раз выполнение команды hg commit может пройти неудачно. Mercurial записывает ваше имя и адрес в каждую ревизию, чтобы вы или другие пользователи могли связаться с автором каждого изменения. Mercurial пытается найти наиболее разумное имя пользователя для коммита. Поиск происходит в следующем порядке:
Если в команде hg commit вы указали опцию -u
, с последующим именем пользователя, то оно будет обладать наивысшим приоритетом.
Если у вас установлена переменная окружения HGUSER
, то следующей будет проверена она.
Если вы создали в своей домашней директории файл .hgrc
, и в нём есть директива username
— будет использована она. Чтобы узнать, как должен выглядеть содержимое этого файла, смотрите Раздел 2.7.1.1, «Создание файла конфигурации Mercurial».
Если у вас установлена переменная окружения EMAIL
, то будет использована она.
Mercurial использует локальное имя пользователя и хоста в системе, чтобы создать конечное имя. Так как часто полученное имя малополезно, то будет выведено предупреждение.
Если все варианты поиска завершились неудачно, Mercurial выведет сообщение об ошибке и не позволит создать коммит, пока вы не укажете имя пользователя.
Переменная HGUSER
и опция -u
в команде hg commit должны использоватся для изменения стандартного способа выбора имени. Для нормальной эксплуатации наиболее простой и надежный путь: установить имя в файле .hgrc
. Подробности смотри ниже.
Чтобы установить имя пользователя откройте свой любимый текстовый редактор и создайте файла .hgrc
в домашней директории. Mercurial будет использовать этот файл для поиска персональных настроек. Первоначальное содержание этого файла должно выглядить примерно так.
# This is a Mercurial configuration file. [ui] username = Firstname Lastname <email.address@example.net>
Строка «[ui]
» обьявляет секцию конфигурационного файла. Вы можете прочитать «username = ...
» как «установить значение переменной username
в секции ui
». Секции продолжаются до начала новых секций. Пустые строки и строки, начинаюшиеся с «#
» игнорируются.
Когда мы фиксируем изменения, Mercurial переводит нас в текстовый редактор, чтобы ввести комментарий, описывающее модификации, которые мы внесли в этом наборе изменений. Такое описание называется сообщением об изменениях (описанием изменений, описанием ревизии). Это будет записью для читателей о том, что мы сделали и почему, и будет выводиться при выполнении команды hg log после того, как мы закончим публикацию ревизии.
$
hg commit
Редактор, который откроется при выполнении команды hg commit, будет содержать пустую строку и несколько строк, начинающихся с «HG:
».
This is where I type my commit comment. HG: Enter commit message. Lines beginning with 'HG:' are removed. HG: -- HG: user: Bryan O'Sullivan <bos@serpentine.com> HG: branch 'default' HG: changed hello.c
Mercurial игнорирует строки, начинающиеся с «HG:
». Он использует их только для того, чтобы сообщить нам, изменения в каких файлах он запишет. Редактирование или удаление этих строк ни на что не повлияет.
Команда hg log по умолчанию выводит только первую строку описания изменений. Поэтому комментарий лучше написать так, чтобы первая строка была отделена. Вот хороший пример плохого комментария:
changeset: 73:584af0e231be user: Censored Person <censored.person@example.org> date: Tue Sep 26 21:37:07 2006 -0700 summary: include buildmeister/commondefs. Add exports.
Для оставшейся части описания ревизии нет жестких правил. Сам Mercurial не обрабатывает и не заботится о содержимом сообщения об изменениях, хотя в вашем проекте могут быть правила, предписывающие определённое форматирование.
Моё личное предпочтение — короткие, но содержательные комментарии, которые сообщают мне то, чего я не могу выяснить при беглом взгляде на вывод команды hg log --patch.
Если мы выполним команду hg commit без каких-либо аргументов, запишутся все изменения, которые мы сделали, как сообщил hg status и hg diff.
Если вы передумаете публиковать изменения во время редактирования комментария, просто выйдите из редактора без сохранения изменяемого файла. Это не вызовет изменений ни в репозитории, ни в рабочем каталоге.
Закончив публикацию ревизии, мы можем воспользоваться командой hg tip для показа только что созданного набора изменений. Вывод этой команды похож на вывод команды hg log, но отображает только последнюю версию в репозитории.
$
hg tip -vp
changeset: 5:c3e3be994861 tag: tip user: Bryan O'Sullivan <bos@serpentine.com> date: Thu Feb 02 14:10:17 2012 +0000 files: hello.c description: Added an extra line of output diff -r 2278160e78d4 -r c3e3be994861 hello.c --- a/hello.c Sat Aug 16 22:16:53 2008 +0200 +++ b/hello.c Thu Feb 02 14:10:17 2012 +0000 @@ -8,5 +8,6 @@ int main(int argc, char **argv) { printf("hello, world!\"); + printf("hello again!\n"); return 0; }
Мы называем последнюю ревизию конечной (или верхней) ревизией или просто главной.
Кстати, команда hg tip принимает многие из опций команды hg log. Так, например, -v
означает «более подробно», -p
— «показать патч». Использование -p
для показа патча является еще одним примером последовательного подхода к именованию опций.
Ранее мы упоминали, что репозитории в Mercurial самодостаточны. Это значит, что только что созданный набор изменений существует лишь в нашем репозитории my-hello
. Давайте рассмотрим несколько способов, которыми мы можем распространить это изменение в другие репозитории.
Для начала клонируем наш исходный репозиторий hello
, в котором нет последнего изменения, только что нами опубликованного. Назовём наш временный репозиторий hello-pull
.
$
cd ..
$
hg clone hello hello-pull
updating to branch default 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
Мы будем использовать команду hg pull, для получения изменений из my-hello
в hello-pull
. Однако вытягивание вслепую неизвестных изменений в репозиторий может быть пугающей перспективой. Mercurial позволяет узнать с помощью команды hg incoming, какие изменения команда hg pull вытянет в репозиторий без реального применения изменений.
$
cd hello-pull
$
hg incoming ../my-hello
comparing with ../my-hello searching for changes changeset: 5:c3e3be994861 tag: tip user: Bryan O'Sullivan <bos@serpentine.com> date: Thu Feb 02 14:10:17 2012 +0000 summary: Added an extra line of output
Получение изменений в репозиторий означает выполнение команды hg pull и указание ей, из какого репозитория следует вытягивать.
$
hg tip
changeset: 4:2278160e78d4 tag: tip user: Bryan O'Sullivan <bos@serpentine.com> date: Sat Aug 16 22:16:53 2008 +0200 summary: Trim comments.$
hg pull ../my-hello
pulling from ../my-hello 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 tip
changeset: 5:c3e3be994861 tag: tip user: Bryan O'Sullivan <bos@serpentine.com> date: Thu Feb 02 14:10:17 2012 +0000 summary: Added an extra line of output
Как видно из вывода команды hg tip до и после, мы успешно вытянули изменения в наш репозиторий. Тем не менее, вытягивание изменений в Mercurial отделено от обновления рабочей директории. Остается один шаг до того, как мы увидим изменения в рабочем каталоге.
До сих пор мы говорили о связи между репозиторием и его рабочим каталогом. Команда hg pull, которую мы выполнили в Раздел 2.8.1, «Получение (вытягивание) изменений из другого репозитория», вытянула изменения в наш репозиторий. Но если проверить, в рабочем каталоге нет ни следа этих изменений. Это потому, что hg pull не трогает (по умолчанию) рабочий каталог. Для применения изменений мы используем команду hg update.
$
grep printf hello.c
printf("hello, world!\");$
hg update tip
1 files updated, 0 files merged, 0 files removed, 0 files unresolved$
grep printf hello.c
printf("hello, world!\"); printf("hello again!\n");
Может показаться странным то, что hg pull не обновляет рабочий каталог автоматически. На самом деле этому есть веская причина: вы можете использовать hg update, для обновления рабочего каталога до состояния, в котором он был в любой ревизии в истории репозитория. Если бы вы обновили рабочий каталог до старой версии — например, чтобы отыскать причину ошибки, — а затем выполнили бы hg pull, которая обновляет рабочий каталог автоматически до новой версии, вы были бы ужасно недовольны этим.
Однако, так как вытягивание с последующим обновлением является распространенным явлением, Mercurial позволяет вам совместить их передачей команде hg pull ключа -u
.
Если вы снова посмотрите на вывод команды hg pull в Раздел 2.8.1, «Получение (вытягивание) изменений из другого репозитория», когда мы выполнили её без -u
, вы увидите, что в конце вывода было полезное напоминание о необходимости явного действия для обновления рабочего каталога.
Чтобы узнать, какая ревизия у рабочего каталога, используйте команду hg parents.
$
hg parents
changeset: 5:c3e3be994861 tag: tip user: Bryan O'Sullivan <bos@serpentine.com> date: Thu Feb 02 14:10:17 2012 +0000 summary: Added an extra line of output
Если вы снова взглянете на Рисунок 2.1, «Графическое представление истории репозитория hello
», вы увидите стрелки, соединяющие между собой каждую последующую ревизию. Вершина, из которой в каждом случае ведёт стрелка, — родитель, а та вершина, куда стрелка ведёт, — потомок. Аналогично, у рабочего каталога есть родитель — это набор изменений, который содержится в данный момент в рабочем каталоге.
Чтобы обновить рабочий каталог до конкретной ревизии, передайте номер или идентификатор ревизии команде hg update.
$
hg update 2
2 files updated, 0 files merged, 0 files removed, 0 files unresolved$
hg parents
changeset: 2:fef857204a0c user: Bryan O'Sullivan <bos@serpentine.com> date: Sat Aug 16 22:05:04 2008 +0200 summary: Introduce a typo into hello.c.$
hg update
2 files updated, 0 files merged, 0 files removed, 0 files unresolved$
hg parents
changeset: 5:c3e3be994861 tag: tip user: Bryan O'Sullivan <bos@serpentine.com> date: Thu Feb 02 14:10:17 2012 +0000 summary: Added an extra line of output
Если вы опустите явное указание ревизии, hg update обновит до верхней ревизии, как видно в примере выше при втором вызове hg update.
Mercurial позволяет передать изменения в другой репозиторий из репозитория, в котором мы в данный момент находимся. Как с примером hg pull выше, создадим временный репозиторий для передачи в него наших изменений.
$
cd ..
$
hg clone hello hello-push
updating to branch default 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
Команда hg outgoing сообщает нам об изменениях, которые будут переданы в другой репозиторий.
$
cd my-hello
$
hg outgoing ../hello-push
comparing with ../hello-push searching for changes changeset: 5:c3e3be994861 tag: tip user: Bryan O'Sullivan <bos@serpentine.com> date: Thu Feb 02 14:10:17 2012 +0000 summary: Added an extra line of output
И команда hg push вызывает настоящую передачу.
$
hg push ../hello-push
pushing to ../hello-push searching for changes adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files
Как и hg pull, команда hg push не обновляет рабочую директорию репозитория, в который передаются изменения. (В отличие от hg pull, у hg push нет ключа -u
, который обновлял бы рабочую директорию другого репозитория). Эта асимметрия является преднамеренной: репозиторий в который мы передаём изменения может находиться на удаленном сервере и распределяться между несколькими людьми. Если бы нам пришлось обновить свой рабочий каталог в то время как кто-то работал в нём, его работа была бы нарушена.
Что же произдойдёт, если мы попробуем получить или передать изменения, а в принимающем репозитории они уже есть? Ничего особенного.
$
hg push ../hello-push
pushing to ../hello-push searching for changes no changes found
Когда мы клонируем репозиторий, Mercurial записывает расположение репозитория из которого мы делали клон в файле .hg/hgrc
нового репозитория. Если мы не будем указывать место для hg pull (откуда) или для hg push (куда), эти команды будут использовать это место в качестве репозитория по умолчанию. Команды hg incoming и hg outgoing делают то же самое.
Если вы откроете файл .hg/hgrc
в текстовом редакторе, вы увидите содержимое похожее на следующее.
[paths] default = http://www.selenic.com/repo/hg
Возможно — и часто полезно — чтобы путь по умолчанию для hg push и hg outgoing, отличался от пути для hg pull и hg incoming. Мы можем так сделать, добавив запись default-push
в секцию [paths]
файла .hg/hgrc
.
[paths] default = http://www.selenic.com/repo/hg default-push = http://hg.example.com/hg
Команды, которые мы затронули в нескольких предыдущих разделах, не ограничиваются работой с локальными репозиториями. Любая из них работает таким же способом и через сеть — просто укажите команде URL вместо локального пути.
$
hg outgoing http://hg.serpentine.com/tutorial/hello
comparing with http://hg.serpentine.com/tutorial/hello searching for changes changeset: 5:c3e3be994861 tag: tip user: Bryan O'Sullivan <bos@serpentine.com> date: Thu Feb 02 14:10:17 2012 +0000 summary: Added an extra line of output
В следующем примере мы могли бы увидеть, какие изменения мы можем передать в удалённый репозиторий, но в репозитории, очевидно, не разрешён приём изменений от анонимных пользователей.
$
hg push http://hg.serpentine.com/tutorial/hello
pushing to http://hg.serpentine.com/tutorial/hello searching for changes remote: ssl required
Начать новый проект так же просто, как и использовать уже существующий. Команда hg init создает новый, пустой репозиторий Mercurial.
$
hg init myproject
Это просто создаст репозиторий с именем myproject
в текущем каталоге.
$
ls -l
total 8 -rw-r----- 1 slava slava 47 Feb 2 14:09 goodbye.c -rw-r----- 1 slava slava 45 Feb 2 14:09 hello.c drwxr-x--- 3 slava slava 60 Feb 2 14:09 myproject
Можно сказать, что myproject
это репозиторий Mercurial, потому что он содержит каталог .hg
.
$
ls -al myproject
total 0 drwxr-x--- 3 slava slava 60 Feb 2 14:09 . drwx------ 3 slava slava 140 Feb 2 14:09 .. drwxr-x--- 3 slava slava 100 Feb 2 14:09 .hg
Если мы хотим добавить существующие файлы в репозиторий, мы копируем их внутрь рабочей директории, и с помощью команды hg add сообщаем Mercurial, что нужно начинать за ними следить.
$
cd myproject
$
cp ../hello.c .
$
cp ../goodbye.c .
$
hg add
adding goodbye.c adding hello.c$
hg status
A goodbye.c A hello.c
После того как мы убедились, что проект выглядит хорошо, мы публикуем наши изменения.
$
hg commit -m 'Initial commit'
Старт нового проекта с Mercurial займёт всего несколько мгновений, и это является частью его привлекательности. Контроль версий стал сейчас настолько простым, что мы можем его использовать даже в маленьких проектах, в которых, возможно, не использовали бы более сложные инструменты.
[1] Экономия пространства возникает, когда источник и получатель репозитория находятся на одной файловой системе, в этом случае Mercurial будет использовать жесткие ссылки, чтобы использовать политику совместного использования копрование-при-записи для его внутренних метаданных. Если это объяснение ничего для вас не значит, не беспокойтесь: все происходит прозрачно и автоматически, и вам не нужно ничего понимать.