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

Copyright (C) Alexey Mahotkin <[email protected]> 2001

Эта статья была впервые опубликована
в журнале "Программист", номер 2 за 2001 год.

Запрещается перепечатка этой статьи без письменного разрешения автора.

<epigraph>
From: [email protected]
Message-ID: <[email protected]>

Практика показывает, что 99% программистов под ОС Уиндоуз ведут разработку программ очень странными способами -- про version control они даже не догадываются, правят по живому, раз и навсегда. На просьбу вернуться к предыдущей версии хлопают глазами и говорят "а мы уже всё переправили!". В общем, культура программирования там в массе своей на уровне африканской деревни.
</epigraph>

Введение

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

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

В этой статье речь пойдет о 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 <stdio.h>

int main() {
  printf("hello world\n");
}
=== 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 <stdio.h>

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 <stdio.h>

	 int main() {
	-  printf("hello world\n");
	+  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/


Alexey Mahotkin
Last modified: Tue Apr 17 00:43:10 MSD 2001