Управление версиями: распределённые системы

Главные вкладки

Аватар пользователя axel axel 15 июня 2006 в 13:21

Короткое предисловие

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

  1. Зачем нужны другие системы, когда есть Subversion?
  2. А что, есть что-то кроме CVS? (вариант "кроме Visual Source Safe?")
  3. А что это такое?

Проще один раз ответить и потом давать ссылки. Однако, если вы знаете ответы на вопросы 2 и 3 - пропустите введение. Если ответ на вопрос 1 для вас очевиден и бесспорен - пропустите статью целиком.

Введение в управление версиями

Ни один серьёзный проект сегодня не обходится без отслеживания истории своих изменений; очень полезно знать, что было день назад, что месяц назад, иметь возможность возвратить код к предыдущему более стабильному состоянию или по количеству сделанных за промежуток времени изменений оценить продуктивность работы. Практически все системы управления версиями основываются на механизме разниц (diffs) между файлами и применении этих изменений к файлам для их приведения к новой версии. Способ приложения изменений называется патчем (patch). Наиболее просто это применимо к текстовым файлам - документации, исходным текстам программ и т.п., хотя с некоторыми оговорками вполне можно использовать для бинарных файлов (собственно тексты по сути ведь бинарные данные). Структура и содержимое файла как правило не имеет значения - консистентность данных до и после применения патча является заботой разработчика (если быть точным, это не всегда так, но в нашем объяснении проще принять такую точку зрения). Далее под файлами мы будем подразумевать текстовые файлы.

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

Подробности:
ru.wikipedia.org/wiki/Патч_(программный)

Как это работает? Допустим мы заменяем в тексте несколько вхождений слова "яблоки" на слово "апельсины", а "вишни" заменяем на "лимоны" и получаем новую версию файла - разница между текстами только в нескольких словах. Допустим также, у нас есть ещё одна модификация исходного документа, с какими-то иными отличиями, но всё с теми же "яблоками" и "вишнями", которые нам надо заменить нашими цитрусовыми. Очевидно в данном случае проще всего применить замену в текстовом редакторе, но поскольку наша цель продемонстрировать механизм работы патчей мы пойдём длинным путём - решим, что функции замены в редакторе у нас нет. Как будет сравнивать два больших похожих друг на друга документа человек? Поищет какие-нибудь ориентиры - номера страниц, заголовки или за их отсутствием какие-то приметные места в тексте - иначе говоря будет разбирать контекст и найдя похожие фразы в них заменять найденные слова. По аналогичному алгоритму действуют программы, автоматизирующие этот процесс - они определяют уникальный контекст в документе, обычно это какие-то части текста вокруг заменяемых слов (а в наиболее примитивном варианте - номера строк, где нужно произвести изменения). Затем при применении патча в другом документе ищется аналогичный контекст и если он найден, производится замена. Таким же способом производится добавление или удаление текста. Замена, вставка и удаление - мы получаем три необходимых операции для любых преобразований текста. Очевидно, что для полностью различных текстов, не имеющих общего контекста попытка применения таких изменений не будет удачной, но в реальной практике возникает потребность в изменении чем-то сходных текстов - разных версий документа или исходного текста программы. Тут перенос довольно значительных изменений вручную может быть чреват ошибками, автоматизация позволяет значительно ускорить процесс (гораздо значительней, чем может показаться на первый взгляд).

Ближе к практике. В юниксе имеется пара утилит diff и patch - по именам видно, чем они занимаются. С помощью diff мы можем получить разницу между текстами, а с помощью patch применить эту разницу к другому тексту:

$ diff file-vers1.txt file-vers2.txt > vers1-vers2.diff
$ patch other-file.txt vers1-vers2.diff > other-file-new-vers.txt

Для справки (для понимания механизма это можно опустить) привожу более употребимый вариант синтаксиса:

$ diff -u file-old.txt file.txt > vers1-vers2.diff
$ patch -p0 < vers1-vers2.diff

Почему так? Прочтите man diff и man patch, отмечу только что унифицированный формат (unified diff, заданный параметром -u) является как бы стандартом де факто при обмене патчами - в отличие от разницы выдаваемой по умолчанию, в унифицированном формате учитывается окружающий текст, а не только номера строк. Это позволяет применять патчи к уже изменённым текстам, где заменяемый фрагмент может иметь другие номера строк.

Пример как выглядит разница для двух похожих текстов:

исходная версия - test1.txt добавили одну строку и удалили другую - test2.txt так выглядит unified diff
строка 1
строка 2
строка 3
строка 4
строка 5

и ещё раз:
строка 1
строка 2
строка 3
строка 4
строка 5
строка 1
строка 2
строка 3
новая строка
строка 4
строка 5

и ещё раз:
строка 1
строка 2
строка 3
строка 4
--- test1.txt   2006-06-15 14:04:36.000000000 +0400
+++ test2.txt   2006-06-15 14:05:05.000000000 +0400
@@ -1,6 +1,7 @@
 строка 1
 строка 2
 строка 3
+новая строка
 строка 4
 строка 5

@@ -9,5 +10,4 @@
 строка 2
 строка 3
 строка 4
-строка 5

Возвращаемся к системам управления версиями (они же кратко VCS - от version control system). Основываясь на механизме изменений и патчей VCS хранит всю историю изменений документа или набора документов, позволяя получить патч и приложить его к другому документу или "откатиться" по истории к любой старой версии документа. Фактически это дальнейшая надстройка над diff и patch, позволяющая автоматизировать работу с ними.

Подробности:
ru.wikipedia.org/Система_управления_версиями
en.wikipedia.org/wiki/Revision_control

Первой системой такого рода была SCCS (Source Code Control System), разработанная в 1972 году в Bell Labs, а первая свободная реализация появилась в 80х годах - это была RCS (Revision Control System).

Подробности:
en.wikipedia.org/wiki/SCCS
en.wikipedia.org/wiki/Revision_Control_System

Работа с VCS осуществляется с помощью специальных программ, позволяющих сохранить файл в хранилище (репозитории), находящемся в ведении VCS. Либо в современных системах это может делаться прозрачно для пользователя - на файловой системе, где файлы реально хранятся в VCS или синхронизируются с ней. Другим примером управления версиями применительно к документам в интернете являются движки Wiki.

Подробности:
en.wikipedia.org/wiki/Versioning_file_system
en.wikipedia.org/wiki/Wiki

Хотя основное применение систем управления версиями - разработки программного обеспечения, ничего не мешает использовать их для любой деятельности связанной с написанием документации и вообще любых текстов (кто знает, может быть кто-нибудь из современных поэтов или писателей на самом деле хранит свои шедевры в домашнем репозитории subversion? - тогда потомки с интересом рассмотрят в будущем историю его творчества).

Централизованные системы

Классический пример системы, который наверняка вспомнят, если речь идёт об управлении версиями - CVS (Concurrent Versioning System). Эта система издавна пользуется популярностью, ввиду своей открытости (свободная лицензия GPL, хотя и не с начала разработки, но по сию пору), стабильности и многоплатформенности. Под неё написано огромное количество сервисных программ, графических клиентов и т.п. Это также классический пример централизованной модели - CVS предоставляет сервер с репозиториями файлов, с помощью клиентских программ можно обращаться к этим хранилищам и получать к себе рабочие копии файлов, изменять их и отправлять обратно на сервер, где они получат новые номера версий. С помощью клиентского п/о можно отслеживать всю историю изменений каждого файла в репозитории. В общем, клиент-сервер в чистом виде. CVS можно рассматривать как дальнейшее развитие RCS - если в RCS история изменений велась для одного файла, то CVS позволяет удобней работать со множеством файлов, при этом в расчёт принята коллективная работа - сервер CVS обеспечивает авторизацию для работы многих пользователей с репозиторием. Тем не менее, CVS обладает рядом неприятных недостатков, которые есть вероятно следствие древности разработки этой системы. В CVS нет возможности переименовать файл (можно только удалить и добавить его вновь), то же относится к директориям. Для разработок программного кода неудобством является сложность разделения кода на ветви разработки. В CVS есть возможность организации веток, но если её пользовательский интерфейс сравнить с реализациями в более поздних системах, то работать с CVS больше не захочется.

Подробности:
en.wikipedia.org/wiki/Concurrent_Versions_System

Весьма большую популярность приобрела система Subversion, в которой устранены недостатки CVS. Собственно, как замена CVS эта система и декларируется. Это также продукт под свободной лицензией, что сделало Subversion широко применимой как в коммерческих так и в некоммерческих проектах. Нет проблем с переименованием файлов, легко создаются новые ветки кода и пометки (tags) к файлам, много дополнительных программ и GUI для разных платформ. Другим важным отличием Subversion (как и других поздних VCS) является возможность работы с наборами изменений (changesets или atomic commits), суть которых в занесении или отмене изменений сразу для многих файлов. Это подразумевает идею, что более важно знать что изменено, чем помнить где именно (в каких файлах) эти изменения произошли. Например сменив имя переменной во всех файлах проекта мы можем внести это изменение кода одной транзакцией и позже в истории логично видеть это как одно целостное изменение, а имена файлов являются уже второстепенным вопросом.

Подробности:
en.wikipedia.org/wiki/Subversion_(software)
subversion.tigris.org

Чего ещё желать от системы управления версиями, если в Subversion так всё хорошо?

Распределённые системы

Отличие таких систем - отсутствие центрального репозитория, к которому обращаются клиентские программы; репозиториев может быть много и между ними существует возможность синхронизации. Такой механизм работы даёт больше свободы разработчику, вместо получения рабочей копии и её отправки обратно в центральный репозиторий разработчик может получить репозиторий в своё полное владение - вносить изменения на своё усмотрение и только отдельные изменения синхронизировать с основным репозиторием.

Отдельные распределённые системы, как Bazaar-NG или Darcs упрощают механизм копирования репозиториев по максимуму. Одной командой можно забрать репозиторий к себе, но если в CVS и Subversion вы получите клиентскую копию, то в Bazaar и Darcs вы получаете по сути точную копию исходного репозитория. Из полученной копии легко сделать свой публичный репозиторий, скопировав все файлы исходного (включая служебные файлы относящиеся к VCS, которые хранятся обычно в специальной поддиректории) и выложить в любое доступное по протоколу http место - хоть на любой бесплатный хостинг; с помощью клиентского п/о с новым репозиторием можно будет работать как с исходным. Правда для доступа на запись в него придётся потратить больше усилий - предоставить доступ по ssh (в случае Darcs) или ftp (в случае Bazaar-NG). Особенно интересна эта модель для проектов свободного п/о, где часто разработка ведётся стихийно, без чётких сроков и планов, могут меняться лидеры проекта и имеющиеся в наличии ресурсы. Лёгкость создания копии репозитория в этом случае повышает надёжность в хранении кода - потеря "центрального" ресурса или уход лидера облегчит продолжение проекта, если остались другие заинтересованные разработчики, имеющие собственные копии репозиториев - одно дело текущий срез данных, другое наличие репозитория с полной историей изменений.

Подробности:
en.wikipedia.org/wiki/Bzr
en.wikipedia.org/wiki/Darcs

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

Ещё одна важная особенность, которая чаще встречается в распределённых системах (хотя нет препятствий для её реализации и в централизованной модели) - работа в офлайне. Вы вносите изменения и "отправляете" их в репозиторий находясь без подключения к сети - на самом деле система складывает их куда-нибудь на диске, а при наличии доступа в сеть - отправляет все отложенные изменения в репозиторий. Реализация здесь отличается для разных систем. Часть распределённых систем разделяют сервер и клиента - так например сделано в Codeville. Там отложенные изменения сохраняются на клиентской стороне (хотя по идее клиент и сервер могут быть на одной машине). А скажем в упомянутой выше Darcs, где любая копия сама себе репозиторий, такой механизм вовсе не требуется, поскольку вы всегда вносите изменения локально, а при наличии доступа в сеть переносите изменения из одного репозитория в другой. В любом случае, возможность такой офлайновой работы есть очень полезное свойство VCS. Не требуется оно только если все разработчики сидят в одном офисе, имеют постоянное подключение к сети и предпочитают вне офиса в код не лазить.

Подробности:
en.wikipedia.org/wiki/Codeville

Значит ли вышесказанное, что распределённые системы предназначены исключительно для стихийных opensource-проектов, в то время как централизованную модель следует использовать в корпоративных разработках? Конечно, нет. В зависимости от принятой организации работ в фирменных разработках вполне применима распределённая модель - например если программисты работают дистанционно, через интернет или имеют привычку работать в разных офисах, дома и т.п. Распределённый репозиторий, который легко "унести" на ноутбуке даёт разработчику больше свободы и при этом сохраняет возможность содержать один "главный" репозиторий, куда в итоге должны стекаться все разработки.

Подробности:
bazaar-vcs.org/DecentralizedArguments
blog.ianbicking.org/distributed-vs-centralized-scm.html
jblack.linuxguru.net/node/33
jblack.linuxguru.net/node/34

Для исторической справки. Первой распределённой системой была TeamWare - разработка Sun Microsystems, использовавшаяся большей частью для внутренних проектов фирмы. Тот же разработчик, что проектировал TeamWare позже создал BitKeeper - другую рапспределённую систему под проприетарной лицензией, долгое время использовавшуюся командой разработчиков ядра GNU Linux. Первая свободная реализация распределённой VCS - GNU Arch. Основная критика в адрес Arch - сложность в установке и использовании (команда tla, с помощью которой управляется Arch предлагает слишком уж много параметров и опций, не отличающихся стройностью логики, да ещё странные соглашения по именам файлов). Это послужило появлению позже альтернатив Arch, первыми из которых стали ArX и Bazaar.

Подробности:
en.wikipedia.org/wiki/TeamWare
en.wikipedia.org/wiki/GNU_arch

Что у нас есть более современного? Систем много, но выбор сделать нелегко, ввиду похожести разных продуктов по функциям, а в случае свободных реализаций ещё часто их недоработанности в деталях. Под "деталями" здесь подразумеваются например такие необязательные, но весьма желательные вещи, как наличие GUI, вебинтерфейса и т.п. - где-то есть одно, нет другого. Лидера, каким выглядит Subversion среди свободных централизованных систем, здесь пока не предвидится.

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

Подробности:
en.wikipedia.org/wiki/SVK
svk.elixus.org

Есть подобное дополнение и для CVS, делающее её распределённой системой (хотя не факт, что это делает CVS удобней) - это DCVS.

Подробности:
www.elegosoft.com/index_dcvs.html

Можно обратить своё внимание на системы изначально проектировавшиеся, чтобы быть распределёнными. К тому же они как правило очень просты в установке (к примеру Darcs под Linux есть в статической сборке подходящей под любой дистрибутив - в виде одного файла, который достаточно скопировать к себе на машину получив клиент и сервер в одном флаконе). На мой взгляд наиболее доработанными по функционалу являются Bazaar-NG, Darcs, Mercurial, Monotone. А может быть в итоге вы решите, что централизованная модель вас устраивает больше и возможностей Subversion или другой централизованной системы вам достаточно.

Подробности:
www.dwheeler.com/essays/scm.html - сравнение разных VCS
bazaar-vcs.org
darcs.net
www.selenic.com/mercurial/wiki/
www.venge.net/monotone/

Откровено говоря, я побоялся утонуть в этом многообразии реализаций, поэтому не буду далее углубляться и оставлю другие продукты из предлагаемых на сегодня проприетарных и свободных VCS за бортом повествования. Однако для умеющих хорошо плавать ссылка ниже.

Подробности:
en.wikipedia.org/wiki/List_of_revision_control_software

TODO: Управление версиями на примере Darcs

Комментарии

Аватар пользователя rgb rgb 16 июня 2006 в 10:48

Cпасибо за эту статью. Пользуюсь CVS достаточно долгое время, но теперь ищу замену. Смотрел в сторону SubVersion, а на распределённые системы как-то не обращал внимания (недооценил). Эта вводная заставила пересмотреть позицию.

Ещё раз - большое спасибо, Axel!