Hg Init: Учебное пособие по Mercurial.
Mercurial — это современная распределенная система контроля версий с открытым кодом. Эта система — заманчивая замена для более ранних систем вроде Subversion. В этом простом учебном пособии в шести частях Джоэль Спольски (Joel Spolsky) рассказывает о ключевых принципах Mercurial.
Если вы использовали Subversion, то Mercurial будет непонятным. Эта часть рассказывает о главных отличиях при работе с Mercurial. Если вы никогда не использовали Subversion, то можете просто пропустить эту часть.
Часть 1. Переобучение для пользователей Subversion
В каком же я был смятении, когда программисты в моей компании решили сменить Subversion на Mercurial!
Для начала, я начал приводить всевозможные тупые причины, по которым нам не надо ничего менять. «Мы должны хранить репозиторий на центральном сервере, так безопаснее», — сказал я. Знаете что? Я был неправ. При работе с Mercurial у каждого разработчика на жестком диске хранится полная копия репозитория. Это, на самом деле, безопаснее. В любом случае, почти в каждой команде, использующей Mercurial, центральный репозиторий тоже существует. И вы можете делать резервное копирование этого репозитория со всей необходимой одержимостью. А еще можете устроить трехступенчатую защиту с Сайлонами, Штурмовиками и прелестными лабрадудлами или что там требует ваш IT-отдел.
«Проблема с распределенными системами контроля версий в том, что они позволяют слишком легко делать ветки (branch)», — сказал я. «А ветки всегда приносят проблемы». Получается, что тут я тоже был неправ. Волна такая пошла. Ветки несут проблемы при работе с Subversion, потому что Subversion не хранит достаточно информации для того, чтобы слияние (merge) нормально работало. В Mercurial слияние безболезненно и легко, а потому ветвление распространено и безвредно.
Потом я сказал: «Хорошо, я буду использовать эту систему, но не ждите, что я смогу в ней разобраться». И я попросил Джейкоба сделать для меня шпаргалку, в которой будет все, что я обычно делал в Subversion, с указанием аналогов в Mercurial.
Я могу показать вам эту шпаргалку, но не буду, потому что она несколько месяцев мешала моим мозгам перестроиться.
Получается что, если вы использовали Subversion, то ваша голова немного… Э-э-э, как бы помягче сказать? Вы ранены во всю голову! Нет, не получилось. Вам нужно переобучение. Я ходил таким раненным полгода и думал, что Mercurial более сложен, чем Subversion. Но это потому, что я не понимал, как новая система на самом деле работала. Как только я понял, как она работает, оказалось — опа! да это достаточно просто.
Вот я и написал для вас это пособие, в котором очень старался не объяснять все в терминах Subversion, потому что хватит уже раненных во всю голову. Их и так достаточно. Вместо этого, для тех, кто переходит на Mercurial с Subversion, я написал эту часть в начале пособия, которая постарается аннулировать как можно больше вреда, чтобы вы могли изучить Mercurial с чистого листа.
Если вы никогда не использовали Subversion, то можете перейти к следующей статье («Основы Mercurial») и ничего не упустите.
Готовы? Хорошо, начнем с короткого опроса.
Вопрос первый: Вы всегда с первого раза пишите идеальный код?
Если вы ответили «Да» на первый вопрос, то вы врун и жулик. Получите «банан» и приходите на пересдачу.
Новый код глючен. Требуется время, чтобы он начал прилично работать. А пока этот код может повредить остальным разработчикам в команде.
И вот, как работает Subversion:
- Когда вы вносите новый код в репозиторий, его получают все.
Так как весь новый код, который вы пишите, содержит баги, то у вас есть выбор.
- Вы можете вносить глючный код и сводить людей с ума, или
- Вы можете придерживать новый код до тех пор, пока полностью его не отладите.
Subversion постоянно ставит вас перед этим ужасным выбором. Или репозиторий полон глючного кода, потому что содержит новый код, который только что написан, или новый код, что только что написан, не добавлен в репозиторий.
Как пользователи Subversion, мы настолько привыкли к этой дилемме, что трудно представить себе систему, где эта дилемма не существует.
Команда, использующая Subversion, часто днями или неделями ничего не добавляет в репозиторий. В таких командах новички боятся залить что-то в репозиторий из-за опасения поломать билд, или разозлить Майка, ведущего разработчика, или по сходным причинам. Майк однажды так рассердился из-за изменений, которые поломали билд, что ворвался к практиканту, смахнул все с его стола и проорал: «Это твой последний день!». Этот день не был последним, но бедный практикант практически намочил штаны.
Все эти страхи и опасения означают, что люди пишут код неделя за неделей не используя преимуществ системы контроля версий, а затем ищут кого-нибудь опытного, чтобы внести код в репозиторий. И для чего репозиторий, если им нельзя пользоваться?
Вот простая иллюстрация жизни с Subversion:
При работе с Mercurial у каждого разработчика свой собственный репозиторий, живущий у них на компьютере:
Так что вы можете вносить изменения в свой репозиторий и пользоваться всеми благами системы контроля версий, когда захотите. Каждый раз, чуть улучшив код, вы можете вносить его в репозиторий.
Когда код надежен, и вы хотите дать другим его использовать, вы проталкиваете (push) ваши изменения из своего репозитория в центральный репозиторий. Из центрального репозитория каждый вытягивает (pull) общие изменения и рано или поздно все получат ваш новый код. Когда он готов.
Mercurial разделяет момент внесения кода в репозиторий и момент получения этого кода всеми остальными.
И это означает, что вы можете коммитить (
hg com
), но все остальные не получат ваши изменения. Когда у вас накопятся изменения, которые вас устраивают, которые стабильны и все круто, вы проталкиваете (hg push
) их в главный репозиторий.Еще одно большое концептуальное отличие
Вы знаете, что у каждой улицы есть название?
Ну, оказывается что в Японии это не совсем так. Японцы обычно просто нумеруют кварталы между улицами и только очень, очень важные улицы имеют названия.
У Subversion и Mercurial есть сходное различие.
В Subversion мыслят ревизиями. Ревизия — это то, как выглядит вся файловая система в определенный момент времени.
В Mercurial вы мыслите наборами изменений (changesets). Набор изменений — это четкий список изменений между двумя соседними ревизиями.
Шесть того или полдюжины этого — в чем разница?
Вот в чем разница. Представьте, что вы и я вместе работаем над каким-то кодом. И мы сделали ветки этого кода, и каждый пошел на свое место и сделал много-много независимых изменений в коде, так что ветки достаточно сильно разошлись в разные стороны.
Когда нам нужно сделать слияние, Subversion смотрит на обе ревизии — мой измененный код и ваш измененный код — и пытается угадать, как слепить их вместе в один большой страшный бардак. Обычно Subversion это не удается, и получаются длинные списки конфликтов («merge conflicts»), которые на самом деле не конфликты, а просто места, в которых система не смогла разобраться в наших изменениях.
Для сравнения, если мы независимо работали в Mercurial, то система сохраняла серии изменений. Таким образом, когда мы хотим сделать слияние кода, у Mercurial на самом деле гораздо больше информации: система знает, что каждый из нас изменил, и может заново применить эти изменения вместо того, чтобы смотреть на конечный вариант и пытаться угадать, как все это собрать воедино.
Если, для примера, я немного изменил какую-то функцию и перенес ее куда-то, то Subversion на самом деле не помнит этого. Так что когда дело дойдет до слияния, она просто может решить, что в коде из ниоткуда появилась новая функция. В то же время, Mercurial запомнит: функция изменилась, функция переместилась. Это значит, что если вы тоже поменяли эту функцию, то вероятность того, что Mercurial успешно проведет слияние наших изменений, гораздо больше.
Так как Mercurial мыслит в терминах наборов изменений, вы можете делать интересные вещи с этими наборами изменений. Вы можете дать попробовать эти изменения другу вместо того, чтобы вносить эти изменения в центральный репозиторий и вынуждать всех ими пользоваться.
Если все это кажется вам немного запутанным — не переживайте. По мере чтения этого пособия все обретет ясный смысл. В данный момент самое главное, что вам нужно знать: из-за того, что Mercurial оперирует наборами изменений, а не ревизиями, слияние кода в Mercurial работает гораздо лучше, чем в Subversion.
И это значит, что вы можете свободно делать ветки, потому что слияние не будет кошмаром.
Хотите узнать кое-что забавное? Почти у каждой команды, использующей Subversion, с членами которой я разговаривал, есть некий вариант одной и той же истории. История настолько часто встречается, что я просто назову ее «Главной историей про Subversion». Вот эта история: в определенный момент они попробовали сделать ветку в развитии кода. Обычно для того, чтобы версия, которую отдали клиентами, была отделена от версии, с которой возятся разработчики. И все рассказывали мне, что когда они попробовали сделать это, то все было отлично до момента, когда им нужно было сделать слияние. И слияние было кошмаром. То, что должно было быть пятиминутным процессом, превратилось в шесть программистов вокруг одного компьютера, работавших две недели, пытаясь вручную внести каждый багфикс из стабильной ветки в ветку разработчиков.
И почти в каждой команде мне сказали, что они поклялись «больше никогда» и отказались от веток. И теперь они делают так: каждая новая фича в большом
#ifdef
блоке. Так они могут работать всегда в стволе репозитория, а клиенты никогда не получают новый код пока он не отлажен, и, откровенно говоря, это нелепо.Отделять стабильный и разрабатываемый код — это именно то, что система контроля версий должна позволять вам делать.
С переходом на Mercurial, вы можете даже не осознать этого, но ветвление снова станет возможным и вам не нужно будет ничего опасаться.
Это означает, что у вас могут быть командные репозитории, где небольшая команда программистов работает над новой фичей, и, когда все готово, сливает свои изменения в главный репозиторий. И это работает!
Это означает, что у вас могут быть репозитории для службы тестирования, где команда тестеров пробует новый код. Если он работает, то служба тестирования вносит изменения в центральный репозиторий, что, в свою очередь, означает, что в центральном репозитории всегда надежный протестированный код. И это работает!
Это означает, что вы можете проводить эксперименты в отдельных репозиториях, и, если эксперименты удачны, сливать изменения в главный репозиторий, а если неудачны, то просто выбрасывать их. И это работает!
И последнее большое концептуальное отличие
Последнее важное концептуальное отличие между Subversion и Mercurial не такое уж и важное, но оно может поставить вас в неудобное положение, если вы не будете про него знать. Вот оно:
Subversion, по сути, система контроля изменений для файлов, а в Mercurial контроль изменений применяется ко всему каталогу, включая все подкаталоги.
Главным образом, это проявляется так: в Subversion, если вы находитесь в подкаталоге и вносите свои изменения в репозиторий, то вносятся только изменения из этого подкаталога и всех его подкаталогов. Это может привести к тому, что вы забудете внести изменения из другого подкаталога. А в Mercurial все команды всегда применяются ко всему дереву каталогов. Если ваш код находится в c:\code, то когда вы выполняете
hg commit
, то можете находиться в c:\code или в любом подкаталоге — результат будет одним и тем же.Это не так уж важно, но если вы привыкли иметь один гигантский репозиторий на всю компанию, в котором некоторые люди работают только с определенными подкаталогами, которые их касаются, то знайте, что это не самый лучший метод при работе с Mercurial. Вам лучше иметь много меньших по размеру репозиториев на каждый проект.
И напоследок...
Теперь часть, где вы просто должны поверить мне на слово.
Mercurial лучше, чем Subversion.
Лучше, если работать над кодом в команде. Лучше, если работать над кодом в одиночку.
Просто лучше.
И, попомните мои слова, если вы поймете как работает Mercurial, и будете работать так, как работает Mercurial, и не будете бороться с этой системой, и не будете пытаться делать с Mercurial все так же, как делали в Subversion, а вместо этого научитесь работать так, как от вас ожидает Mercurial, то будете счастливы, успешны, упитаны и всегда сможете найти пульт от телевизора.
И поначалу вас будет искушать мысль — я знаю, будет, — бросить Mercurial и вернуться к Subversion. Потому что будет странно, словно вы живете в чужой стране, и вас будет тянуть на родину, и вы будете придумывать всевозможные оправдания вроде того, что будете заявлять, что в Mercurial рабочие копии занимают слишком много места, что есть туфта, так как на самом деле они занимают меньше места, чем в Subversion. Это правда!
И затем вы вернетесь к Subversion, потому что вы пробовали делать ветки так же, как в Subversion, и запутались, и получилось не очень, потому что вы на самом деле должны были делать ветки как в Mercurial, клонируя репозитории, не пытаться делать так, как работало в Subversion, а научиться принятому в Mercurial способу, который, поверьте мне, работает.
И после этого вы попросите Джейкоба, или кто там у вас эквивалент Джейкоба в вашем офисе, дать вам шпаргалку «От Subversion к Mercurial», и вы потратите три месяца, думая, что
hg fetch
это как svn up
, не понимая, на самом деле, что делает hg fetch
, и однажды все пойдет не так, и вы будете винить Mercurial, хотя вам стоило бы винить себя за непонимание того, как работает Mercurial.Я знаю, вы так и сделаете, потому что это то, что я сделал.
Не делайте ту же ошибку. Изучите Mercurial, доверьтесь ему, разберитесь, как делать все в его стиле, и вы продвинетесь на целое поколение в области систем контроля версий. Пока ваши конкуренты тратят неделю на разрешение конфликтов, которые возникли после того, как поставщик обновил библиотеку, вы напечатаете
hg merge
и скажете себе «О, боже, это круто, это просто сработало.» И Майк расслабится и поделится косячком с практикантами, и наступит весна, и молодежь из соседнего колледжа сменит пуховики на коротенькие надорванные футболки, и жизнь будет хороша.Продолжение здесь:
Hg Init: Часть 2. Основы Mercurial