17. Использование CVS


Сверхкраткий курс по CVS

Система управления версиями CVS (Concurrent Versions System) является инструментом с открытым исходным кодом, предназначенным для управления версиями файлов. Под контроль системы CVS можно поставить любые типы файлов, но в данном разделе основное внимание будет сконцентрировано на файлах исходных текстов программ и других текстовых файлах.

Под управлением версиями (version control) понимается возможность отслеживания изменений в файлах. Каждый раз, когда файл изменяется, в системе регистрируется дата изменения, описание изменения и пользователь, который изменил файл. Это позволяет отслеживать когда, кем и почему был изменен файл. Система CVS позволяет также координировать изменения, выполняемые для одного и того же файла многими пользователями.

Использование системы CVS для контроля за версиями файлов исходных текстов дает возможность выделять, какие изменения в файлах станут частью очередной версии программного обеспечения, а какие — нет. Это означает, что можно выпустить текущую версию проекта, продолжая, в то же время, работу над будущей версией с новыми функциями. Именно возможность такого параллелизма при контроле версий программного обеспечения сделали систему CVS столь популярной.

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

Более подробную информацию о системе CVS, включая полное руководство пользователя CVS ("CVS User's Guide"), можно найти на сайте http://www.cvshome.org.

Основы CVS

В системе CVS файлы сохраняются в едином месте, называемом репозиторием (repository). Репозиторий размещается на диске вашей локальной машины или на удаленном сервере. В данном разделе предполагается локальное сохранение версий.

Версии

Каждый раз, когда в хранимый в CVS файл вносятся изменения, создается новая версия (revision) файла. В версию файла включается дата изменения, имя пользователя, сделавшего изменение, и журнальное сообщение, описывающее суть изменения. В любое время можно извлечь для изучения произвольные версии файла. Отдельным версиям можно присваивать символические имена, метки (tags), для упрощения ссылок на них.

Версия обозначается как последовательность чисел и точек. Этот метод аналогичен стандартной схеме нумерации версий программного обозначения. Например, в файле foo.с за последние несколько дней было сделано три изменения. Первая редакция файла получает номер 1.1, вторая — 1.2, а третья — 1.3. Номера в системе CVS назначаются автоматически и используются только внутри системы. Вам придется использовать эти номера в разных ситуациях.

Изменения в файле foo.с носят кумулятивный характер, поэтому в версии 1.3 содержатся как все изменения, внесенные между версиями 1.1 и 1.2, а также все изменения, внесенные между версиями 1.2 и 1.3.

Основные операции

Как в системе CVS становится известно о внесенных в файл изменениях? Создается ли новая версия каждый раз, когда файл сохраняется?

Фактически вы не манипулируете файлами непосредственно в репозитории. Вместо этого вы создаете у себя на диске копию репозитория. Изменения вносятся в копии файлов, а когда вы будете удовлетворены внесенными изменениями, то системе CVS дается команда на перенос измененного файла в репозиторий и о создании новой версии. Этот процесс называется обновлением версии (checking in). В момент обновления вы вводите комментарий о сделанных изменениях.

Как создать у себя локальную копию репозитория? Эта операция называется выгрузкой версии (checking out) и является обратной операции обновления. При выполнении операции выгрузки создается копия репозитория с информацией о ее текущем состоянии. Обычно требуется получить копию текущего состояния репозитория, но иногда необходим более детальный контроль над версиями файлов. Поэтому для этой операции предусмотрено множество ключей, в том числе возможность использования символических имен и явных дат.

Репозиторий

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

Для всех операций в первую очередь нужно знать место нахождения репозитория. Для него нет местоположения по умолчанию. Репозиторий — это просто каталог, имя которого можно указать через командную строку или задать значение для некоторой переменной окружения.

Редакторы и система CVS

В системе CVS часто выдается запрос на получение некоторой информации, при этом запускается редактор с определенным шаблоном. Можно управлять этим процессом, указав, какую именно программу редактора нужно запускать. Это делается путем установки значения переменной окружения EDITOR. Например, для использования редактора оболочки Photon ped нужно использовать такую команду для помещения этой информации в профиль .profile:

export EDITOR=ped


Сведения о доступных редакторах приведены в разделе 7. Информация о профиле .profile приведена в разделе 9.

Создание репозитория

Вначале нужно решить, где будет размещаться репозиторий. Например, для него выбран каталог $HOME/cvs.

Для создания пустого репозитория введите следующую команду:

cvs -d$HOME/cvs init


Если заглянуть в каталог $HOME/cvs, то там можно увидеть созданный каталог CVSROOT. В нем находятся внутренние административные файлы, необходимые для работы системы CVS.

Ключ -d в команде cvs используется в системе CVS для указания на место расположения репозитория. Исполняемая операция init осуществляет создание нового репозитория. Ключ -d является глобальным, поскольку он появляется перед исполняемой операцией init. В общем случае вызов команды cvs имеет следующий формат:

cvs [глобальные_ключи] команда [ключи_команды] имена_файлов


После того как был создан репозиторий, в каталоге
CVSROOT нужно отредактировать указанные далее файлы:
Один и тот же пользователь не может присутствовать в обоих файлах.

Загрузка файлов в репозиторий и выгрузка из него

Есть два способа помещения в репозиторий исходных файлов: добавление новых файлов или импортирование существующего дерева каталога. Сначала рассмотрим вариант с созданием новых файлов.

Поскольку работа начинается с новым репозиторием, то нужно создать локальную рабочую копию. Но в каталоге пока ничего нет.

Сначала можно выполнить выгрузку упомянутого выше каталога CVSROOT — кроме него ничего другого в репозитории нет — как это можно сделать с любым каталогом. Необходимо также создать каталог для помещения локальной копии, назовем его "песочницей" (sandbox) и разместим его в своем домашнем (home) каталоге:

cd $HOME

mkdir sandbox

cd sandbox


Теперь необходимо поместить в этот каталог рабочую копию из репозитория:

cvs -d$HOME/cvs checkout .


или

cvs -d$HOME/cvs get .


Использование точки (.) в качестве имени файла интерпретируется как "получить содержимое всего репозитория".

В каждом выгруженном каталоге вы обнаружите подкаталог с именем CVS. Этот каталог используется системой CVS для сохранения информации о том, в каком месте репозитория размещены файлы, каковы версии этих файлов и т. д. Не вносите никакие изменения в файлы этого каталога.

Предупреждение.

Если вы создаете новый проект, копируя каталоги из одной части "песочницы" в другую, не копируйте подкаталог CVS. Если вы сделаете это, то файлы могут сохраниться не в том месте репозитория, в котором вы ожидаете.

Теперь, когда у нас имеется рабочая копия, можно создать другие каталоги и файлы, чтобы продемонстрировать выполнение операций обновления и выгрузки. Начнем с написания стандартной программы "Hello, world" на языке C. Традиционно рекомендуется сохранять все проекты в отдельной структуре каталогов, поэтому мы также создадим для проекта новый каталог.

Для этого нужно выполнить команду:

mkdir myproj


Теперь добавим этот каталог в репозиторий системы CVS:

cvs -d$HOME/cvs add myproj


Наконец, пришло время создать тестовый файл, но вначале нужно оказаться в каталоге проекта:

cd myproj


Теперь вызывайте любой текстовый редактор, чтобы создать файл
foo.с со следующим содержимым:

#include <stdio.h>


int main (int argc, char *argv[]) {

printf ("Hello, world.\n");


}


Добавление файла в репозиторий производится так же, как и добавление каталога:

cvs add foo.с

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

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

Перенос изменений в репозиторий

Операции commit или ci (от англ. check in — обновление) приводят содержимое репозитория в соответствие с содержимым вашей локальной копии. Если с общим репозиторием работает несколько человек, все происходит немного по-другому, но в данном случае мы предполагаем, что репозиторием пользуется только один человек:

cvs commit foo.с

или

cvs ci foo.с

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

Импорт существующего дерева файлов с исходными текстами

Вероятно, вы уже обратили внимание на то, что добавление в систему CVS файлов из существующего дерева каталогов с использованием описанных выше команд add и commit становится трудоемким, если файлов более двух. В этом случае можно воспользоваться операцией import. В данном разделе мы коснемся наиболее общих принципов использования этой операции. Позднее будут рассмотрены некоторые дополнительные возможности.

При использовании операции import предполагается, что где-то на диске имеется дерево каталогов. Эти каталоги не должны находиться ни внутри репозитория, ни внутри локальной копии репозитория. Для добавления в CVS-репозиторий всего дерева каталогов используются команды следующего формата:

cd добавляемый_источник

cvs -dпуть_к_репозиторию import путь_в_репозитории метка_ветки_поставщика метка_версии

После этого в открывшемся окне редактора можно добавить комментарий.

На первый взгляд такой формат команды может показаться несколько странным, но операция import выполняет не только простое импортирование. Эта команда всегда импортирует содержимое текущего рабочего каталога. Параметр путь_в_репозитории означает, что система CVS должна создать этот путь внутри репозитория и поместить туда содержимое текущего каталога.

Последние два аргумента — метка_ветки_поставщика (vendor) и метка_версии (init) — служат для создания так называемой "ветки" (branch) и метки для импортируемых файлов (см. подразд. "Параллельная разработка: ветвление и слияние" далее в этом разделе). Эти параметры не нужны при импортировании собственного программного обеспечения, но в соответствии с форматом их все равно требуется указать для системы CVS.

Получение информации о файлах

Текущий статус файла можно получить с помощью команд status или stat:

cvs status foo.с


Результат работы команды будет выглядеть примерно так:

===================================================================

File: foo.c Status: Up-to-date


Working revision: 1.1 Tue Jun 3 17:14:55 2003

Repository revision: 1.1 /home/fred/cvs/myproj/foo.c,v

Sticky Tag: (none)

Sticky Date: (none)

Sticky Options: (none)

Изменение файлов

При создании файла foo.c мы не вставили в него ни одной строки комментария! Это нужно исправить. С помощью текстового редактора добавьте в самом начале файла foo.c строку:

/* Это файл для проверки системы CVS */


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


===================================================================

File: foo.c Status: Locally Modified


Working revision: 1.1 Tue Jun 3 17:14:55 2003

Repository revision: 1.1 /home/fred/cvs/myproj/foo.c,v

Sticky Tag: (none)

Sticky Date: (none)

Sticky Options: (none)

Статус файла изменился на Locally Modified (локально изменен). Это сигнал о том, что вы изменили файл, но должны еще сообщить об этом системе CVS. Это можно сделать так:

cvs commit foo.с

Как и раньше, после запуска команды открывается окно редактора для ввода сообщения (комментария). Здесь можно написать о причине изменений или кратко описать их характер. Опять же текст может быть в свободной форме, поэтому напишите любое сообщение. Мы, например, напишем: Добавили комментарий для ясности. Сохраните файл и закройте редактор.

Опросим статус файл. Теперь мы получим такой результат:

===================================================================

File: foo.c Status: Up-to-date



Working revision: 1.2 Tue Jun 3 17:30:49 2003

Repository revision: 1.2 /home/fred/cvs/myproj/foo.c,v

Sticky Tag: (none)

Sticky Date: (none)

Sticky Options: (none)


Дополнительная информация о файлах: что изменилось и почему?

В показанном выше результате о статусе файла номер его версии (revision) изменился с 1.1 на 1.2. У нас теперь есть две версии файла foo.c, поэтому можно посмотреть, что изменилось и почему были сделаны изменения. Для получения ответа на вопрос "почему" нужно просмотреть сообщения журнала, куда заносятся записи каждый раз при совершении операции по внесению изменений. Содержимое журнала выводится по команде:

cvs log foo.с


Результат вывода будет таким:

RCS file: /home/fred/cvs/myproj/foo.c,v

Working file: foo.c

head: 1.2

branch:

locks: strict

access list:

keyword substitution: kv

total revisions: 2; selected revisions: 2

description:

----------------------------

revision 1.2

date: 2003/06/03 17:35:43; author: fred; state: Exp; lines: +2 -0

Added comments for clarity.

----------------------------

revision 1.1

date: 2003/06/03 17:19:34; author: fred; state: Exp;

A file to test the basic functionality of CVS

===================================================================
Для того чтобы увидеть различия между двумя версиями, используем команду diff:


cvs diff -r1.1 foo.с

Результат вывода будет таким:

Index: foo.c

===================================================================

RCS file: /home/fred/cvs/myproj/foo.c,v

retrieving revision 1.1

retrieving revision 1.2

diff -r1.1 -r1.2

0a1,2

>/* Это файл для проверки системы CVS */

>


Последние строки, начиная с diff -r1.1 -r1.2z, показывают фактические различия, используя стандартный формат команды diff (см. руководство "Описание программы. Часть 1. Справочник по утилитам" КПДА.10964-01 13 01).

Возможно, вы уже обратили внимание на то, что для команды diff с помощью ключа -r был указан номер только одной версии. В системе CVS подразумевается, что второй версии соответствует файл foo.с, находящийся в вашей "песочнице". Из последнего результата вывода статуса по команде status видно, что номер рабочей версии был 1.2, следовательно, это вторая версия. Мы могли бы явно указать номер версии, используя второй ключ -r:

cvs diff -r1.1 -r1.2 foo.c

Index: foo.c

===================================================================

RCS file: /home/fred/cvs/myproj/foo.c,v

retrieving revision 1.1

retrieving revision 1.2

diff -r1.1 -r1.2

0a1,2

> /* Это файл для проверки системы CVS */

>

Как видно, получены аналогичные результаты.

Система CVS и деревья каталогов

В системе CVS дерево каталогов просматривается автоматически, начиная с текущего рабочего каталога (если не задано конкретное имя файла или имя каталога). Например, после выполнения команды:

cvs stat


выдается статус всех файлов текущего каталога и всех нижележащих подкаталогов.


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

cvs commit


Вы получите запрос на ввод только одного сообщения для журнала. Это сообщение будет распространяться на все изменения, выполненные этой командой.

Параллельная разработка: ветвление и слияние

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

Ветвление


Когда вы создаете ветку, в системе CVS создается другая копия файла или файлов, причем редактировать можно любую версию. В системе CVS отслеживается, к какой версии относятся соответствующие изменения.

Основная ветка (branch) разработки называется головной (head). Можно принять решение о разработке новых функциональных возможностей в головной ветке, а можно создать отдельные ветки для других версий программного обеспечения (рис. 17.1).



Рис. 17.1.
Ветвление файла в системе CVS

Допустим, выпускается версия 1.0 нового продукта, названного Stella, и в состав этого продукта входит файл foo.c. Можно создать ветку для этой версии следующим образом:

cvs tag -b "Stella_1.0" foo.c


Stella_1.0 является меткой (sticky tag). Любые изменения, которые вы делаете в вашей "песочнице", связываются с веткой Stella_1.0, а не с основной веткой. Если вы хотите работать с основной веткой, то нужно обновить "песочницу", указав ключ -A, который отключит работу с метками:

cvs update -A

или

cvs up -A


Что нужно сделать, если вы хотите выгрузить обе версии? Можно обновлять содержимое "песочницы", используя отдельную команду для головной ветки (как показано ранее) и отдельную для рабочей ветки (
cvs update -r Stella_1.0), однако в этом случае трудно отслеживать, над какой именно версией вы сейчас работаете. Вместо этого вы можете выгрузить ветку в другой каталог:

cd ~/cvs

mkdir version1.0

cd version1.0

cvs checkout -r Stella_1.0 путь_к_файлам


Слияние

Итак, вы сделали изменения в одной ветке, и нужно сделать изменения в другой ветке. Можно отредактировать файлы дважды, но это не очень удобно. Вместо этого в системе CVS можно выполнить слияние одной ветки с другой.

Примечание. Обычно проще выполнить слияние дополнительной ветки с основной.

Для слияния изменений в файле foo.с ветки Stella_1.0 с версией головной ветки перейдите в каталог, откуда была выгружена основная ветка в вашу "песочницу", и введите команду:

cvs update -j Stella_1.0 foo.c


Примечание. Рекомендуется проверить файл на корректность выполнения операции слияния. Никогда не полагайтесь полностью на действия машины.

Иногда изменения, сделанные в одной ветке, конфликтуют с изменениями, сделанными в другой ветке. Если такое случается, то при слиянии версий перед именем файла выводится символ С. В системе CVS конфликтующие строки остаются без изменения, но помечаются знаками "больше чем", "равно", "меньше чем". Вам нужно отредактировать файлы для устранения несоответствий, а затем повторно обновить версии в системе CVS.

Удаление и восстановление файлов

Когда файл удаляется из репозитория, система CVS перемещает его на "чердак" (attic). У каждого каталога в репозитории имеется подкаталог Attic. Этот каталог нельзя выгрузить в вашу "песочницу", но содержимое каталога можно исследовать через Web-интерфейс в системе CVS.

Для удаления файла (например, phoenix.c) необходимо выполнить такую последовательность действий.

rm phoenix.с

cvs remove phoenix.с

или

cvs rm phoenix.с

Если нужно восстановить файл, то выполните следующие действия.

cvs log phoenix.с | less

cvs checkout -r 1.3 my_project/phoenix.с

или

cvs get -r 1.3 my_project/phoenix.с


Ключ
-r устанавливает метку.

mv phoenix.с save_phoenix.с

cvs update -A

mv save_phoenix.с phoenix.с

cvs add phoenix.с


Настройка сервера CVS

Настройка сервера CVS похожа на настройку локального репозитория (см. подразд. "Создание репозитория" ранее в этом разделе). Однако нужно выполнить три дополнительные операции.

pserver 2401/tcp

pserver stream tcp nowait root /usr/bin/cvs cvs -b /usr/local/bin –f--allow-root=корневой_каталог pserver


Здесь корневой_каталог — это путь, который вы хотите использовать в качестве корневого каталога системы CVS. Общепринято, чтобы путь заканчивался именем CVSRoot, хотя это не обязательное правило.

Можно иметь более одного корневого каталога. Нужно просто добавить несколько экземпляров параметра --allow-root=корневой_каталог.

cvs -d корневой_каталог init


После этого будет создан каталог с именем корневой_каталог, и в него будут занесены все необходимые для работы репозитория файлы.

Более подробная информация содержится на сайте http://www.cvshome.org.