Hg Init: Часть 1. Переобучение для пользователей Subversion

<html> <div class="content">

<h5>Hg Init: Учебное пособие по Mercurial.</h5><br>

<br> <img src="http://habrastorage.org/storage/eebea7f1/5482efc4/01467053/55589e0f.png" align="left">Mercurial — это современная распределенная система контроля версий с открытым кодом. Эта система — заманчивая замена для более ранних систем вроде Subversion. В этом простом учебном пособии в шести частях Джоэль Спольски (<a href="http://www.joelonsoftware.com/">Joel Spolsky</a>) рассказывает о ключевых принципах Mercurial.<br> <br> Если вы использовали Subversion, то Mercurial будет непонятным. Эта часть рассказывает о главных отличиях при работе с Mercurial. Если вы никогда не использовали Subversion, то можете просто <a href="http://habrahabr.ru/blogs/development_tools/108658/">пропустить эту часть</a>.<br> <br> <h4>Часть 1. Переобучение для пользователей Subversion</h4><br> В каком же я был смятении, когда программисты в моей компании решили сменить Subversion на Mercurial!<br> <br> <img src="http://habrastorage.org/storage/33c920fc/5fefe056/7d9c727b/7761db50.png" align="left">Для начала, я начал приводить всевозможные тупые причины, по которым нам не надо ничего менять. «Мы должны хранить репозиторий на центральном сервере, так безопаснее», — сказал я. Знаете что? Я был неправ. При работе с Mercurial у каждого разработчика на жестком диске хранится полная копия репозитория. Это, на самом деле, <i>безопаснее</i>. В любом случае, почти в каждой команде, использующей Mercurial, центральный репозиторий тоже существует. И вы можете делать резервное копирование этого репозитория со всей необходимой одержимостью. А еще можете устроить трехступенчатую защиту с <a href="http://ru.wikipedia.org/wiki/%D0%A1%D0%B0%D0%B9%D0%BB%D0%BE%D0%BD%D1%8B">Сайлонами</a>, Штурмовиками и прелестными <a href="http://en.wikipedia.org/wiki/Labradoodle">лабрадудлами</a> или что там требует ваш IT-отдел.<br> <br> <a name="habracut"></a><br> <br> «Проблема с распределенными системами контроля версий в том, что они позволяют слишком легко делать ветки (branch)», — сказал я. «А ветки всегда приносят проблемы». Получается, что тут я тоже был неправ. Волна такая пошла. Ветки несут проблемы <i>при работе с Subversion</i>, потому что <i>Subversion</i> не хранит достаточно информации для того, чтобы <i>слияние</i> (merge) нормально работало. В Mercurial слияние безболезненно и легко, а потому ветвление распространено и безвредно.<br> <br> Потом я сказал: «Хорошо, я буду использовать эту систему, но не ждите, что я смогу в ней разобраться». И я попросил Джейкоба сделать для меня шпаргалку, в которой будет все, что я обычно делал в Subversion, с указанием аналогов в Mercurial.<br> <br> Я могу показать вам эту шпаргалку, но не буду, потому что она несколько месяцев мешала моим мозгам перестроиться.<br> <br> Получается что, если вы использовали Subversion, то ваша голова немного… Э-э-э, как бы помягче сказать? Вы ранены во всю голову! Нет, не получилось. Вам нужно переобучение. Я ходил таким раненным полгода и думал, что Mercurial <i>более сложен</i>, чем Subversion. Но это потому, что я не понимал, как новая система на самом деле работала. Как только я понял, как она работает, оказалось — опа! да это достаточно просто.<br> <br> Вот я и написал для вас это пособие, в котором очень старался <i>не</i> объяснять все в терминах Subversion, потому что хватит уже раненных во всю голову. Их и так достаточно. Вместо этого, для тех, кто переходит на Mercurial с Subversion, я написал эту часть в начале пособия, которая постарается аннулировать как можно больше вреда, чтобы вы могли изучить Mercurial с чистого листа.<br> <br> <b>Если вы никогда не использовали Subversion, то можете перейти к следующей статье (<a href="http://habrahabr.ru/blogs/development_tools/108658/">«Основы Mercurial»</a>) и ничего не упустите.</b><br> <br> Готовы? Хорошо, начнем с короткого опроса.<br> <br> <blockquote><b>Вопрос первый:</b> Вы всегда с первого раза пишите идеальный код?</blockquote><br> <br> Если вы ответили «Да» на первый вопрос, то вы врун и жулик. Получите «банан» и приходите на пересдачу.<br> <br> Новый код глючен. Требуется время, чтобы он начал прилично работать. А пока этот код может повредить остальным разработчикам в команде.<br> <br> И вот, как работает Subversion:<br> <ul> <li>Когда вы вносите новый код в репозиторий, его получают все.</li> </ul><br> <br> Так как весь новый код, который вы пишите, содержит баги, то у вас есть выбор.<br> <ul> <li>Вы можете вносить глючный код и сводить людей с ума, или</li> <li>Вы можете придерживать новый код до тех пор, пока полностью его не отладите.</li> </ul><br> <br> Subversion постоянно ставит вас перед этим ужасным выбором. Или репозиторий полон глючного кода, потому что содержит новый код, который только что написан, <i>или</i> новый код, что только что написан, не добавлен в репозиторий.<br> <br> Как пользователи Subversion, мы настолько привыкли к этой дилемме, что трудно представить себе систему, где эта дилемма не существует.<br> <br> Команда, использующая Subversion, часто днями или неделями ничего не добавляет в репозиторий. В таких командах новички боятся залить что-то в репозиторий из-за опасения поломать билд, или разозлить Майка, ведущего разработчика, или по сходным причинам. Майк однажды так рассердился из-за изменений, которые поломали билд, что ворвался к практиканту, смахнул все с его стола и проорал: «Это твой последний день!». Этот день не был последним, но бедный практикант практически намочил штаны.<br> <br> Все эти страхи и опасения означают, что люди пишут код неделя за неделей <i>не используя преимуществ системы контроля версий</i>, а затем ищут кого-нибудь опытного, чтобы внести код в репозиторий. И для чего репозиторий, если им нельзя пользоваться?<br> <br> Вот простая иллюстрация жизни с Subversion:<br> <img src="http://habrastorage.org/storage/d15885f7/9ebf875d/5d83d6f4/f6ea14f3.png" align="center"><br> <br> При работе с Mercurial <i>у каждого разработчика свой собственный репозиторий, живущий у них на компьютере:</i><br> <img src="http://habrastorage.org/storage/df9ce736/7f3b9699/aa8bb2bb/b5180086.png" align="center"><br> <br> Так что вы можете вносить изменения в свой репозиторий и пользоваться всеми благами системы контроля версий, когда захотите. Каждый раз, чуть улучшив код, вы можете вносить его в репозиторий.<br> <br> Когда код надежен, и вы хотите дать другим его использовать, вы проталкиваете (push) ваши изменения из своего репозитория в центральный репозиторий. Из центрального репозитория каждый вытягивает (pull) общие изменения и рано или поздно все получат ваш новый код. Когда он готов.<br> <br> <i>Mercurial разделяет момент внесения кода в репозиторий и момент получения этого кода всеми остальными.</i><br> <br> И это означает, что вы можете коммитить (

hg com

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

hg push

) их в главный репозиторий.<br> <br> <h5>Еще одно большое концептуальное отличие</h5><br> <br> Вы знаете, что у каждой улицы есть название? <br> <br> <img src="http://habrastorage.org/storage/0a94d9a4/417a4639/b4495b24/db298b24.png" align="right">Ну, оказывается что в Японии это не совсем так. Японцы обычно просто <a href="http://sivers.org/jadr">нумеруют кварталы</a> между улицами и только очень, очень важные улицы имеют названия.<br> <br> У Subversion и Mercurial есть сходное различие.<br> <br> В Subversion мыслят <i>ревизиями</i>. Ревизия — это то, как выглядит вся файловая система в определенный момент времени.<br> <br> В Mercurial вы мыслите <i>наборами изменений (changesets)</i>. Набор изменений — это четкий список изменений между двумя соседними ревизиями.<br> <br> Шесть того или полдюжины этого — в чем разница?<br> <br> Вот в чем разница. Представьте, что вы и я вместе работаем над каким-то кодом. И мы сделали ветки этого кода, и каждый пошел на свое место и сделал много-много независимых изменений в коде, так что ветки достаточно сильно разошлись в разные стороны.<br> <br> Когда нам нужно сделать слияние, Subversion смотрит на обе ревизии — мой измененный код и ваш измененный код — и пытается угадать, как слепить их вместе в один большой страшный бардак. Обычно Subversion это не удается, и получаются длинные списки конфликтов («merge conflicts»), которые на самом деле не конфликты, а просто места, в которых система не смогла разобраться в наших изменениях.<br> <br> Для сравнения, если мы независимо работали в Mercurial, то система сохраняла <i>серии изменений</i>. Таким образом, когда мы хотим сделать слияние кода, у Mercurial на самом деле гораздо больше информации: система знает, <i>что каждый из нас изменил</i>, и может <i>заново применить эти изменения</i> вместо того, чтобы смотреть на конечный вариант и пытаться угадать, как все это собрать воедино.<br> <br> Если, для примера, я немного изменил какую-то функцию и перенес ее куда-то, то Subversion на самом деле не помнит этого. Так что когда дело дойдет до слияния, она просто может решить, что в коде из ниоткуда появилась новая функция. В то же время, Mercurial запомнит: функция изменилась, функция переместилась. Это значит, что если вы тоже поменяли эту функцию, то вероятность того, что Mercurial успешно проведет слияние наших изменений, гораздо больше.<br> <br> Так как Mercurial мыслит в терминах наборов изменений, вы можете делать интересные вещи с этими наборами изменений. Вы можете дать попробовать эти изменения другу вместо того, чтобы вносить эти изменения в центральный репозиторий и вынуждать всех ими пользоваться.<br> <br> Если все это кажется вам немного запутанным — не переживайте. По мере чтения этого пособия все обретет ясный смысл. В данный момент самое главное, что вам нужно знать: из-за того, что Mercurial оперирует наборами изменений, а не ревизиями, <i>слияние кода в Mercurial работает гораздо лучше, чем в Subversion</i>.<br> <br> И это значит, что <i>вы можете свободно делать ветки</i>, потому что слияние не будет кошмаром.<br> <br> Хотите узнать кое-что забавное? Почти у каждой команды, использующей Subversion, с членами которой я разговаривал, есть некий вариант одной и той же истории. История настолько часто встречается, что я просто назову ее «Главной историей про Subversion». Вот эта история: в определенный момент они попробовали сделать ветку в развитии кода. Обычно для того, чтобы версия, которую отдали клиентами, была отделена от версии, с которой возятся разработчики. И все рассказывали мне, что когда они попробовали сделать это, то все было отлично <i>до момента, когда им нужно было сделать слияние</i>. И слияние было кошмаром. То, что должно было быть пятиминутным процессом, превратилось в шесть программистов вокруг одного компьютера, работавших две недели, пытаясь вручную внести каждый багфикс из стабильной ветки в ветку разработчиков.<br> <br> И почти в каждой команде мне сказали, что они поклялись «больше никогда» и отказались от веток. И теперь они делают так: каждая новая фича в большом

#ifdef

блоке. Так они могут работать всегда в стволе репозитория, а клиенты никогда не получают новый код пока он не отлажен, и, откровенно говоря, это нелепо.<br> <br> Отделять стабильный и разрабатываемый код — <i>это именно то, что система контроля версий должна позволять вам делать</i>.<br> <br> С переходом на Mercurial, вы можете даже не осознать этого, но ветвление снова станет возможным и вам не нужно будет ничего опасаться.<br> <br> Это означает, что у вас могут быть командные репозитории, где небольшая команда программистов работает над новой фичей, и, когда все готово, сливает свои изменения в главный репозиторий. И <i>это работает</i>!<br> <br> Это означает, что у вас могут быть репозитории для службы тестирования, где команда тестеров пробует новый код. Если он работает, то служба тестирования вносит изменения в центральный репозиторий, что, в свою очередь, означает, что в центральном репозитории всегда надежный протестированный код. И <i>это работает</i>!<br> <br> Это означает, что вы можете проводить эксперименты в отдельных репозиториях, и, если эксперименты удачны, сливать изменения в главный репозиторий, а если неудачны, то просто выбрасывать их. И <i>это работает</i>!<br> <br> <h5>И последнее большое концептуальное отличие</h5><br> <br> Последнее важное концептуальное отличие между Subversion и Mercurial не такое уж и важное, но оно может поставить вас в неудобное положение, если вы не будете про него знать. Вот оно:<br> <br> Subversion, по сути, система контроля изменений для <i>файлов</i>, а в Mercurial контроль изменений применяется ко всему каталогу, включая все подкаталоги.<br> <br> Главным образом, это проявляется так: в Subversion, если вы находитесь в подкаталоге и вносите свои изменения в репозиторий, то вносятся только изменения из этого подкаталога и всех его подкаталогов. Это может привести к тому, что вы забудете внести изменения из другого подкаталога. А в Mercurial все команды всегда применяются ко всему дереву каталогов. Если ваш код находится в <b>c:\code</b>, то когда вы выполняете

hg commit

, то можете находиться в <b>c:\code</b> или <i>в любом подкаталоге</i> — результат будет одним и тем же.<br> <br> Это не так уж важно, но если вы привыкли иметь один гигантский репозиторий на всю компанию, в котором некоторые люди работают только с определенными подкаталогами, которые их касаются, то знайте, что это не самый лучший метод при работе с Mercurial. Вам лучше иметь много меньших по размеру репозиториев на каждый проект.<br> <br> <h5>И напоследок…</h5><br> <br> Теперь часть, где вы просто должны поверить мне на слово.<br> <br> Mercurial лучше, чем Subversion.<br> <br> Лучше, если работать над кодом в команде. Лучше, если работать над кодом в одиночку.<br> <br> Просто <i>лучше</i>.<br> <br> И, попомните мои слова, если вы поймете как работает Mercurial, и будете работать так, как работает Mercurial, и не будете бороться с этой системой, и не будете пытаться делать с Mercurial все так же, как делали в Subversion, а вместо этого научитесь работать так, как от вас ожидает Mercurial, то будете счастливы, успешны, упитаны и всегда сможете найти пульт от телевизора.<br> <br> И поначалу вас будет искушать мысль — я знаю, будет, — бросить Mercurial и вернуться к Subversion. Потому что будет странно, словно вы живете в чужой стране, и вас будет тянуть на родину, и вы будете придумывать всевозможные оправдания вроде того, что будете заявлять, что в Mercurial рабочие копии занимают слишком много места, что есть туфта, так как на самом деле они занимают меньше места, чем в Subversion. Это правда!<br> <br> И затем вы вернетесь к Subversion, потому что вы пробовали делать ветки так же, как в Subversion, и запутались, и получилось не очень, потому что вы на самом деле должны были делать ветки как в Mercurial, клонируя репозитории, не пытаться делать так, как работало в Subversion, а научиться принятому в Mercurial способу, который, поверьте мне, <i>работает</i>.<br> <br> И после этого вы попросите Джейкоба, или кто там у вас эквивалент Джейкоба в вашем офисе, дать вам шпаргалку «От Subversion к Mercurial», и вы потратите три месяца, думая, что

hg fetch

это как

svn up

, не понимая, на самом деле, что делает

hg fetch

, и однажды все пойдет не так, и вы будете винить Mercurial, хотя вам стоило бы винить себя за непонимание того, как работает Mercurial.<br> <br> Я знаю, вы так и сделаете, потому что это то, что я сделал.<br> <br> Не делайте ту же ошибку. Изучите Mercurial, доверьтесь ему, разберитесь, как делать все в его стиле, и вы продвинетесь на целое поколение в области систем контроля версий. Пока ваши конкуренты тратят неделю на разрешение конфликтов, которые возникли после того, как поставщик обновил библиотеку, вы напечатаете

hg merge

и скажете себе «О, боже, это круто, это просто сработало.» И Майк расслабится и поделится косячком с практикантами, и наступит весна, и молодежь из соседнего колледжа сменит пуховики на коротенькие надорванные футболки, и жизнь будет хороша.<br> </html>

Продолжение здесь: Hg Init: Часть 2. Основы Mercurial