![](https://habrastorage.org/storage/eebea7f1/5482efc4/01467053/55589e0f.png)
Одно из преимуществ использования Mercurial — возможность работать командой над одним кодом. Mercurial позволяет каждому работать независимо и помогает объединять сделанные изменения.
Часть 3. Привыкаем работать в команде
![](https://habrastorage.org/storage/7b7801cf/49b2fd7d/6d606de3/1c97bbd1.png)
При командной работе с Mercurial общепринято настраивать центральный репозиторий в дополнение к личным репозиториям, расположенным на компьютерах членов команды. Центральный репозиторий можно рассматривать как своего рода блошиный рынок, то есть, как место где встречаются и обмениваются сделанным.
![](https://habrastorage.org/storage/32a5f305/c4895d33/2f30d931/4210364d.png)
Проще всего создать центральный репозиторий при помощи встроенного в Mercurial веб-сервера. Вам нужно лишь создать репозиторий при помощи
hg init
и открыть к нему доступ при помощи hg serve
. По умолчанию репозиторий будет доступен на 8000-ом порту.![](https://habrastorage.org/storage/1918f1bf/d865dae0/d4966f24/12e8fe35.png)
hg serve
запускает веб-сервер и делает текущий репозиторий доступным в сети Интернет.
Так как сервер запущен на компьютере joel.example.com, то я могу просто открыть joel.example.com:8000 в браузере и увидеть, что сервер работает, правда репозиторий абсолютно пуст.
![](https://habrastorage.org/storage/0140b8e0/896882e3/4baa6617/d1a267f3.png)
Имея запущенный центральный веб-сервер, я могу склонировать центральный репозиторий с сервера на мой компьютер для личного пользования. Репозиторий в данный момент пуст, значит, я получу еще один пустой репозиторий в результате клонирования.
![](https://habrastorage.org/storage/2c740a45/4fabec98/c98fcb7a/92f422c6.png)
hg clone
делает полную копию всего репозитория.
Теперь я создам файл guac, в котором запишу мой знаменитый рецепт гуакамоле.
![](https://habrastorage.org/storage/4aff84ff/486ba60c/9057e021/c0035b15.png)
Я добавлю и закоммичу этот файл в репозиторий. Это будет первая официальная версия:
![](https://habrastorage.org/storage/44d3a55b/e0d4e124/e42c1cf7/cf3b7c31.png)
Напишу комментарий к коммиту:
![](https://habrastorage.org/storage/89a503a1/b5c6d82d/6c6b4193/13248894.png)
Я быстренько отредактирую файл, сделав одно небольшое изменение, для того, чтобы у нас было хоть немного истории изменений в репозитории.
![](https://habrastorage.org/storage/deaba090/1260460f/410b04a4/5167fd72.png)
И зафиксирую изменения:
![](https://habrastorage.org/storage/233f2aa8/8318239c/90025c61/b72bd994.png)
Обратите внимание, что когда я коммитил в этот раз, то использовал аргумент
-m
, чего раньше не делал. Это просто для того, чтобы указать комментарий к коммиту в командной строке и не использовать редактор.Хорошо, что у нас есть? К настоящему времени у меня есть центральный репозиторий и мой персональный клон этого репозитория. Я сделал два изменения и зафиксировал их, но эти изменения хранятся в моем клоне. В центральном репозитории их пока нет. Так что все выглядит так:
![](https://habrastorage.org/storage/24badfd6/f67bd275/c3ddb80b/26b09b8b.png)
А сейчас я воспользуюсь командой
hg push
, которая протолкнет мои изменения из локального в центральный репозиторий:hg push
проталкивает свежие изменения из текущего репозитория в центральный.
![](https://habrastorage.org/storage/5a06d34f/2bc320d7/b153b069/e629a0db.png)
Ну, отлично. Ясно видно, что так не сработает. Не хочу думать о безопасности и последствиях запуска какого-то веб-сервера с разрешением всем и каждому проталкивать в него свои тупые изменения. Потерпите немного, я собираюсь настроить сервер так, чтобы он разрешал делать всем что угодно. Нужно отредактировать файл .hg\hgrc на сервере:
![](https://habrastorage.org/storage/36e5b657/454f8d10/28fb9c5f/d8f05740.png)
Не стоит и говорить, что это небезопасно. Но если вы в защищенной локальной сети на работе, и у вас есть хороший файрвол, и вы доверяете всем в своей сети, то так вполне можно сделать. В противном случае вам стоит почитать о настройках безопасности.
Хорошо, пора вновь запустить сервер:
![](https://habrastorage.org/storage/105523b5/59e1b4bf/6342c521/267d945e.png)
Теперь у меня должно получиться протолкнуть изменения:
![](https://habrastorage.org/storage/a2b9811f/4badc381/b95e5697/f5eb54c8.png)
Ага! Теперь все выглядит так:
![](https://habrastorage.org/storage/4dbad5c0/8258e140/798f5ae3/e02b095c.png)
Я знаю, о чем вы думаете. Вы думаете: «Господи, Джоэль, это все странно. Почему в репозиториях лежат изменения, а не файлы? Где тот файлик guac?».
Ну да, странно. Но так уж работает распределенный контроль версий. Репозитории просто хранят большие стопки изменений. Представьте, что одно изменение — это как лист частично прозрачного материала. Если у вас есть пачка таких листов, и вы сложите их друг на дружку так, чтобы самое последнее изменение было сверху, а потом посмотрите на эту пачку сверху вниз, то — та-да-да-дам! — увидите текущую версию файла. Если по одному убирать листы с верха стопки, то вы будете видеть все более и более ранние версии файла.
Воспользуемся браузером и снова заглянем в центральный репозиторий:
![](https://habrastorage.org/storage/3c857027/d3fe2213/746c3e1a/bd26eb0f.png)
Там именно то, что ожидалось.
Теперь я позову Розу помочь мне в работе над рецептом. Роза из команды тестеров. Любой подтвердит, что она напоминает одну из тех бабулек, что можно увидеть в Вегасе, часами сидящих с отвисшей челюстью перед «одноруким бандитом» и бросающих монетку за монеткой в заветную щелку. Все отличие в том, что Роза программы тестирует. Вы можете подкинуть ей новую версию программы, и она проверит ее на 23 дистрибутивах Linux. Проверит по очереди на каждом. Не выказывая никаких эмоций, не делая лишних движений. Останавливаясь только для того, чтобы сообщить вам, что пропущена точка над i в турецкой версии Ubuntu Linux. Роза отлично тестирует, но, клянусь, иногда ведет себя как зомби.
![](https://habrastorage.org/storage/371530e4/00fbd7ce/85609735/4208ce7b.png)
Роза воспользовалась командой
hg clone
для создания своей собственной полной копии репозитория. hg clone
принимает два аргумента: URL репозитория и имя каталога, в который вы хотите склонировать. У Розы свой каталог recipes.![](https://habrastorage.org/storage/3750c07a/f5b90d1b/06d55bb2/ecd4d3a6.png)
Обратите внимание, что при выполнении
hg log
она видит всю историю. То есть Роза скачала весь репозиторий с полной историей всего, что уже произошло.Сейчас Роза сделает изменение и внесет его в репозиторий:
![](https://habrastorage.org/storage/625ee93f/4abace04/4fa31409/85261f2d.png)
Вот, коммитит. Обратите внимание, что она может работать даже если сервер не работает: коммит полностью выполняется на ее машине.
![](https://habrastorage.org/storage/2326821c/0aa0eb4e/1b0ff6ad/985efcd6.png)
Пока Роза делала свои изменения, я тоже кое-что сделал.
![](https://habrastorage.org/storage/5e8ea447/72ead90e/263bba3f/8721f9eb.png)
После того, как я зафиксирую свои изменения, станет видно, что в моем логе под номером два указано не то же, что у Розы.
![](https://habrastorage.org/storage/2dba88e3/6da5d0aa/a3bb4bd9/7b38c1e1.png)
Истории в наших репозиториях начали отличаться.
![](https://habrastorage.org/storage/a9c1352a/9d5dc961/99774de2/5ae54129.png)
Не переживайте, скоро увидим, как свести все эти изменения воедино для получения отменной вкусняшки с чипсами и перчиком хабанеро.
Роза может продолжать работать без подключения к серверу, делая сколько угодно изменений. Она может фиксировать или откатывать изменения в своем репозитории. Однако настанет момент, когда она решит поделиться своими изменениями с остальными. Она может выполнить команду
hg outgoing
и увидеть список изменений, ожидающих отправки в центральный репозиторий. Это те изменения, которые будут отправлены при выполнении hg push
.![](https://habrastorage.org/storage/db449ef2/d6b61d93/156b0919/f19dd056.png)
hg outgoing
отображает список изменений ждущих отправки в текущем репозитории.
hg outgoing
это просто список всех таких изменений в текущем репозитории, которых нет в центральном репозитории.Хорошо, вот Роза проталкивает свои изменения в центральный репозиторий.
![](https://habrastorage.org/storage/7fce8e5d/56405199/c27ae4af/25722734.png)
И теперь все выглядит так:
![](https://habrastorage.org/storage/28086fde/fee793f7/af840235/a9751709.png)
После того, как я сходил выпить четвертую чашку латте за сегодняшний день, я тоже готов протолкнуть мое изменение про картофельные чипсы.
![](https://habrastorage.org/storage/66211440/3bef48f3/e7d8fa43/4a17dfb5.png)
ААААА!!! Ошибка! Да, кстати, видите сообщение? То, в котором написано используйте ключ -f для принудительного проталкивания (use push -f to force)? Это ужасный совет. Никогда и ни за что не используйте ключ -f. Вы пожалеете о том, что использовали его. Просто поверьте мне в данный момент.
Причина, по которой у Розы получилось протолкнуть изменения, а у меня нет в том, что картофельный чипсы и гуакамоле плохо сочетаются. Шучу, шучу! Просто хотел удостовериться, что вы еще не уснули там.
Команда завершилась с ошибкой потому, что каждый из нас сделал изменения, а значит, их нужно слить вместе, и Mercurial знает об этом.
Первым делом я заберу все изменения из центрального репозитория, которых у меня еще нет, чтобы произвести слияние (merge).
![](https://habrastorage.org/storage/cc14316f/6d00f829/c045eaff/b28a5dff.png)
Тут какая-то тарабарщина про +1 голову (+1 heads). Это потому, что мой репозиторий, в котором раньше были аккуратно уложены три изменения, стал двухголовым монстром. На вершине репозитория опасно расположены два разных изменения. Вот как это выглядит:
![](https://habrastorage.org/storage/d20fe311/841ec62a/25136b20/a75b2b3b.png)
У меня в репозитории теперь обе версии. Вот моя:
![](https://habrastorage.org/storage/7727aca4/0638daad/bddcb9a2/1cb4c06e.png)
А вот версия Розы:
![](https://habrastorage.org/storage/ccca055a/4385a92c/1b996f55/8e9755c9.png)
И я должен слить эти версии воедино. К счастью, это просто:
![](https://habrastorage.org/storage/94ed4e43/6c8c1c1c/f34767ff/9825f25a.png)
Глядите-ка! Команда
hg merge
взяла и объединила обе мои «головы» (изменения на вершине репозитория) в одну. Так как в данном случае мы с Розой изменили разные части файла, то конфликтов при слиянии не было и все прошло без сучка без задоринки.hg merge
производит слияние (объединение) двух «голов».
Мне по-прежнему надо сделать коммит. Это важно. Если бы слияние не удалось, то я всегда мог бы откатиться и попробовать снова. Но, так как слияние было успешным, то я сделаю коммит. После этого я смогу протолкнуть мои изменения в центральный репозиторий.
![](https://habrastorage.org/storage/2372798e/f0a49c6a/2f49a1ee/75085756.png)
Теперь в центральном репозитории то же, что в моем:
![](https://habrastorage.org/storage/3301ab87/9868c9ff/9bb6c7ea/acb0e87e.png)
Хорошо, у меня есть изменения Розы и мои собственные изменения, но у Розы пока нет моих изменений.
Есть еще один момент, связанный с Розой, о котором я забыл рассказать. Она — доктор. Ага, доктор, который врач. Ну не чудно? Она была главным педиатром в больнице Mt. Sinai и получала, наверное, «раз в пять больше, чем этот поганый укурок платит своим тестерам». Никто наверняка не знает, почему она оставила медицину. Остальные тестеры думают, что случилось что-то трагичное. Еще у нее семья была: на ее столе картинка милого десятилетнего ребенка. Но теперь она живет одна, и мы не хотим лезть ей в душу.
Розе нужно вытянуть (pull) свежие входящие изменения из репозитория, чтобы получить мои изменения.
![](https://habrastorage.org/storage/19f31f66/0a623177/f258cc66/5667615b.png)
Готово. Теперь, — вам может показаться это странным, — несмотря на то, что Роза втянула новые изменения в свой репозиторий, эти изменения не находятся в ее рабочем каталоге.
![](https://habrastorage.org/storage/c8bc0274/0d8008f0/40c44b5b/b92c3101.png)
Видите, Она по-прежнему работает с кукурузными чипсами. С кукурузными чипсами!
У нее есть мои последние изменения где-то в репозитории…
![](https://habrastorage.org/storage/37e67e82/67a3e142/e9022010/4fd8cfde.png)
Просто мои изменения не в ее рабочем каталоге. Это потому, что она до сих пор изменяет второй набор изменений. Это можно увидеть, выполнив команду
hg parent
:![](https://habrastorage.org/storage/248c9d9e/b3027e43/dee45f23/6063a7e3.png)
hg parent
отображает набор изменений, находящийся в рабочем каталоге.
Mercurial добр к нам. Вытягивать изменения всегда безопасно. Все, что происходит — это получение свежих изменений, сделанных другими людьми. Мы можем начать работать с этими изменениями позже, когда нам удобно.
Запомните, что команда
hg up
без аргументов приведет рабочий каталог к «макушке» (tip), то есть применит все изменения до самого верхнего набора изменений. В данном случае, это четвертый набор изменений:![](https://habrastorage.org/storage/06bd58a7/84eba403/73124798/54b38879.png)
Теперь Роза видит самую свежую версию с изменениями от обоих нас.
Когда вы работаете в команде, то рабочий процесс будет выглядеть во многом так:
- Забрать свежую версию, с которой все работают, если вы давненько этого не делали, выполнив:
- hg pull
- hg up
- Внести изменения
- Зафиксировать изменения (локально)
- Повторить пункты 2-3 до тех пор, пока у вас не получится хороший код, который вы хотите вывалить на всех остальных
- Когда вы готовы поделиться, выполнить:
- hg pull для получения чужих изменений (если есть)
- hg merge для слияния этих изменений со своими
- тестирование! для того, чтобы удостовериться, что при слиянии ничего не попортилось
- hg commit (для фиксации результата слияния)
- hg push
Проверь себя
Вот все, что вы должны уметь делать на данный момент:
- Настроить центральный репозиторий и дать членам команды возможность делать его клоны
- Проталкивать изменения в центральный репозиторий
- Вытягивать изменения из центрального репозитория
- Делать слияние изменений от разных авторов
Продолжение здесь:
Hg Init: Часть 4. Исправляем ошибки