Mercurial vs. Git в коммерческой разработке
Для начала я хочу внести ясность в понятие коммерческой разработки и её отличий от других моделей. В коммерческой разработке принято ставить конкретные цели и отслеживать этапы выполнения работы. Тогда как, например, в open source моделях разработки, обычно цели ставит перед собой отдельный разработчик, а этапность их исполнения и привязка к бизнес требованиям никого не интересует.
Зачем вообще нужна система контроля версий? Есть несколько причин:
— Обеспечить одновременную возможность работы коллектива над кодом;
— Сохранить лог всех изменений и версий для того чтобы при необходимости вернуть версию или часть кода, а также разобраться в проблеме на основе анализа изменений.
Отличия между Git и Mercurial
Главное отличие — «Its all in branches», как сформулировал однажды Felipe Contreras в своём блоге. В статье приведена масса аргументов, почему git технически лучше, чем mercurial, и большинство из этих аргументов бесспорны. Действительно, для программиста проекта open source на сегодняшний день git — лучший выбор.
Да и вообще, если спрашивать только программистов, в том числе на коммерческих проектах, выбор тоже будет преимущественно в пользу git. Видимо, процесс выбора системы контроля версий полностью отдаётся на откуп программистам, а они, конечно же, выберут самый технически совершенный инструмент на рынке, чем и является на сегодня git.
Но этот выбор может оказаться сомнительным, если взглянуть на него с точки зрения PM. А вот многие слабые места Mercurial оказываются, на поверку, его сильными сторонами.
Взгляд техлида/PM — почему Mercurial удобнее
Предлагаю рассмотреть следующие отличия git vs. mercurial в контексте их удобства для PM и коммерческого проекта в целом:
— невозможность удаления веток, коммитов, т.е. изменения истории репозитория;
— уровень сложности обучения;
— «тяжёлые» ветки, в коммитах которых ветка привязана напрямую.
Отслеживаемость изменений
На всех наших проектах поддержка Traceability позволяет нам работать более эффективно. Если вернуться в начало статьи, то трассировка позволяет нам отслеживать:
— этапность изменений;
— привязку изменений к бизнес требованиям.
Как это реализовано на практике: связка с таском кодируется в названии ветки, например: 29277_pivot_table, 30249_summary_page, 30081_agroups, 28255_angularjs_todo. Мы работаем c теми самыми «тяжёлыми» ветками, в которых ветка привязана к коммиту. В номере ветки кодируется номер задачи и краткое описание. Потом, если вдруг в hg annotate (аналог команды blame) мы попытаемся понять, кто изменил конкретную строку кода, нам не составит труда открыть трекинговую систему с номером таска. В таске, в свою очередь, перечислены (путём обычных comments) список всех изменений к данному таску.
И если вдруг заказчик задаст мне вопрос: «Кто выпилил важный баннер на первой странице с рекламой главного рекламодателя?» — я смогу чётко ответить, указав ссылку на бизнес требование и таск, с ним связанный.
Полноценная трассировка невозможна в Git по нескольким причинам:
— Ветка может быть удалена. Git, как более мощный инструмент, позволяет удалять ветки и другие части лога из истории. То есть вполне может так оказаться, что останется только merge commit, в котором может быть указана только общая причина (например, «вливка версии 11 в master»).
— Возможно, вы обнаружите commit девелопера, но это ещё не решение. В коммите может быть сказано: «Выпилил баннер». А почему так произошло — тайна покрытая мраком. Тут приходится делать упор на то, чтобы девелоперы обязательно ставили номер таска в commit msg. Регулярно наблюдаю эту картинку в командах, которые работают с git, и там же регулярно наблюдаю процентов
Для того, чтобы хоть как-то решить эту проблему, в Jira стоит авто-отслеживание коммитов по номеру таска, совпадающих с названием проекта. Но этого оказывается недостаточно для 100% гарантии результата.
Сложность обучения и эксплуатации
Большинство людей, которые используют git, вообще не понимают, о чём я говорю. Ну да, они «уже» работают, в 90% случаев не вдаваясь в подробности, почему это так устроено. Некоторые имеют на бумажке «шпаргалку» в которой указаны наиболее часто используемые команды.
Я не могу себе отказать в удовольствии немного потроллить пользователей git, которые считают его синтаксис логичным и понятным.
1. Разделение типов репозиториев в git и команда clone
Начнём с первого шага, и здесь я сразу вижу некоторую неудобность git в рельной жизни. И в git, и в mercurial синтаксис команды clone одинаковый:
git clone <откуда> <куда>
hg clone <откуда> <куда>
Вроде всё логично? Всё, да не совсем. В Git, оказывается, есть разделение репозиториев на клоны для девелоперов (рабочие) и клоны для сервера (bare). Это сделано, видимо, в целях оптимизации, но в результате, чтобы обменяться кодом с соседом программистом, мне уже недостаточно будет просто написать hg push ssh://otheruser@othercomp, а потребуется создать bare репозиторий и организовать обмен кодом на его основе.
2. Работа с ветками
В Git придётся выучить целый раздел описания того, как работать с локальными и удалёнными ветками, как их клонировать, коммититься и т.п. Это, конечно, хорошо, если оно реально используется. Это суперфича важна для open source, когда можно локально играться на разных ветках и оправлять на оценку сообществу только те ветки, которые уже завершены и готовы к рассмотрению.
В коммерческой же модели разработки PM’у важно видеть объём и качество сделанной работы каждый день, а иногда и чаще. И, соответственно,удобно, чтобы все рабочие ветки заливались на сервер, что по умолчанию происходит в mercurial.
Я не хочу сказать, что работа с локальными/удалёнными ветками — это плохо. Опционально я был бы не против такой фичи в mercurial. Но её полезность в нашей ежедневной работе под большим сомнением.
Помимо того, данный функционал довольно сильно усложняет синтаксис вызова команд. Если в Mercurial всё, что вам требуется знать, — это просто команды создания, перехода между ветками, то в git всё намного сложнее. И хотя сложный функционал востребован редко, пользоваться им приходится всем. Примеры для сравнения:
hg | git | комментарий |
hg diff | git diff HEAD | показать текущие изменения |
hg up branchname | git checkout -b branchname origin/branchname | перейти в ветку |
hg push | git push git push origin master | отправить изменения на сервер |
Мне поначалу было сложно понять, что за origin и почему надо указывать ветку.
С точки зрения простоты, Mercurial действительно незамысловат. Отправляет все локальные ветки по умолчанию на сервер, то же самое происходит в обратной ситуации.
Будьте внимательны с синтаксисом вызова git. Допустим, для удаления ветки в git используется не очень понятная конструкция типа git push origin :the_remote_branch
. То есть мы отправляем «пусто» заменить ветку на сервере — в результате команды удаляется ветка на сервере.
С точки зрения менеджмента это опасная команда. Я бы такую запретил, если бы мог:) Или, как вариант, — бекапировать основной репозиторий время от времени.
В Mercurial ничего удалить нельзя (тривиальным способом). Для меня как для PM’а это плюс, для разработчика скорее минус.
Простота запоминания команд в Mercurial
Сравните:
hg | git |
hg in | git fetch && git log master..FETCH_HEAD |
hg out | git fetch && git log FETCH_HEAD..master |
hg purge | git clean -fd |
hg revert -a | git reset --hard |
hg addremove | git add .; git ls-files --deleted xargs git rm |
hg glog | git log --graph --all --decorate |
Ну и закодированное git config
по сравнению с обычным простым файлом .hg/hgrc
Минусы Mercurial
Все вышеуказанные плюсы в какой-то мере могут стать и минусами. Например, самая проблемная ситуация — не стоит добавлять огромные файлы в репозиторий. Один наш заказчик решил, что таким образом можно добавить media файлы, включая рекламные ролики, и размер репозитория резко вырос на размер видео, помноженный на два. Удалить их простым способом было невозможно, пришлось использовать ConvertExtension.
Второй минус — к хорошему привыкаешь быстро. Поработав немного с mercurial, возвращаться на git довольно сложно, так как приходится вспоминать зубодробительный синтаксис для простых вещей.
Третий минус — вы, как PM, скорее всего, не сможете переубедить свои программистов в необходимости перехода на Mercurial. Причина проста — они уже выучили один синтаксис, переучиваться не хотят. Тем более, на заведомо более слабую по фичам систему. Есть шанс, если стартовать новый проект.
Выводы
Спор о том, что лучше, а что хуже, сильно зависит от контекста решаемых задач. Мой выбор на сегодня прост — для Open Source я пользуюсь в основном git, в коммерческих проектах — только Mercurial.
Хочу пожелать читателям правильно делать свой выбор.