Mercurial vs. Git в коммерческой разработке

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://[email protected], а потребуется создать 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.

Хочу пожелать читателям правильно делать свой выбор.

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті.

До обраного В обраному 0

Схожі статті Коли дрібниці важливі. Пишемо коміти в Git

Коміти — це цінна штука, але водночас буденна, хоча так було не завжди. Ще кілька років тому заливати зі схрещеними пальцями апдейти щодо FTP було так само поширеною практикою, як сьогодні «коміт-пуш-додомку». 29

Підготовка додатків до локалізації

В локалізації, як і всюди, легше попередити потенційні проблеми, ніж потім боротися з ними. В статті перераховано деталі, на які варто звертати увагу уже на етапі розробки продукту, щоб потім не мати проблем, як зліпити «бульдога з носорогом». 25

Рефакторинг: основные принципы и правила

Привет, DOU. Меня зовут Андрей Данильченко, я PHP-разработчик в Wikr Group. В этой статье расскажу о рефакторинге. Не всегда удается сразу писать хороший код, поэтому рефакторинг становится неотъемлемой частью процесса разработки. 28

DOU News #12

Найкращі коментарі пропустити

жду статью «двойные кавычки vs одинарные кавычки в javascript в комерческой разработке»

Изначально думал не тратить время на комментарий, но, сделав себе крепкого кофе, приступим:1.

Как PM у Вас есть возможность устанавливать правила на проекте

Я пользовался и hg, и git. Мне кажется, что для конечного пользователя (программиста, девопса или тестировщика) разницы нет, это довольно простой (и мощный, конечно) инструмент в использовании. Намного распространённей git, поэтому смысла изучать hg не вижу.А ещё, перед написанием такого рода статьи, надо самому пройти курс git’a

Пожалуйста, выпилите эту статью. Неокрепшие умы могут подумать, что она правдива

Вброс на тему Г@вно vs Конфетка.Натыкаясь на подобные статьи, понимаешь что кто-то там» это состояние души.. ТС перестаньте.Я понимаю, что некоторое количество знаний у Вас перешло в качество.Но не надо экстраполировать его на новые домены, в которых Вы не совсем эксперт.Ещё и в ультимативной форме.. Команды в гите для вас не очень логичные!А вас не смущает, что есть кран подъёмный и кран водопроводный?!Это жизнь, она многообразнее всех вместе взятых проекций реального мира, под названием — люди. .

118 коментарів

честно говоря вообще пофиг, svn, git, tfs все работает в правильных руках

С этим сложно не согласиться ;-) Да и действительно, какой бы совершенный инструмент не был, если в процессах бардак, ничего не поможет. Мы вот проект один начинали на cvs, потом импорт в svn, далее в hg. 10+ лет, полёт нормальный, вся история с привязкой к tasks сохранилась

Автор, марш учить матчасть git-scm.com/bookВсе надумано от незнания. Некоторые вещи вообще практически вывели меня из себя..

Начнем с того, что ветки в hg не были задизайнены специально для того, что-бы в них хранить фича нейм. Вы *адоптировали* hg под себя. Точно так-же вы можете и в гите, как уже говорилось, записывать метаданные о коммите в коммит мессадж, или использовать теги, или организовав нужный вам маппинг в джире, итд — тем самым адоптировав под себя и гит. Я не хочу даже начинать спорить с «Тех. директор в UA2WEB» об организации девелопмент процесса в веб-студии, где преимущественно php и пришибленные заказчики. Вы не одиноки — с 1Сниками об этом я бы тоже спорить не стал. Ровно как и бухгалтеры, наверное, зачем-то, теоретически, могли бы адаптировать git/hg под какие-то свои нужды.Я просто хочу сказать остальным девелоперам, которые случайно могут наткнуться на вашу статью, что-бы ни в коем случае вас не слушали. В остальном, прогрессивном мире, ваши проблемы надуманны и никому не интересны. Там стремятся уменьшить риски непрерывной интеграцией (или хотя-бы минимизацией времени жизни фича-бренчей), делая фокус на работающем продукте, а не на разборе полетов «кто удалил баннер» (я уже молчу о том, что в прогрессивном мире такой чендж просто бы не пропустили авто тесты).Инфа по теме jeffkreeftmeijer.com/. arent-you-using-git-flow

Дмитрий, Вы второй раз позволяете себе переходить на личности и не отвечать на прямые вопросы. Да у нас в компании построен бизнес процесс который даёт определённый уровень прозрачности. Я совершенно согласен с тем, что не всем это нужно, и не собираюсь уговаривать всех переходить на аналогичные бизнес процессы.

Я задал простой вопрос, и вместо ответа получил "

Про git-flow интересно, но всё это мы делаем или вручную или с помощью инструментов типа Jira, те же самые feature-branches, hotfixes, releases, интеграции в master и тп.

Я проясню ситуацию. Статья практически в ультимативной форме доказывает, что hg лучше git. Что действительно лучше — это предмет долгих споров и холиваров в самых разных уголках интернета, и я не хочу до этого скатываться. Но аргументы, они надуманны и вымышлены, местами даже врут, именно они привлекли мое внимание, и большую часть я развенчал в посте, с которого началась данная ветвь.

Статья в ультимативной форме доказывет не то что hg лучше git (как раз технически наоборот), а что в конкретном бизнес процессе, с упором на traceability hg подходит лучше, по объективным причинам (их несколько, главная их которой конечно же ветки). На мой вопрос не ответили, отсыл к «куче книг, литературы» не засчитан т к это не решает мою проблему, поверьте, читал. Пусть люди сами переживают за себя, не переживайте так за них: они сами смогут сделать свои выводы. Всё на что Вы сослались это git-flow, который у нас применяется посредством Jira, но проблем указанных мною выше он не решает.

Хорошо, допустим после моих изменений для новой фичи X в ветке валится тест Y, как понять какое бизнес требование тест Y отслеживает? Я должен сформулировать проблему в терминологии: «При попытки реализации фичи X нарушается целостность исполнения бизнес требования Z, с привязанным тестом Y». Что делать далее? Как выяснить какую часть заложенной логике и какие бизнес требования поломались? Большая часть команд валят всё на отдел QA, пусть они сами разбираются. Мне же такой подход претит, он занимает в разы больше времени и не даёт качественного результата, т к метаданные могут отсутствовать (зависит от того, насколько хорошо организвана работа отдела QA). Я же просто избегаю лишних шагов, если есть ветка, могу сказу сказать о том, какое бизнес требование Z будет нарушено в связи с введением новой фичи X и далее инициировать дискуссию бизнес аналитики, QA и меня как разработчика.

dou.ua/. cles/to-kill-the-project тут в соседнем топике коллега составил вам список вредных советов ;)

В статье уже это расписывал, но попытаюсь ещё раз. Как мы работаем — для каждой функционально отдельной фичи делается заглавный таск и своя ветка, привязанная к этому таску. Помимо «фича» веток есть ещё master, stable ветки, первая для интеграции, вторая — текущая версия на продакшн сервере. Далее, коммиты соответсвенно будут или в ветках, или напрямую в master/stable. Вопросы которые я хочу решать оперативно с точки зрения управления проектом — получить список всех изменений, сделанных по этой фиче. Второй вопрос который я могу задать, и хочу получить быстрый ответ — к разработке какой фичи относиться данная строка кода. Как я действую во втором случае — учитывая то, что фичи рождаются в ветках, моей задачей является найти ветку, и далее найти ассоциированый таск, таск может быть самодостаточным, может ссылаться на развёрнутые бизнес требования. Вот такая вот история. git branch —contains показывает с десяток бранчей, в которых находиться данный коммит, ведь с тех пор как коммит попадает в master, а от мастера делаются дальнейшие ветки. Возможно я как то неправильно это применяю? Меня интересует одна ветка, в которой данный коммит попал в код. Т е первая команда которую я запускаю (посредством своего ide конечно же, не буду сейчас на него указывать), получаю список строк кода, рядом коммит в котором последний раз менялась эта строка. Потом даю этот commit аргументом к git branch —contains и в общем случае получаю список всех локальных веток, в которые этот commit входит. Это малоинформативно и не является ответом на тот вопрос, на который я хотел найти ответ. Буду признатален если сможете рассказать как добиться нужного мне результата.

идея то простая — если мы *уже* пользуемся бранчами при создании новых фич, то в дальнейшем можно было бы положиться на эту информацию для раскрутки обратного процесса (см ниже). но суть простая — и польза следующая — допустим заказчик поручает сделать фичу X, программист открывает код, начинает менять, и находит кусок логики, включая unit test который повалится после введения новой логики, для фичи X. Вот тут внимание вопрос — к кому идти с вопросом, и как его сформулировать? я обычно формулирую просто — логика фичи X, противоречит логике фичи Y (нахожу бизнес требование к Y по коммиту, далее таску и связке). Без этой связки фича X конечно заработает, но разборки потом почему логика X поломало Y, Z ложится целиком на плечи QA. Я не привык ломать а потом разбираться, лучше вначале разобраться, и делать свои изменения осознанно, в рамках понимания проекта целиком а не логики отдельной фичи которая делается сейчас

В компаниях работают разные люди, и для «эпизодического» пользователя SCM или того кто переходит с SVN важны вот эти все мелкие детали. Веб-дизайнеру или сисамдину, который работает с репозитарием раз в месяц, реально либо использовать GUI, либо начать с чего-то концептуально простого. Сетевая шара, Drpobox — понятно. SVN — на уровень сложнее. Mercurial — почти космос. Git — космос.

Они не глупые, просто оно им не нужно, как vi.

Не, интеграция по правому клику по файлу — это фигня.

Да вы, батенька, небось и IDE пользуетесь.

На С++ без IDE таки тяжко. То ли дело javascript.

Во-первых, если мы говорим о коммерческой разработке, то тут требование не только VCS системы, а полного флакона, включая CI, какой-то review board и тому подобное, причём связанное между собой. Тут упоминалась JIRA. Я с этим зверем, как со всем Atlassian’овским хозяйством, не сдружился, а на предыдущей работе наблюдал замечательный флакон Gerrit+Jenkins+RequestTracker. (Могу дать координаты, думаю, продадут дешевле, чем решения от JIRA.) И вот там часть обозначенных проблем уже принципиально решена: коммит без номера тикета в трекере просто не будет принят, и используется per-commit peer review (на базе Gerrit). Gerrit же не позволяет просто так удалять ветки, но и не светит их на каждый чих. Ещё из его вкусностей — общий id изменения, проходящий через разные релизные ветки и не меняющийся, как собственно Git commit id.

С другой стороны, старые ветки и нужно переносить в старый репозиторий (IMHO).

Во-вторых, в статье заметное количество фактических ошибок или необоснованных стилевых комментариев по Git. В частности (постараюсь не сильно дублировать уже отписавшихся коллег):

> И, соответственно,удобно, чтобы все рабочие ветки заливались на сервер, что по умолчанию происходит в mercurial.

Ничего в этом хорошего нет, пока идёт локальная работа с формированием правильных коммитов (в которой возможно множество случаев rebase с разделением, слиянием коммитов, правкой уже сделанных).

> В Git, оказывается, есть разделение репозиториев на клоны для девелоперов (рабочие) и клоны для сервера (bare). Это сделано, видимо, в целях оптимизации, но в результате, чтобы обменяться кодом с соседом программистом, мне уже недостаточно будет просто написать hg push ssh://[email protected], а потребуется создать bare репозиторий и организовать обмен кодом на его основе.

Можно свободно делать pull от соседа или push ему в не-текущую ветку и на не-bare репо. В текущую не допускается хотя бы потому, что могут быть конфликты с локальными правками, и удалённый пушер не вправе резолвить эти конфликты. Но из локальной ветки сам владелец запросто заберёт всё, что ему нужно, в пришедшем.

git diff, просто.

git checkout -b branchname origin/branchname

git checkout $branchname (если настроен один дефолтный origin, что тривиально, а в случае создания по clone делается автоматически)

> Мне поначалу было сложно понять, что за origin и почему надо указывать ветку.

Точно так же — есть ремота по умолчанию (и ветку тоже можно строить, или задавать все, или группу по маске)

> Ну и закодированное git config по сравнению с обычным простым файлом .hg/hgrc

С простым файлом $REPO/.git/config или

> Второй минус — к хорошему привыкаешь быстро. Поработав немного с mercurial, возвращаться на git довольно сложно, так как приходится вспоминать зубодробительный синтаксис для простых вещей.

Вкусовщина, но мне строго наоборот — git выучился почти мгновенно, а с Hg всё время проблемы из-за нарушения POLA. До этого были CVS и Subversion, так вот SVN резко сложнее из-за неочевидных подходов, а Git проще SVN, несмотря на особенности от распределённости.

> Тем более, на заведомо более слабую по фичам систему.

Верно. Одно только staging area по удобству использования достаточно, чтобы про Hg не вспоминать.

Valentin, а можете немного расписать как Вы пользуетесь staging area в git, потому как видимо многие этого не понимают, включая меня. У меня простой алгоритм работы — работаю с файлами, добавляю удаляю и тп, и потом делаю commit. Я выборочно могу указать какие файлы и изменения войдут в этот commit, какие нет. Если вдруг необходимо «отложить» коммит, есть команда git stash, аналогичная ей команда hg shelve/unshelve. Т е этого ф-ла мне хватает с головой, и реально staging area, где файлы могут отличаться от того, что реально будет коммититься по моему запутывает ситуацию. Когда именно это востребовано? Т е Вы допустим сделали изменения, готовитесь к commit, но commit не делаете а далее модифицируете файлы, понимаете что это коммититься пока не будете, и коммитите те, что лежат уже в staging? Или я как от не так понимаю?

Вот весь вопрос об уровне выборочности. Представим себе, что над локальной копией по сравнению с состоянием репозитория сделаны следующие изменения:1. Добавление отладочной печати под ловлю конкретного бага (не предназначена для коммита).2. Переименование переменных — для стиля (старое название соответствует ушедшему функционалу). Сам факт отставания названия обнаружен уже когда началось исправление бага.3. Функциональное изменение — правка бага.

В некотором куске кода изменения находятся слишком близко друг к другу и с точки зрения diff относятся к одному чанку. Средствами указания конкретного чанка я не могу их разделить (например, в одной и той же строке поучаствовали правка бага и переименование, а отладочная печать примыкает к ним вплотную). Мне нужно получить коммит на переименование. Добавление целого файла не сработает. stash (shelve) — аналогично. add —patch — аналогично.Работает только один вариант (для Git) — «add -e». Тогда в редактируемом диффе я формирую в этом конкретном чанке только переименование, срезая остальное.

После этого я вижу два диффа — между committed и staging (git diff —cached) — то, что я собираюсь коммитить; между staging и рабочей версией (git diff) — то, что не коммитится (правка бага и отладочная печать). Оба изменения чётко и понятно читаются, и я могу проверить глазами, что в них только необходимая суть каждого. Потом я говорю commit и перехожу к выделению второго изменения (правка бага), срезая из диффа отладочную печать.С этого момента оба изменения локально зафиксированы, я могу сделать какой-нибудь sync на бэкапное хранение, могу сделать push в рабочую копию на сервере. важная часть работы сделана и расшарена. Отладочная печать в этой рабочей копии может оставаться ещё долго для последующей проверки (бывало, не удалял месяцами, пока не начинала явно мешать).

Конечно, можно было сделать это и без staging. Например, позвать stash, повторить переименование (дублирование уже сделанной работы), закоммитить, сделать stash pop и разобрать неизбежные конфликты (вторая дополнительная работа, причём в сильно менее удобном виде, чем при add -e). И зачем себе лишнюю работу делать? Я этих граблей с CVS’ом настрадался.

Не запутывает, если про неё помнить. Вас же не запутывает тот же stash (shelve)? Если нужно тестировать локально то, что предназначено для пуша, потребуется сохранить stash, на неизменённой копии проверить полученное, сделать stash pop для восстановления работы. Так и тут — просто надо знать и помнить свойства инструмента. А кто не помнит, git status покажет факт и просто локального изменения, и чего-то в staging.

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

📎📎📎📎📎📎📎📎📎📎