Введение
Системы управления версиями - класс программных
продуктов, нацеленных на решение ряда задач, с которыми повседневно сталкивается
каждый программист. С помощью систем управления версиями вы следите за
изменениями кода вашего программного продукта в ходе его разработки, и можете
управлять различными его состояниями: новая версия, работа над которой идет
прямо сейчас; старая версия, которую придется поддерживать еще некоторое время;
или же старая версия, интересная только историкам.
Программисты,
чьи исходники контролируются системой управления версиями, чем-то неуловимо
отличаются от остальных программистов. Они в каждый момент рабочего дня точно
знают, что именно было сделано за день, а после исправления ошибки могут точно
сказать, в каком именно месте кода была ошибка. Они не подвержены синдрому
"работает - не трогай", потому что могут совершенно безболезненно ударяться в
самые сложные эксперименты со своей программой. Они твердо знают, что в любой
момент могут вернуться к "исходникам, которые работали", сколько бы
экспериментов с новым кодом не было проведено. Более того, если пользователь
вдруг захочет небольшое, крошечное изменение, когда программа находится в
многообещающем, но совершенно нерабочем состоянии, то все, что для этого
потребуется -- переключиться на стабильную ветку, исправить там, что надо и
отдать пользователю, затем переключиться обратно на ствол разработки.
В этой статье речь пойдет о 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.