CVS - система управления версиями

Автор статьи: Алексей Махоткин
Сайт Автора: cpp.com.ua
E-mail Автора: нет
Дата публикации: 15.03.2006

Введение

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

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

В этой статье речь пойдет о cvs (concurrent versions system) - одной из систем управления версиями, существующих на рынке. Я впервые начал использовать cvs около трех лет назад, программируя на delphi, но имея довольно плотный опыт работы под linux. С тех пор я сменил область деятельности на программирование для web, участвовал в проектах с несколькими разработчиками, и использовал cvs в каждом своем проекте, сколь бы невелик он был, и даже сколь мало он ни был бы связан с собственно программированием. Признаться, сейчас я вообще не представляю себе, как можно программировать, если не контролируешь собственные исходники: даже этот небольшой текстовый файл со статьей уже имеет ревизию 1.1.

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

Повседневное использование

Если ваша операционная система - linux, то, скорее всего, cvs уже установлена на вашей машине или же может быть установлена в мгновение ока с помощью менеджера пакетов. Если вы используете windows, то сходите на http://www.cvsgui.org/, и скачайте там клиента и графическую оболочку к нему (если хотите). Создайте репозиторий, руководствуясь инструкциями из обширной документации к cvs.

Теперь начнем создавать где-нибудь в отдельном каталоге (не каталоге с репозиторием!) рабочую копию. Создадим каталог для нашего проекта:

$ cvs co -l .
$ mkdir hello

и поместим его в репозиторий:

$ cvs add hello
directory /home/cvsroot/hello added to the repository

Создадим внутри этого каталога файл с нашей программой:

=== hello.c ===
#include
int main() {
printf("hello worldn");
}
=== hello.c ===

и поместим этот файл под контроль версий:

$ cvs add hello.c
cvs add: scheduling file `hello.c' for addition
cvs add: use 'cvs commit' to add this file permanently

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

$ cvs commit -m "first revision" hello.c
rcs file: /home/cvsroot/myproject/hello.c,v
done
checking in hello.c;
/home/cvsroot/myproject/hello.c,v <-- hello.c
initial revision: 1.1
done

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

=== hello.c ===
#include
int main() {
printf("hello, world!n");
}

=== hello.c ===
Что же изменилось? Спросим у cvs:
$ cvs diff -u hello.c
index: hello.c
===================================================================
rcs file: /home/cvsroot/myproject/hello.c,v
retrieving revision 1.1
diff -u -r1.1 hello.c
--- hello.c 2001/01/23 22:16:35 1.1
+++ hello.c 2001/01/23 22:19:08
@@ -1,5 +1,5 @@
#include
int main() {
- printf("hello worldn");
+ printf("hello, world!n");
}

Вот в таком вот формате ("унифицированном diff-формате") cvs показывает нам изменения, произошедшие с файлом с того момента, когда он последний раз "фиксировался" в репозиторий. Легко видеть, что одна строка в файле была изменена: мы видим ее старое и новое состояния. Теперь, когда приветствием, выводимым программой, будет доволен любой корректор, можно зафиксировать и это изменение с помощью все той же команды:

$ cvs commit -m "improved greeting" hello.c

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

  • добавление файла в проект (cvs add);
  • удаление его из проекта при помощи команды cvs remove (заметьте, что вся история изменений в этом файле будет сохранена!);
  • просмотр изменений (cvs diff);
  • фиксация изменений в репозитории (cvs commit);
  • на должность пятой команды в данном случае претендуют почти все остальные команды в зависимости от личных предпочтений.

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

Например, самый распространенный случай: исправлена ошибка. Следует просмотреть изменения (в этот момент вас могут поджидать самые любопытные сюрпризы, например, после многочасовой отладки вдруг может выясниться, что все изменение свелось к двум строкам в двух разных файлах, хоть вы и редактировали десяток этих файлов в поисках ошибки). Теперь нужно зафиксировать изменение, причем обязательно документировать его: cvs запустит для вас редактор и предложит ввести журнальное сообщение. Если вы вдобавок пользуетесь системами отслеживания ошибок (а это тема для отдельной статьи), то журнальное сообщение - отличное место, куда можно вписать номер исправленной ошибки или, например, ссылку на письмо, в котором пользователь сообщил об исправленной ошибке.

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

Несколько ветвей разработки

Через несколько месяцев, когда вы более-менее освоитесь с повседневным использованием cvs, вам все чаще станут вспоминаться виденные когда-то в документации и в речи старших товарищей словосочетания "стабильная ветка", "сольем изменения на ствол", "поддержка старых версий". Это означает, что вы уже готовы программировать одновременно две версии своей программы. Одна - стабильная, которая уже работает у заказчика, но время от времени требует небольших исправлений или доработок. Вторая - та, разработку которой вы продолжаете, которая будет называться версией 2.0, содержит новые возможности или вообще почти полностью переписана. На помощь приходит cvs, которая с самого начала разрабатывалась для поддержки нескольких ветвей разработки программы.

В какой-то момент вы объявляете, что выпущена hello version 1.0. Дистрибутив программы отправлен пользователю, а вам самое время приготовиться к дальнейшей разработке. Пометьте текущее состояние исходников:

$ cvs rtag hello-1-0-release hello

Во-первых, теперь вы всегда сможете вернуться к состоянию программы на момент релиза с помощью команды

$ cvs co -r hello-1-0-release hello

Во-вторых, что важнее, теперь вы сможете создать ветку разработки, в которой будете вести поддержку программы (выпуская версии 1.01, 1.02 и т. д.). Для этого используется команда cvs rtag с ключом -b:

$ cvs rtag -b -r hello-1-0-release hello-1-0 hello

Теперь в вашей текущей рабочей копии можно продолжать активную разработку hello version 2. Одновременно с этим от пользователя начнут поступать запросы на исправление ошибок, небольшие доработки etc. Создайте себе еще одну рабочую копию в каталоге hello-support:

$ cvs co -r hello-1-0 -d hello-support hello

Эта рабочая копия "помнит" о том, что при ее извлечении использовался идентификатор ветки (hello-1-0), и теперь все исправления, которые вы сделаете и зафиксируете, окажутся именно на ветке, не затрагивая основной ствол разработки. И наоборот, изменения, вносимые в вашу основную рабочую копию, не окажут влияния на ветки, которые существуют в репозитории.

Несколько разработчиков

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

$ cvs update

Если вдруг случайно Петя и Вася бросятся исправлять один и тот же кусок кода, и сделают это по-разному (сама по себе эта ситуация указывает на недостаток общения Пети и Васи друг с другом), то cvs обработает и эту ситуацию. Когда Петя зафиксирует свое исправление, cvs позволит ему сделать это. Когда Вася попытается зафиксировать свой вариант исправления, cvs обнаружит, что эти исправления перекрываются, и предложит ему обновить рабочую копию с помощью cvs update. Эта команда покажет, что в исправляемом файле произошел так называемый "конфликт" и пометит место конфликта в рабочей копии этого файла. Предположим, Петя решил, что важнее исправить синтаксис выводимого сообщения, а Вася -- что нужно использовать более простую функцию puts(). Конфликт будет выглядеть примерно так:

<<<<<<<<
printf("hello, world!n");
=========
puts("hello world!");
>>>>>>>>

Васе следует обсудить с Петей причину конфликта, договориться, какое из изменений важнее (или просто объединить их), затем убрать индикаторы конфликта (строчки из символов "больше", "меньше" и "равно"), оставить лучший из двух вариантов и, если нужно, зафиксировать окончательное изменение.

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

Заключительная часть

cvs необычайно широко применяется при разработке подавляющего большинства современных проектов с открытым исходным текстом. Среди огромного списка операционных систем и программ: freebsd, xemacs, xfree86, openssl, выделяется, пожалуй, лишь ядро linux, главный разработчик которой, Линус Торвальдс, в силу особенностей личности отказывается использовать какую бы то ни было систему управления версиями, кроме собственного мозга. Да и то, почти все остальные участники разработки держат свой собственный cvs-репозиторий, которым активно пользуются при разработке (здесь им помогает интересная возможность cvs: т. н. "ветки поставщика" (vendor branches)). Проект http://sourceforge.net/, обеспечивающий свободно доступную инфраструктуру для разработчиков свободного программного обеспечения, в качестве стандартной возможности предоставляет использование своего cvs-сервера. Вообще, количество инсталляций и пользователей -- одно из значительных преимуществ cvs.

Альтернативы

На рынке свободно распространяемых программ cvs практически нет конкурентов. Однако из-за почтенного возраста (первые версии cvs появились в 1986 г.) появилась небольшая, но ясно видная ниша для конкурирующих продуктов. Дело в том, что cvs не поддерживает несколько удобных (некоторые даже считают их критичными) возможностей, например, версионность каталогов - отслеживание истории файлов с учетом их переименования, а также поддержку "наборов изменений" (changesets). Кроме того, разработка cvs в последнее время несколько приостановилась, в нем давно не появляется новых крупных возможностей (впрочем, это не означает, что существующих возможностей не хватает). Есть несколько коммерческих продуктов, поддерживающих примерно тот же набор возможностей, что и cvs. Два, на мой взгляд, самых известных - это perforce (http://www.perforce.com/) и rational clearcase (http://www.rational.com/). В конце статьи приведена ссылка на каталог, содержащий ссылки на большое количество систем управления версиями.


В настоящий момент активно ведется разработка того, что когда-нибудь придет на смену cvs: http://subversion.tigris.org/. Этот проект, subversion, разрабатывается с учетом положительных сторон cvs, у него новое, не страдающее от "старческих болезней", дерево исходников, некоторые из его разработчиков в прошлом участвовали в разработке cvs. Конечно же, subversion будет распространяться с исходными текстами и по свободной лицензии. Я очень надеюсь, что этому проекту будет сопутствовать успех! Но в любом случае cvs будет использоваться еще очень и очень долго.


Ссылки на дополнительную информацию

Домашняя страница cvs: http://www.cvshome.org/

Основной ресурс по cvs на open directory:
http://dmoz.org/computers/software/configuration_management/tools/concurrent_versions_system/

Крупнейший ресурс по cvs на русском языке (документация, статьи, список рассылки):
http://alexm.here.ru/cvs-ru/

Графический (а также обычный текстовый) cvs-клиент под win32:
http://www.cvsgui.org/

cvs-сервер под win32:
http://www.cvsnt.org/

Ссылки на другие системы управления версиями:
http://dmoz.org/computers/software/configuration_management/tools/
--------------------------------------------------------------------------------
Альтернативная версия данной статьи была опубликована в журнале "Программист", номер 2 за 2001 год, а авторский оригинал находится по адресу http://www.vak.ru/tcpip/internet.html.