Создание и сопровождение сайтов

Блог. Разработка. Mercurial: коммиты, слияния

Поиск

    Это статья для начинающих, постараюсь объяснить непонятные моменты (подразумеваю, что базовые вещи всетаки уже известны) работы в HG.

    Когда человек работает с репозиторием один - проблем, как правило, не возникает. Непонятки начинаются, когда с репозиторием работают 2 или более человек. Добавляет бардака "визуальный" софт - TortoiseHg, например. Люди привыкли тыкать одну кнопочку и чтобы "всё было хорошо". А тут куча кнопочек, еще и с невнятным переводом (если используется руссифицированная версия).

    Поэтому для обучения категорически рекомендую начинать с работы в консоли.

    Самая основная концепция, которую необходимо понять: HG - это децентрализованная система контроля версий. В любой момент времени есть, как минимум, два полноценных репозитория: на удаленном сервере и локальный, в папке проекта. Все изменения, в первую очередь, происходят в локальном репозитории. Чтобы обновить репозиторий на сервере необходимы дополнительные шаги.

    Итак, рабочий процесс.
Пришли утром на работу, начинаем работать и выполняем в консоли из директории проекта (подразумеваю, что проект уже есть и вечером предыдущего дня нормально положили всё на сервер):

hg pull -u

Командой hg pull мы обновляем с сервера наш локальный репозиторий (только репозиторий! файлы проекта не трогаются). За обновление файлов проекта отвечает флаг -u. Это всё делается на случай, если были какие-то изменения в коде.

    Теперь мы начинаем работать: пишем код, по завершению каждого логического блока выполняем коммит (и сразу пишем комментарий к нему):

hg commit -m "Исправил ошибку #58"

Этой командой мы зафиксировали изменения кода в локальном репозитории. Другим разработчиком ваши изменения пока недоступны! Они хранятся только у вас.

    К концу рабочего дня у нас имеется локальный репозиторий с несколькими коммитами в нём.
Теперь нам надо отправить всё наше добро на удаленный сервер - чтобы наши правки были доступны остальным разработчикам. Выполняем команду:

hg push

Этой командой мы отправляем все изменения из локального репозитория в удаленный. Если в удаленном репозитории с утра не было никаких изменений - то все проходит нормально.

Но мы рассмотрим случай с конфликтом. Поэтому в ответ мы получаем:

pushing to ...
searching for changes
abort: push creates new remote heads on branch 'default'!
(you should pull and merge or use push -f to force)

Не надо пугаться такого сообщения - это лишь значит, что в удаленном репозитории произошли изменения и нам необходимо обновить свой локальный репозиторий и произвести слияние своих изменений с другими изменениями.
Для этого выполняем:

hg pull

Этой командой обновляем локальный репозиторий из удаленного. Получаем сообщение:

pulling from ...
searching for changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 1 changes to 1 files (+1 heads)
(run 'hg heads' to see heads, 'hg merge' to merge)

    Теперь у нас в локальном репозитории интересная ситуация - у нас получилось 2 ветки. Одна ветка - изменения с сервера, вторая ветка - наши изменения.
Но нам необходимо из этих двух веток сделать одну, в которой были бы все изменения. Для этого выполяем команду:

hg merge

И если слияние произошло без конфликтов - у нас получается код проекта, к которому применены все изменения.
Мы должны зафиксировать эти изменения:

hg commit -m "Слияние"

И протолкнуть их на сервер:

hg push

    Если же при слиянии были конфликты - то открывается программа слияния с тремя версиями конфликтного файла. Это окно всех начинающих повергает в шок :)
Если окно не отрывается, то, возможно, у вас не настроена или не установлена утилита слияния. Рекомендую установить и настроить - интернете множество статей по этой теме.

    Утилит слияния много, не буду останавливаться на какой-то конкретно, расскажу общие принципы.
Все они отличаются немного внешним видом, управлением, некоторые отличаются кривостью (встроенная мержилка в NetBeans 6.9.1 выводит меня из себя своим неудобством, поэтому использую meld).

    Итак, отображаются 3 версии файла: local, base, remote (в некоторых есть еще и 4 версия - merged). Именно BASE/MERGED вводит всех в ступор.

Расшифрую, что к чему:
LOCAL - файл с вашими правками
REMOTE - файл с сервера
BASE - исходный файл, "не правленный", к которому была попытка применения изменений (локальных и с сервера). 

Тут мы подходим к очень деликатному моменту. Как я говорил выше - у нас есть две ветки. В данном случае ветви анонимные - то есть у них нет названия и возникли они из-за конфликта. После слияния ветвление исчезнет и ветви сольются в один "ствол". Поэтому все изменения вносим в файл LOCAL - то есть в наш текущий проект.

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

    Смотрим и исправляем все конфликты, сохраняемся и выходим из программы.

    После всех исправлений смотрим на работоспособность кода (актуально, если изменения были нетривиальные). После чего коммитим наше слияние и проталкиваем на сервер командами:

hg commit -m "Слияние"
hg push

Рабочий день закончен, с чистой совестью идём домой. Всем спасибо!

PS: Обсудить, задать вопросы по HG можно в специальной теме на нашем форуме.