CVS-RCS- HOW-TO документ для Linux (система контроля исходного кода)

Этот документ является "практическим руководством" для очень быстрой установки системы контроля исходного кода -- CVS/RCS. Также выборочно будут рассмотрены скрипты оболочки, являющихся внешними функциями для CVS. Они предоставляют легкий пользовательский интерфейс к CVS. Излагаемая информация применима к Linux, а так же ко всем остальным разновидностям Unix, подобно Solaris, HPUX, AIX, SCO, Sinix, BSD, SCO, и т.д.

[Alavoor Vasudevan (alavoor@yahoo.com). Перевод Султанбек Тезадов (st99@mail.ru)]

CVS-RCS- HOW-TO документ для Linux (система контроля исходного кода)

Аннотация

Этот документ является "практическим руководством" для очень быстрой установки системы контроля исходного кода -- CVS/RCS. Также выборочно будут рассмотрены скрипты оболочки, являющихся внешними функциями для CVS. Они предоставляют легкий пользовательский интерфейс к CVS. Излагаемая информация применима к Linux, а так же ко всем остальным разновидностям Unix, подобно Solaris, HPUX, AIX, SCO, Sinix, BSD, SCO, и т.д.


Введение

Система контроля исходного кода НЕОБХОДИМА для управления изменениями, возникающими в процессе разработки программного обеспечения. Разработчикам нужна полная история изменений для возможности отката к предыдущим версиям в случае возникновения проблем. Поскольку исходный код -- самый основной компонент любого проекта программного обеспечения и разработчики расходуют огромное количество времени и денег, очень важно потратить некоторое время для сопровождения ( safe-guarding ) исходного кода посредством использования системы контроля исходного кода, подобно CVS и RCS.

CVS (Concurrent Version Control System) -- мощный инструмент, позволяющий одновременную разработку программы несколькими пользователями. Он основан на RCS и имеет интерфейс уровня приложений в виде внешних функций к RCS.

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

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

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

CVS используется для хранения файлов C, C++, Java, Perl, HTML и других.


Что мне подходит, CVS или RCS?

CVS реально использует RCS и является намного более мощным инструментом, обладая возможностью контроля полного дерева исходного кода. Очень настоятельно рекомендуется использование CVS, поскольку имеется возможность чрезвычайно гибкой настройки CVS с помощью скриптовых языков вроде PERL, оболочек Korn и Bash. Смотрите пример для оболочки Korn в "Разд. Скрипты оболочки ".

Преимущества CVS

  • CVS децентрализован от редактируемых пользователем файлов/каталогов из репозитория и имеет свое собственное отдельное дерево каталогов исходного кода.

  • CVS может создавать "штампы" деревьев исходного кода проекта.

  • CVS может обеспечить одновременное редактирование файлов.

  • CVS можно очень гибко настроить для обеспечения сильного блокирования файлов или для одновременного редактирования файлов с использованием скриптов оболочки или PERL.

Недостатки CVS

  • Требует чуть больше администрирования, чем RCS.

  • Является очень сложной составной системой и является практически произведением искусста ("State of the Art"). Программа CVS -- очень продвинутая и хитроумная система, разрабатываемая в течении длительного периода времени (нескольких лет!).

  • Обладает большим количеством команд и параметров, делая кривую обучения круче для начинающих. Скрипты оболочки в "Разд. Скрипты оболочки " могут упростить использование.

Преимущества RCS

  • RCS очень прост в установке, требует меньше административной работы.

  • RCS используется в централизованной области, в которой работает каждый отдельный разработчик.

  • RCS полезен для простых систем.

  • Осуществляет очень сильную блокировку файлов -- одновременное редактирование исключено.

Обратная сторона RCS

  • Одновременная разработка несколькими разработчиками невозможна из-за блокировки файлов и ограничения единственным рабочим каталогом. Единственность рабочего каталога может стать причиной неудачи команды "make" после изменения файлов несколькими разработчиками.

  • Не умеет делать общие "штампы" проекта программного обеспечения.

Этот документ содержит скрипты оболочки, предоставляющие простые команды для извлечения, загрузки и фиксации файлов. Скрипты оболочки смотрите в "Разд. Скрипты оболочки ".

О RCS смотрите "RCS mini-howto" на компакт-диске Linux:

cd /mnt/cdrom/Redhat/RPMS
ls -l howto-6.0-*.noarch.rpm
rpm -qpl howto-6* | grep -i rcs 
или посетите http://www.LinuxDoc.org/HOWTO/mini/RCS.html.

Можно также посмотреть скрипты оболочки для RCS в "Разд. RCS Скрипты оболочки ".


Установка CVS

Сперва необходимо инсталлировать пакет CVS; на Redhat Linux наберите:

cd /mnt/cdrom/Redhat/RPMS
rpm -i rcs*.rpm
rpm -i cvs*.rpm
Для просмотра списка установленных файлов:
rpm -qpl cvs*.rpm | less
полученный вывод пролистывайте с помощью "j", "k", "CTRL+f", "CTRL+D", "CTRL+B", "CTRL+U" или клавиш со стрелками и "Page Up", "Page Down". Посмотрите "man less".

На других разновидностях Unix может понадобиться скачать tar-архивы RCS и CVS, а затем прочесть файлы README и INSTALL для установки CVS. Посетите http://www.cyclic.com и http://www.loria.fr/~molli/cvs-index.html.


Переменные окружения

Необходимо установить следующие переменные окружения в файле /etc/profile; для всех пользователей требуются значения по умолчанию. Если они не установлены в /etc/profile, то следует добавить их в Ваш локальный файл профиля =/.bash_profile.

export EDITOR=/bin/vi
export CVSROOT=/home/cvsroot
export CVSREAD=yes

Создайте каталог для хранения репозитория исходного кода и установите права на чтение/запись для группы/пользователя. Проверьте, чтобы имя каталога CVSROOT не содержало пробелов. Пример недопустимого значения CVSROOT: "/home/my rootcvs".

export CVSROOT=/home/cvsroot
mkdir $CVSROOT
chmod o-rwx $CVSROOT
chmod ug+rwx $CVSROOT
Теперь установите группу для $CVSROOT в значение группы пользователей, желающих использовать систему CVS.
chgrp users $CVSROOT
Для инициализации CVS и размещения файлов исходного кода:
cvs init

# Смена каталога обязательна
cd $HOME/my_source_code_dir

# Необходимо указать поставщика (напр., V1_0) и редакцию (напр., R1_0)
cvs import my_source_code_dir V1_0 R1_0  


Миграция от RCS к CVS

Для переноса файлов из RCS в CVS воспользуйтесь следующим скриптом. Проверьте, установлен ли у Вас пакет оболочки Korn pdksh*.rpm с компакт-диска Linux.

ВНИМАНИЕ: оболочка Korn /bin/ksh устанавливается инсталляцией pdksh*.rpm с компакт-диска дистрибутива Linux

#!/bin/ksh

#############################################################
# Программа для переноса существующего в RCS исходного кода
# в CVS 
#
# Нуждается в RPM-пакете pdksh*.rpm оболочки Korn c компакт-
# диска Linux 
#############################################################

#
# rcs2cvs - преобразование дерева исходного кода из RCS в CVS
#

# проект для преобразования
PROJECT='project'

# текущий корень RCS
RCSROOT="$HOME/rcs"

if cd "$RCSROOT/$PROJECT"
then
 cd "$RCSROOT"
else
 echo >&2 "`basename "$0"`: не могу перейти в каталог RCS '$RCSROOT/$PROJECT'."
 exit 1
fi

# текущий корень CVS
CVSROOT="$HOME/cvs"

# создание нового каталога CVS для проекта "project"
if mkdir "$CVSROOT/$PROJECT"
then
 :
else
 echo >&2 "`basename "$0"`: не могу создать CVS-каталог '$CVSROOT/$PROJECT'."
 exit 2
fi

# создание дерева CVS-проекта из дерева RCS
find "$PROJECT" -type d -name RCS -print |
while read RCS
do
 CVS="`dirname "$RCS"`"
 (if cd "$RCS"
 then
#  if find . -type f -name '*,v' -print | cpio -pdmv "$CVSROOT/$CVS"
  if find . -type f -print | cpio -pdmv "$CVSROOT/$CVS"
  then
   :
  else
   echo >&2 "`basename "$0"`: не могу преобразовать RCS-подкаталог\
                     '$RCSROOT/$RCS' в CVS-подкаталог '$CVSROOT/$CVS'."
  fi
 else
  echo >&2 "`basename "$0"`: не могу перейти в RCS-подкаталог '$RCSROOT/$RCS'."
 fi)
done
Теперь RCS перенесен в CVS под именем "project". Вы можете начать использование команд CVS применительно к модулю "project".


Введение в команды CVS

CVS предоставляет широкий диапазон команд (cvs_command in the Synopsis), каждая из которых, как правило, имеет богатый набор опций, призванные удовлетворить многие потребности управления исходным кодом в распределенных окружениях. Однако, Вы не обязаны овладеть каждой деталью чтобы делать полезную работу с помощью CVS; на самом деле, достаточно пяти команд для использования репозитория исходного кода. Команды CVS, используемые чаще всего: checkout, update, add, remove, commit и diff.


checkout

cvs checkout модули... Необходимая подготовка для выполнения большинства последующей работы CVS: создает Вашу личную копию исходного кода для "модулей" (именнованного набора исходных кодов; здесь можно также использовать путь относительный к местоположению репозитория). Ваша работа с этой копией никак не будет пересекаться с работой других разработчиков. Всегда создается по меньшей мере один уровень подкаталогов. (Для Вашего удобства вывод программы также переведен на русский язык. -- Прим. перев.)

bash$ cvs --help checkout
Вызов:
  cvs checkout [-ANPRcflnps] [-r rev | -D дата] [-d dir]
    [-j rev1] [-j rev2] [-k kopt] модули...
        -A      Сбросить липкие тэги/дату/kopts.
        -N      Если задано -d, не укорачивать пути модулей.
        -P      Удалять пустые каталоги.
        -R      Обрабатывать каталоги рекурсивно.
        -c      "cat" базу данных модулей.
        -f      Вынудить совпадение редакции, если тэг/дата не найдена.
        -l      Только локальный каталог, не рекурсивно.
        -n      Не запускать программу модуля (при ее наличии).
        -p      Извлечь файлы и отправить на стандартный вывод (избегает липкость).
        -s      Подобен -c, но включает статус модуля.
        -r rev  Извлечь редакцию или тэг. (включает -P) (липкий)
        -D date Извлечь редакцию указанной даты. (включает -P) (липкий)
        -d dir  Извлечь в каталог dir вместо каталога с именем модуля.
        -k kopt При извлечении использовать опцию RCS kopt -k.
        -j rev  Объединить изменения, сделанные между текущей редакцией и rev.
(Задайте глобально опцию --help для получения списка остальных опций справки)


update

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

bash$ cvs --help checkout
Вызов:
  cvs checkout [-ANPRcflnps] [-r rev | -D дата] [-d dir]
    [-j rev1] [-j rev2] [-k kopt] модули...
        -A      Сбросить липкие тэги/дату/kopts.
        -N      Если задано -d, не укорачивать пути модулей.
        -P      Удалять пустые каталоги.
        -R      Обработать каталоги рекурсивно.
        -c      "cat" базу данных модулей.
        -f      Вынудить совпадение редакции, если тэг/дата не найдена.
        -l      Только локальный каталог, не рекурсивно.
        -n      Не запускать программу модуля (при ее наличии).
        -p      Извлечь файлы и отправить на стандартный вывод (избегает липкость).
        -s      Подобен -c, но включает статус модуля.
        -r rev  Извлечь редакцию или тэг. (включает -P) (липкий)
        -D date Извлечь редакцию указанной даты. (включает -P) (липкий)
        -d dir  Извлечь в каталог dir вместо каталога с именем модуля.
        -k kopt При извлечении использовать опцию RCS kopt -k.
        -j rev  Объединить изменения, сделанные между текущей редакцией и rev.
(Задайте глобально опцию --help для получения списка остальных опций справки)

bash$ cvs --help update
Вызов: cvs update [-APdflRp] [-k kopt] [-r rev|-D дата] [-j rev]
    [-I ign] [-W spec] [файлы...]
        -A      Сбросить липкие тэги/дату/kopts.
        -P      Удалять пустые каталоги.
        -d      Создавать каталоги, как делает checkout.
        -f      Вынудить совпадение редакции, если тэг/дата не найдена.
        -l      Только локальный каталог, не рекурсивно.
        -R      Обработать каталоги рекурсивно.
        -p      Отправить обновления на стандартный вывод (избегает липкость).
        -k kopt При извлечении использовать опцию RCS kopt -k.
        -r rev  Обновить используя указанную редакцию/тэг. (липкий)
        -D date Указать дату с которой извлечь обновления. (липкий)
        -j rev  Объединить изменения, сделанные между текущей редакцией и rev.
        -I ign  Больше файлов для игнорирования (! для сброса).
        -W spec Строка задания оберток.
(Задайте глобально опцию --help для получения списка остальных опций справки)


add

cvs add файл... Воспользуйтесь этой командой для внесения новых файлов в CVS-записи Вашего рабочего каталога. Файлы будут добавлены в репозиторий в следующий раз, как Вы запустите "cvs commit". Заметьте, что для занесения новых исходных кодов в репозиторий следует использовать команду "cvs import". "cvs add" используется только для файлов, новых для уже извлеченного (checked-out) модуля.

bash$ cvs --help add
Вызов: cvs add [-k rcs-kflag] [-m сообщение] файлы...
        -k      Использовать "rcs-kflag" для добавления файла с указанным kflag.
        -m      Использовать "сообщение" для лога о создании.
(Задайте глобально опцию --help для получения списка остальных опций справки)


remove

cvs remove файл... Эта команда (после удаления перечисленных файлов) предназначена для заявления желания уничтожить файлы из репозитария. Для остальных разработчиков удаление возымеет действие после выполнения "cvs commit".

bash$ cvs --help remove
Вызов: cvs remove [-flR] [файлы...]
        -f      Удалить файл перед его исключением.
        -l      Обработать только этот каталог (не рекурсивно).
        -R      Обработать каталоги рекурсивно.
(Задайте глобально опцию --help для получения списка остальных опций справки)


commit

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

bash$ cvs --help commit
Вызов: cvs commit [-nRlf] [-m msg | -F logfile] [-r rev] файлы...
        -n      Не запускать программу модуля (при ее наличии).
        -R      Обработать каталоги рекурсивно.
        -l      Только локальный каталог (не рекурсивно).
        -f      Вынудить фиксацию файла; отключает рекурсию.
        -F file Читать лог-сообщения из файла.
        -m msg  Лог-сообщение.
        -r rev  Фиксировать в этой ветке или этом стволе редакции.
(Задайте глобально опцию --help для получения списка остальных опций справки)


diff

cvs diff файл... Показывает различия между файлами в рабочем каталоге и репозитории исходных кодов. (Не изменяет ни репозиторий ни рабочий каталог.)

bash$ cvs --help diff
Usage: cvs diff [-lNR] [rcsdiff-options]
    [[-r rev1 | -D date1] [-r rev2 | -D date2]] [файлы...]
        -l      Только локальный каталог, не рекурсивно.
        -R      Обработать каталоги рекурсивно.
        -D d1   Редакция различий между указанной датой и рабочим файлом.
        -D d2   Различия между rev1/date1 и date2.
        -N      Включить различия между добавленными и исключенными файлами.
        -r rev1 Редакция различий между rev1 и рабочим файлом.
        -r rev2 Различия между rev1/date1 и rev2.
        --ifdef=arg     Вывести различия в формате ifdef.
(обратитесь к документации Вашей программы diff насчет rcsdiff-options.
Самым популярным является -c для получения различий с контекстом, но
существует много других опций).
(Задайте глобально опцию --help для получения списка остальных опций справки)


Редактор Emacs

Emacs -- мощный редактор и поддерживает CVS/RCS, особенно для объединения редакций и поиска различий. Основной сайт Emacs расположен здесь: http://www.emacs.org.


Скрипты оболочки

Ниже приведены внешние скрипты к базовым командам CVS. Они написаны для оболочки Korn, поскольку он всегда доступен на всех разновидностях Unix, но, в случае необходимости, Вы можете перевести их на Bash или PERL. Вы можете настроить скрипты на свой вкус. В основном они представляют собой команды CVS с деталями, добавленными для обеспечения нужд конкретной машины. Например, скрипт sedit осуществляет блокировку, давая пользователям знать, что кто-то уже редактирует файл. Безусловно, пользователи могут использовать непосредственно команды CVS, в обход этих скриптов. Эти скрипты лишь демонстрируют как в большой степени можно настроить CVS.

Заметьте: Скрипты оболочки принимают домашний каталог пользователя как корневой и извлекают дерево CVS внутрь него.

К сведению: В скриптах оболочки каждое целевое имя файла состоит из трех частей -- домашнего каталога, подкаталога и имени файла. Полный путь: $HOME/$subdir/$fname. В CVS сохраняется эта же структура каталогов (с помощью переменной $subdir), поэтому в CVS будет что-то вроде $CVSROOT/$subdir/$fname. Во всех стриптах эти четыре переменные -- $HOME, $CVSROOT, $subdir и $fname играют важную роль. Примерами их значений могут быть: HOME=/home/aldev, subdir=myproject/src, CVSROOT=/home/cvsroot и fname=foo.cpp.

Скопируйте скрипты оболочки в /usr/local/bin, который должен быть среди значений переменной окружения PATH пользователя.

  1. sget [-r номер_редакции] <файл/каталог> Для получения файла или целого каталога из CVS в режиме только для чтения. Скрипт Разд. sget .

  2. sedit [-r номер_редакции] <файл> Для редактирования файла с целью внесения изменений в код. Блокирует файл, так что никто не сможет его извлечь. Конечно, Вы можете изменить скрипт по своему усмотрению -- убрать блокировку, предупредительные сообщения или сильную блокировку. Скрипт Разд. sedit .

  3. scommit [-r номер_редакции] <файл> Для фиксации Ваших изменений файла или целого каталога. Загружает Ваши изменения в CVS. Скрипт Разд. scommit .

  4. supdate <файл/каталог> Для обновления файла или целого каталога, получением новейших файлов из CVS. Скрипт Разд. supdate .

  5. sunlock [-r номер_редакции] <файл> Для разблокирования файла, полученного с помощью sedit. Убирает блокировку. Скрипт Разд. sunlock .

  6. slist Для просмотра списка файлов, редактируемых Вами в настоящий момент. Выполняет команду "ls -l | grep | ...". Скрипт Разд. slist . Заметим, что есть еще другая команда Unix с именем slist (список доступных серверов Netware), следует убедиться, что CVS-скрипт slist встречается раньше другого в переменной окружения PATH.

  7. sinfo <файл/каталог> Для получения информации об изменениях/редакциях файла. Скрипт Разд. sinfo .

  8. slog <файл> Для получения от CVS истории изменений/редакций файла. Скрипт Разд. slog .

  9. sdif <файл>

    sdif -r ред1 -r ред2 <файл> Для получения отличий Вашего файла от CVS. Скрипт Разд. sdif .

    Заметьте, что в sdif одна "f", потому что есть другая Unix-команда "sdiff".

  10. sadd <файл> Для добавления нового файла в репозиторий CVS. Скрипт Разд. sadd .

  11. sdelete <файл> Для удаления файла из репозитория CVS. Скрипт Разд. sdelete .

  12. sfreeze <редакция> <каталог> Для замораживания кода, то есть выпуска редакции всего дерева исходного кода. Скрипт Разд. sfreeze .

    Например:

     cd $HOME;   
     sfreeze REVISION_1_0  srctree  
    Это замораживает код с меткой "REVISION_1_0", так что позже Вы можете извлечь целое дерево с помощью имени редакции.

  ******************************************************


Документация по CVS

По приглашению Unix напечатайте:

  1. cvs --help

  2. cvs --help-options

  3. cvs --help-commands

  4. cvs -H checkout

  5. cvs -H commit

  6. man cvs

  7. man tkcvs

  8. info cvs (-- перев.)

  9. Посетите http://www.cyclic.com

  10. Посетите http://www.loria.fr/~molli/cvs-index.html

  11. Посетите http://linux.ru.net/index.php?module=library&action=show&docid=33&part=586 ("CVS -- система управления параллельными версиями" в пер. Алексея Махоткина. -- Прим. перев.)

Tkcvs http://www.tkcvs.org -- Tcl/Tk GUI интерфейс к CVS. Имеется также интерактивная справка.

  • cd $HOME/src/foo.cpp

  • tkcvs

  • Щелкните на "foo.cpp"

  • Щелкните на "Revision Log Icon", расположенном рядом с изображением "очки".

  • В окне появится ветка дерева. Теперь щелкните ПРАВОЙ кнопкой мыши на надписи "1.3" и ЛЕВОЙ кнопкой мыши на "1.1". Затем нажмите кнопку "Diff". Появится двухпанельное окно.

  • Щелкните на кнопке "Next" для просмотра различий. Нажмите "Center" чтобы отцентрировать текст.

Существует также CVS-клиент для Windows 95, он называется WinCVS http://www.wincvs.org. WinCVS можно использовать совместно с Samba -- http://www.samba.org.

Основные команды:

  • cvs checkout <файл>

  • cvs update <файл>

  • cvs add <файл, ..>

  • cvs remove <файл, ..>

  • cvs commit <файл>

  • cvs status <файл>

  • cvs log <файл>

  • cvs diff -r1.4 -r1.5 <файл> Дает различия между версиями 1.4 и 1.5 файла.


Системная документация

На Linux-системах Вы можете найти CVS-документацию в формате Postscript по пути /usr/doc/cvs*/*.ps. Имеется также FAQ и другая полезная информация.

bash# cd /usr/doc/cvs*
bash# gv cvs.ps


RCS Скрипты оболочки

Если Вы хотите использовать RCS вместо CVS, то могут пригодиться следующие скрипты оболочки.


cotree.sh

#!/bin/ksh

# cotree.sh (Скрипт оболочки для извлечения дерева каталогов)
# cotree.sh - Извлечение целого RCS-каталога

# Вызов:
# Для получения всех каталогов:
# unix> cotree.sh 
#
# Для получения дерева единственного каталога:
# unix> cotree.sh <имя каталога>

# Смотрите также cofiles.sh

###############################################################
# Установка RCS (Revision Control System)
# Инсталлируйте программы RCS -- появятся команды co, ci, rcslog
# Создайте домашний каталог RCS, куда Вы поместите репозиторий
# исходного кода. Выполните $RCSDIR=/home/rcs_version_control
# Задайте переменную окружения RCSDIR=/home/rcs_version_control
# в файле $HOME/.profile. Так:
#  export RCSDIR=/home/rcs_version_control
# Создайте структуру каталогов в $RCSDIR и занесите туда все
# ваши файлы с помощью ci. Смотрите "man ci"
# Теперь создайте связь из Вашего домашнего каталога со своим
# проектом в $RCSDIR
#   cd $HOME
#  mkdir $HOME/myproject
#  cd $HOME/myproject
# и запустите следующий скрипт чтобы получить все файлы и дерево
# каталогов:
#  cotree.sh
# Данный скрипт создаст целое дерево исходного кода в домашнем 
# каталоге пользователя и будет иметь мягкую ссылку на каталоги
# RCS. Каждый пользователь запустит этот скрипт в своем домашнем
# каталоге.
###############################################################

check_out_directory()
{
 # Корневой каталог RCS (Revision Control System)
 # подобно RCSDIR=/home/rcs_version_control
 RCSDIR=$1
 DIRNAME=$2

 # Заданный каталог должен существовать в корневом каталоге RCS
 if [ "$DIRNAME" = "" -o  ! -d $RCSDIR/$DIRNAME ]; then
  print "\nКаталог DIRNAME=$DIRNAME не существует!!"
  print "\nЗавершение программы... и выход...\n"
  exit
 fi
 
 mkdir -p $DIRNAME
 ln -s $RCSDIR/$DIRNAME/RCS $DIRNAME
 (
  cd $DIRNAME

  # Неудача, если имя_файла=sample,vv что в RCS
  # будет RCS/sample,vv,v
  # ls RCS | cut -d',' -f1 | xargs co
  # Используем сопоставление с концом имени $, как ниже
  # Используем ls RCS/* во избежание прибавления к 
  # именам ./ и ../
  #ls RCS/* | cut -d'/' -f2 | sed -e's/,v$//g' | xargs co
  if [ -d RCS ]; then
   ls RCS/* | cut -d'/' -f2 | sed -e's/,v$//g' | \
   while read ii
   do
    #echo "ii is : $ii"
    if [ -f "RCS/$ii,v" ]; then
     co $ii
    fi
   done
  fi
 )
}

# Корневой каталог RCS (Revision Control System)
# подобно RCSDIR=/home/rcs_version_control
if [ "$RCSDIR" = "" -o ! -d $RCSDIR ]; then
 print "\nКаталог RCSDIR=$RCSDIR не существует!!"
 print "\nЗавершение программы... и выход...\n"
 exit
fi
#echo "rcsdir is : $RCSDIR"

# Если передан аргумент-каталог, то извлекаем все файлы
# только для этого каталога и выходим.
if [ "$1" != "" ]; then
 (cd $RCSDIR; find $1 -type d -print ) | 
 while read DIRNAME
 do
  #echo DIRNAME=$DIRNAME
  #DIRNAME=c_src
  # Передай корневой каталог RCS и имя каталога относительно
  # корневого каталога RCS
  tmpaa=` basename $DIRNAME `
  if [ "$tmpaa" != "RCS" ]; then
   check_out_directory $RCSDIR $DIRNAME
  fi
 done
else
 (cd $RCSDIR; find * -type d -print ) | 
 while read DIRNAME
 do
  echo DIRNAME=$DIRNAME
  #DIRNAME=c_src
  # Передай корневой каталог RCS и имя каталога относительно
  # корневового каталога RCS
  tmpaa=` basename $DIRNAME `
  if [ "$tmpaa" != "RCS" ]; then
   check_out_directory $RCSDIR $DIRNAME
  fi
 done
fi


cofiles.sh

#!/bin/ksh

# cofiles.sh (Скрипт оболочки для извлечения файлов)
# cofiles.sh - Извлечь все файлы из RCS в текущий каталог
# Смотрите также cotree.sh и "man rcsclean"

if [ ! -d RCS ]; then
 print "\nКаталог RCS не существует!!"
 print "\nЗавершение программы... и выход...\n"
 exit
fi

#echo "No. of args = " $# " and all args " $@

while true
do
 print -n "\n\nИзвлечь все файлы в режиме чтения-записи? <y/n> [n]: "
 read ans
 if [ "$ans" = "" -o "$ans" = "n" -o "$ans" = "N" ]; then
  ans="N"
  break
 elif [ "$ans" = "y" -o "$ans" = "Y" ]; then
  ans="Y"
  break
 else
  print "\nОшибочный ввод! Попробуйте снова!!"
 fi
done
#echo "The ans is : " $ans

if [ $# -eq 0 ]; then
 # "ls RCS" терпит неудачу в случае имя_файла=sample,vv в RCS/sample,vv,v
 # ls RCS | cut -d',' -f1 | xargs co
 # Используем сопоставление с концом имени $, как ниже
 if [ "$ans" = "Y" ]; then
  ls RCS | sed -e's/,v$//g' | xargs co -l 
 else
  ls RCS | sed -e's/,v$//g' | xargs co
 fi
elif [ $# -eq 1 ]; then
 if [ -f "RCS/$1,v" ]; then
  # Здесь, в этом случае $1 будет подобен dbalter.sql,
  # а не db*.sql...
  #echo "One arg, no. of args = " $# " and all args " $@
  if [ "$ans" = "Y" ]; then
   co -l "$1"
  else
   co "$1"
  fi
 else
  # Для случая, когда $1=db*.sql и нет db*.sql в
  # текущем каталоге
  #echo "No files... no. of args = " $# " and all args " $@
  tmpaa="RCS/$1,v"  # будет вроде RCS/db*.sql,v
  ls $tmpaa | \
  while read ii
  do
   #echo "ii is : $ii"
   if [ "$ans" = "Y" ]; then
    co -l "$ii"
   else
    co "$ii"
   fi
  done
 fi
else
 for ii in $@
 do
  #echo "ii is : $ii,v"
  if [ "$ans" = "Y" ]; then
   co -l "$ii"
  else
   co "$ii"
  fi
 done
fi


ciall.sh

#!/bin/ksh

# ciall.sh (Скрипт оболочки для фиксации файлов)
# ciall.sh - Загрузка всех файлов текущего каталога в RCS
# Данный скрипт очень полезен для загрузки огромного количества
# новых файлов в RCS. Экономит время, избегая необходимости
# набора "описания" для каждого файла
# Для файлов уже в RCS, выполняет обычную команду check-in


# Чтобы преобразовать имена файлов в нижний регистр,
# воспользуйтесь следующей техникой; используйте "tr",
# смотрите "man tr"
#ls * | \
#while read ii
#do
# jj=`echo $ii | tr [A-Z] [a-z] `
# echo "ii is : $ii"
# echo "jj is : $jj"
# mv $ii $jj
#done

if [ ! -d RCS ]; then
 print "\nКаталог RCS не существует!!"
 print "\nСоздаю каталог RCS...\n"
 mkdir RCS
fi

print "\n\nВНИМАНИЕ: это не лог-сообщение!"
print "Пожалуйста, введите описание (будет использовано для"
print -n "всех фиксируемых файлов): "
read description

#find * -prune -type f | 

# Количество аргументов нулевое или больше.... 
if  [ $# -eq 0 ]; then
 listoffiles="*"
else
 listoffiles="$@"
fi

find $listoffiles -prune -type f | 
while read ii
do
 #echo $ii
 if [ -f "RCS/$ii,v" ]; then
  #print "The file $ii already in RCS"
  ci -m"$description" $ii 
 else
  #print "The file $ii is new file"
  ci $ii << EOF
$description
EOF
 fi
done


Система сообщений об ошибках

Вместе с CVS Вы можете захотеть использовать "Систему отслеживания проекта" (Project Tracking System) или "Систему сообщений об ошибках" (Problem Reporting System). Каждый проект программного обеспечения нуждается в системе сообщений об ошибках, которая отслеживает ошибки и назначает их разным разработчикам. Посетите сайт http://www.stonekeep.com.


Другие форматы этого документа

Данный документ опубликован в 11 различных форматах: DVI, Postscript, Latex, Adobe Acrobat PDF, LyX, GNU-info, HTML, RTF (Rich Text Format), обычный текст, man-страницы Unix и SGML.

Документ написан с использованием инструмента под названием "SGML-Tools", который Вы можете получить с http://www.sgmltools.org. После компиляции исходного кода Вы получите команды подобные следующим:

  • sgml2html CVS-HOWTO.sgml (для генерации HTML-файла)

  • sgml2rtf CVS-HOWTO.sgml (для генерации RTF-файла)

  • sgml2latex CVS-HOWTO.sgml (для генерации Latex-файла)

LaTeX-документы можно преобразовать в PDF-файлы просто созданием Postscript-вывода с помощью sgml2latex (и dvips) и пропуском вывода через Acrobat-команду distill (http://www.adobe.com) как показано ниже:

bash$ man sgml2latex
bash$ sgml2latex filename.sgml
bash$ man dvips
bash$ dvips -o filename.ps filename.dvi
bash$ distill filename.ps
bash$ man ghostscript
bash$ man ps2pdf
bash$ ps2pdf input.ps output.pdf
bash$ acroread output.pdf &
Или можно использовать Ghostscript-команду ps2pdf. ps2pdf почти полностью повторяет функциональность продукта Adobe Acrobat Distiller: он преобразует PostScript-файлы в файлы Portable Document Format (PDF). ps2pdf реализован как очень маленький командный скрипт (пакетный файл), вызывающий Ghostscript и выбирающий специальное "выходное устройство" под именем pdfwrite. Для использования ps2pdf, в make-файл Ghostscript при компиляции необходимо включить устройство "pdfwrite"; чтобы получить более подробную информацию смотрите документацию по компиляции Ghostscript.

Этот документ расположен по адресу

Его можно найти также на следующих зеркалах:

Файлы формата DVI просматриваются с помощью программы xdvi. Она находится в пакете tetex-xdvi*.rpm на Redhat Linux и может быть доступна через ControlPanel | Applications | Publishing | меню для TeX. Для чтения DVI-документов выполните команду

 xdvi -geometry 80x90 howto.dvi
 man xdvi
Затем измените размер окна при помощи мыши. Для навигации используйте клавиши со стрелками, "Page Up", "Page Down", а также клавиши с буквами "f", "d", "u", "c", "l", "r", "p", "n" чтобы сместиться вверх, вниз, к следующей странице, предыдущей странице и т.д. Нажатие "x" убирает экспертное меню.

Postscript-файлы можно читать с помощью программы "gv" (ghostview) или "ghostscript". Программа ghostscript содержится в пакете ghostscript*.rpm, а gv -- в gv*.rpm на Redhat Linux; их можно найти в пункте меню ControlPanel | Applications | Graphics. Программа gv более дружественна к пользователю нежели ghostscript. Ghostscript и gv доступны и на других платформах, таких как OS/2, Windows 95 и NT, Вы сможете просмотреть этот документ даже на этих платформах.

Чтобы прочесть Postscript-документ наберите команду

  gv howto.ps
  ghostscript howto.ps

Документы в формате HTML можно читать с помощью Netscape Navigator, Microsoft Internet Explorer, Redhat Baron Web или любого из 10 остальных веб-браузеров.

Вывод Latex и LyX можно читать с помощью LyX -- X-Window-надстройки над Latex.


Авторские права и лицензия

Copyright Al Dev (Alavoor Vasudevan) 1998-2000.

Copyright 2000, 2001 Sultanbek Tezadov, translation into Russian.

Под лицезией GNU GPL с дополнительным требованием сохранять имя и e-mail автора во всех копиях.


sget

Замечание: оболочка Korn /bin/ksh устанавливается инсталляцией pdksh*.rpm с компакт-диска дистрибутива Linux

Сохраните этот файл как текст и выполните для него "chmod a+rx".

#!/bin/ksh

# CVS-программа sget
# Программа для извлечения файлов из CVS в режиме только для чтения

# Имя каждого файла составляется из 3 частей -- домашнего каталога,
# подкаталога и имени файла. Полный путь -- $HOME/$subdir/$fname
# В CVS сохраняется такая же структура каталогов (с помощью переменной
# $subdir), поэтому в CVS мы будем иметь $CVSROOT/$subdir/$fname
# В данной программе эти 4 переменные $HOME, $CVSROOT, $subdir и $fname
# играют важную роль. Примеры их значений:
# HOME=/home/aldev, subdir=myproject/src CVSROOT=/home/cvsroot 
# и fname=foo.cpp

# Предупреждение: заключите значения переменных, содержащих пробелы
# в двойные кавычки: "$HOME/$subdir", если subdir равен "some foo.cpp"

cmdname=`basename $0`

Usage()
{
 print "\nВызов: $cmdname [-r номер_редакции/символическое_имя_тэга] <файл/каталог> "
 print "Опции -r необязательны "
 print "Например: "
 print " $cmdname -r 1.1 foo.cpp"
 print " $cmdname foo.cpp "
 print " $cmdname некий_каталог "
 print "Извлечение по символическому тэгу редакции: "
 print " $cmdname -r РЕДАКЦИЯ_1 некий_каталог "
 print " "
 exit
}

# Каманда getopt не будет поддерживаться в следующей версии.
# Вместо нее используем getopts.
while getopts r: ii
do
 case $ii in
 r) FLAG1=$ii; OARG1="$OPTARG";;
 ?) Usage; exit 2;;
 esac
done
shift ` expr $OPTIND - 1 `

#echo FLAG1 = $FLAG1 , OARG1 = $OARG1

if [ $# -lt 1 ]; then
 Usage
fi

bkextn=sget_bak

homedir=` echo $HOME | cut -f1 -d' '  `
if [ "$homedir" = "" ]; then
 print "\nОшибка: \$HOME не установлен!!\n"
 exit
fi

cur_dir=`pwd`
#echo $cur_dir

len=${#homedir}
len=$(($len + 2))
#echo $len

subdir=` echo $cur_dir | cut -b $len-2000 `
#echo "subdir is : " $subdir
tmpaa=`dirname $1`
if [ "$tmpaa" = "." ]; then
 fname=$1
 if [ "$subdir" = "" ]; then
  subdir=$tmpaa
 fi
else
 fname=`basename $1`
 if [ "$subdir" = "" ]; then
  subdir=$tmpaa
 else
  subdir="$subdir/$tmpaa"
 fi
fi
#echo "subdir is : " $subdir
#echo "fname is : " $fname

# Проверка существования файла...
if [ -f "$HOME/$subdir/$fname" ]; then
 tmpaa="$HOME/$subdir/$fname"
 user_perms=" "
 group_perms=" "
 other_perms=" "
 user_perms=`ls -l $tmpaa | awk '{print $tmpaa }' | cut -b3-3 `
 group_perms=`ls -l $tmpaa | awk '{print $tmpaa }' | cut -b6-6 `
 other_perms=`ls -l $tmpaa | awk '{print $tmpaa }' | cut -b9-9 `
 if [ "$user_perms" = "w" -o "$group_perms" = "w"  \
   -o "$other_perms" = "w" ]; then
  print "\nОшибка: файл доступен для записи. Завершение $cmdname ......"
  print "       Следует либо сделать резервную копию, выполнить scommit"
  print "       или удалить файл и запустить $cmdname снова\n"
  exit
 fi
fi

# Перемещение файла
mkdir -p "$HOME/$subdir"
touch "$HOME/$subdir/$fname" 2>/dev/null
\mv -f "$HOME/$subdir/$fname" "$HOME/$subdir/$fname.$bkextn"

# Создание дочерней оболочки
(
 cd $homedir

 # Для очистки всех липких флагов используем опцию -A
 if [ "$FLAG1" = "" ]; then
  if [ "$subdir" = "." ]; then  # не использовать точку -- это смешает CVS
   cvs -r checkout -A $fname
  else
   cvs -r checkout -A "$subdir/$fname"
  fi
 else
  if [ "$subdir" = "." ]; then  # не использовать точку -- это смешает CVS
   cvs -r checkout -A -$FLAG1 $OARG1 $fname
  else
   cvs -r checkout -A -$FLAG1 $OARG1 "$subdir/$fname"
  fi
 fi
)
#pwd

if [ -f "$HOME/$subdir/$fname" ]; then
 print "\nПолучена копия файла $subdir/$fname только для чтения."
 print "$cmdname выполнен."
 #print "\nTip (Usage): $cmdname <file/directory name> \n"
fi


sedit

Замечание: оболочка Korn /bin/ksh устанавливается инсталляцией pdksh*.rpm с компакт-диска дистрибутива Linux

Сохраните этот файл как текст и выполните для него "chmod a+rx".

#!/bin/ksh

# CVS-программа sedit
# Программа для извлечения файла из CVS в режиме чтения/записи
# с блокировкой

# Имя каждого файла составляется из 3 частей -- домашнего каталога,
# подкаталога и имени файла. Полный путь -- $HOME/$subdir/$fname
# В CVS сохраняется такая же структура каталогов (с помощью переменной
# $subdir), поэтому в CVS мы будем иметь $CVSROOT/$subdir/$fname
# В данной программе эти 4 переменные $HOME, $CVSROOT, $subdir и $fname
# играют важную роль. Примеры их значений:
# HOME=/home/aldev, subdir=myproject/src CVSROOT=/home/cvsroot 
# и fname=foo.cpp

# Предупреждение: заключите значения переменных, содержащих пробелы
# в двойные кавычки: "$HOME/$subdir", если subdir равен "some foo.cpp"

cmdname=`basename $0`

Usage()
{
#       print "\nUsage: $cmdname [-r revision_number] [-F] <filename>"
#       print "The options -r, -F are optional "
#       print "The option -F is FORCE edit even if file is "
#       print "locked by another developer"

        print "\nВызов: $cmdname [-r номер_редакции] <файл>"
        print "Опции -r необязательны "

 print "Например: "
        print " $cmdname -r 1.1 foo.cpp"
        print " $cmdname foo.cpp "
#       print " $cmdname -F foo.cpp "
        print " "
}

# Каманда getopt не будет поддерживаться в следующей версии.
# Вместо нее используем getopts.
#while getopts r:F ii
while getopts r: ii
do
        case $ii in
        r) FLAG1=$ii; OARG1="$OPTARG";;
#       F) FLAG2=$ii; OARG2="$OPTARG";;
        ?) Usage; exit 2;;
        esac
done
shift ` expr $OPTIND - 1 `

#echo FLAG1 = $FLAG1 , OARG1 = $OARG1

if [ $# -lt 1 ]; then
        Usage
        exit
fi

homedir=` echo $HOME | cut -f1 -d' '  `
if [ "$homedir" = "" ]; then
        print "\nОшибка: \$HOME не установлен!!\n"
        exit
fi

bkextn=sedit_bak

cur_dir=`pwd`
#echo $cur_dir

len=${#homedir}
len=$(($len + 2))
#echo $len

subdir=` echo $cur_dir | cut -b $len-2000 `
tmpaa=`dirname $1`
if [ "$tmpaa" = "." ]; then
 fname=$1
 if [ "$subdir" = "" ]; then
  subdir=$tmpaa
 fi
else
 fname=`basename $1`
 if [ "$subdir" = "" ]; then
  subdir=$tmpaa
 else
  subdir="$subdir/$tmpaa"
 fi
fi
#echo "subdir is : " $subdir
#echo "fname is : " $fname

# Если файл уже извлечен другим разработчиком...
cvs_root=` echo $CVSROOT | cut -f1 -d' '  `
if [ "$cvs_root" = "" ]; then
        print "\nОшибка: \$CVSROOT не установлен!!\n"
        exit
fi
mkdir -p "$CVSROOT/$subdir/Locks" 2>/dev/null

if [ ! -e "$CVSROOT/$subdir/$fname,v" ]; then
        print "\nОшибка: файл $fname не существует в репозитории CVS!!\n"
        exit
fi

# Для всех команд требуется каталог CVS в Вашем локальном каталоге...
if [ ! -d  "$homedir/$subdir/CVS" ]; then
 tmpaa=` (cd "$CVSROOT/$subdir"; find * -prune -type f -print | head -1 ) `
 tmpbb=`basename $tmpaa | cut -d',' -f1 `
 if [ "$tmpaa" = "" -o ! -f "$CVSROOT/$subdir/$tmpbb,v" ]; then
  print "\nКаталог $homedir/$subdir/CVS не существует"
  print "Вы должны выполнить sget в каталоге `basename $subdir`. Наберите"
  print "       cd $homedir/`dirname $subdir` "
  print "       sget `basename $subdir` "
  exit
 else
  # Теперь попытка создать CVS в локальном каталоге с помощью sget
  (
   cd "$homedir"
   if [ "$subdir" = "." ]; then  # не использовать точку -- это смешает CVS
    cvs -r checkout -A $tmpbb
   else
    cvs -r checkout -A "$subdir/$tmpbb"
   fi
  )
 fi
fi

# Получение старшего номера редакции файла...
# Используем временный файл tmpfile, так как аргумент не может быть задан
# внутри дочерней оболочки
tmpfile=$homedir/sedit-lock.tmp
\rm -f $tmpfile 2>/dev/null
if [ "$FLAG1" = "" ]; then
 (
        cd $homedir
  if [ "$subdir" = "." ]; then  # не использовать точку -- это смешает CVS
   cvs log $fname | head -6 | grep head: | awk '{print $2}' > $tmpfile
  else
   cvs log "$subdir/$fname" | head -6 | grep head: | awk '{print $2}' > $tmpfile
  fi
 )
 OARG1=`cat $tmpfile`
 \rm -f $tmpfile 2>/dev/null
fi

lockfile="$CVSROOT/$subdir/Locks/$fname-$OARG1"
#echo "lockfile is : " $lockfile
#if [ -e $lockfile -a "$FLAG2" = "" ]; then
if [ -e $lockfile ]; then
        print "\nОшибка: файл $fname версии $OARG1 уже заблокирован другим разработчиком!!"
        aa=` ls -l $lockfile | awk '{print "Unix-имя бюджета блокирующего разработчика: " $3}' `
        print $aa
        print "Этот разработчик должен выполнить scommit или sunlock для разблокировки"
        print " "
#       print "Вы можете воспользоваться опцией -F чтобы вынудить редактирование файла даже если"
#       print "файл заблокирован другим разработчиком. Но Вы должны поговорить с"
#       print "остальными разработчиками прежде чем одновременно работать с этим файлом."
#       print "Например, эта возможность полезна, если Вы работаете над отдельной"
#       print "функцией C++ в файле, которая не пересекается с остальными разработчиками."
#       print " "
        exit
fi

# Теперь получение копии только для чтения...
if [ ! -e "$HOME/$subdir/$fname" ]; then
 (
        cd $homedir
  if [ "$subdir" = "." ]; then  # не использовать точку -- это смешает CVS
   cvs -r checkout $fname 1>/dev/null
  else
   cvs -r checkout "$subdir/$fname" 1>/dev/null
  fi
 )
fi

# Проверка существования файла...
tmpaa="$HOME/$subdir/$fname"
if [ -f $tmpaa ]; then
 user_perms=" "
 group_perms=" "
 other_perms=" "
 user_perms=`ls -l $tmpaa | awk '{print $tmpaa }' | cut -b3-3 `
 group_perms=`ls -l $tmpaa | awk '{print $tmpaa }' | cut -b6-6 `
 other_perms=`ls -l $tmpaa | awk '{print $tmpaa }' | cut -b9-9 `
 if [ "$user_perms" = "w" -o "$group_perms" = "w"  \
   -o "$other_perms" = "w" ]; then
  print "\nОшибка: файл доступен для записи. Завершение $cmdname ......"
  print "       Следует либо сделать резервную копию, выполнить scommit"
  print "       или удалить файл и запустить $cmdname снова\n"
  exit
 fi
 #print "\nNote: The file $tmpaa is read-only."
 #print "Hence I am moving it to $tmpaa.$bkextn ....\n"
 \mv -f $tmpaa $tmpaa.$bkextn
 chmod 444 $tmpaa.$bkextn
elif [ -d $tmpaa ]; then
 print "\nОшибка: $tmpaa является каталогом, а НЕ файлом. Завершение $cmdname ....\n"
 exit
fi

# Создание дочерней оболочки
print "\nПолучение файла $fname из CVS-репозитория...\n"
(
 cd $homedir
 # Используем опцию -A для очистки липкого тэга и получения
 # номер редакции HEAD
 if [ "$FLAG1" = "" ]; then
  if [ "$subdir" = "." ]; then  # не использовать точку -- это смешает CVS
   cvs -w checkout -A $fname
  else
   cvs -w checkout -A "$subdir/$fname"
  fi
 else
  if [ "$subdir" = "." ]; then  # не использовать точку -- это смешает CVS
   cvs -w checkout -A -$FLAG1 $OARG1 $fname
  else
   cvs -w checkout -A -$FLAG1 $OARG1 "$subdir/$fname"
  fi
 fi
)

if [ -e "$HOME/$subdir/$fname" ]; then
 # Файл блокировки -- $CVSROOT/$subdir/Locks/$fname-$OARG1
 touch $lockfile
fi

#pwd

print "\n$cmdname выполнен."
#print "\nTip (Usage): $cmdname <filename> \n"


scommit

Замечание: оболочка Korn /bin/ksh устанавливается инсталляцией pdksh*.rpm с компакт-диска дистрибутива Linux

Сохраните этот файл как текст и выполните для него "chmod a+rx".

#!/bin/ksh

# CVS-программа scommit
# Программа для фиксации изменений и загрузки файла в CVS

# Имя каждого файла составляется из 3 частей -- домашнего каталога,
# подкаталога и имени файла. Полный путь -- $HOME/$subdir/$fname
# В CVS сохраняется такая же структура каталогов (с помощью переменной
# $subdir), поэтому в CVS мы будем иметь $CVSROOT/$subdir/$fname
# В данной программе эти 4 переменные $HOME, $CVSROOT, $subdir и $fname
# играют важную роль. Примеры их значений:
# HOME=/home/aldev, subdir=myproject/src CVSROOT=/home/cvsroot 
# и fname=foo.cpp

# Предупреждение: заключите значения переменных, содержащих пробелы
# в двойные кавычки: "$HOME/$subdir", если subdir равен "some foo.cpp"

cmdname=`basename $0`

Usage()
{
 print "\nВызов: $cmdname [-r номер_редакции] <файл>"
 print "Опции -r необязательны "
 print "Например: "
 print " $cmdname -r 1.1 foo.cpp"
 print " $cmdname foo.cpp "
 print " "
}

# Каманда getopt не будет поддерживаться в следующей версии.
# Вместо нее используем getopts.
while getopts r: ii
do
 case $ii in
 r) FLAG1=$ii; OARG1="$OPTARG";;
 ?) Usage; exit 2;;
 esac
done
shift ` expr $OPTIND - 1 `

#echo FLAG1 = $FLAG1 , OARG1 = $OARG1

if [ $# -lt 1 ]; then
 Usage
 exit 2
fi

if [ -d $1 ]; then
 Usage
 exit 2
fi

homedir=` echo $HOME | cut -f1 -d' '  `
if [ "$homedir" = "" ]; then
        print "\nОшибка: \$HOME не установлен!!\n"
 exit
fi

# Определить подкаталог
cur_dir=`pwd`
#echo $cur_dir
len=${#homedir}
len=$(($len + 2))
#echo $len

subdir=` echo $cur_dir | cut -b $len-2000 `
tmpaa=`dirname $1`
if [ "$tmpaa" = "." ]; then
 fname=$1
 if [ "$subdir" = "" ]; then
  subdir=$tmpaa
 fi
else
 fname=`basename $1`
 if [ "$subdir" = "" ]; then
  subdir=$tmpaa
 else
  subdir="$subdir/$tmpaa"
 fi
fi
# echo "subdir is : " $subdir
# echo "fname is : " $fname

# Если файл уже извлечен другим разработчиком...
cvs_root=` echo $CVSROOT | cut -f1 -d' '  `
if [ "$cvs_root" = "" ]; then
        print "\nОшибка: \$CVSROOT не установлен!!\n"
 exit
fi
mkdir -p "$CVSROOT/$subdir/Locks" 2>/dev/null

# Для всех команд требуется каталог CVS в Вашем локальном каталоге...
if [ ! -d  "$homedir/$subdir/CVS" ]; then
 tmpaa=` (cd "$CVSROOT/$subdir"; find * -prune -type f -print | head -1 ) `
 tmpbb=`basename $tmpaa | cut -d',' -f1 `
 if [ "$tmpaa" = "" -o ! -f "$CVSROOT/$subdir/$tmpbb,v" ]; then
  print "\nКаталог $homedir/$subdir/CVS не существует"
  print "Вы должны выполнить sget в каталоге `basename $subdir`. Наберите"
  print "       cd $homedir/`dirname $subdir` "
  print "       sget `basename $subdir` "
  exit
 else
  # Теперь попытка создать CVS в локальном каталоге с помощью sget
  (
   cd "$homedir"
   if [ "$subdir" = "." ]; then  # не использовать точку -- это смешает CVS
    cvs -r checkout -A $tmpbb
   else
    cvs -r checkout -A "$subdir/$tmpbb"
   fi
  )
 fi
fi

# Получение рабочего номера версии файла...
# Используем временный файл tmpfile, так как аргумент не может быть задан
# внутри дочерней оболочки
tmpfile=$homedir/sedit-lock.tmp
\rm -f $tmpfile 2>/dev/null
if [ "$FLAG1" = "" ]; then
 (
        cd $homedir
  if [ "$subdir" = "." ]; then  # не использовать точку -- это смешает CVS
   cvs status $fname 2>/dev/null | grep "Рабочая версия:" | awk '{print $3}' >$tmpfile
  else
   cvs status "$subdir/$fname" 2>/dev/null | grep "Рабочая версия:" | awk '{print $3}' >$tmpfile
  fi
 )
 OARG1=`cat $tmpfile`
 \rm -f $tmpfile 2>/dev/null
fi

if [ "$OARG1" = "" ]; then
 print "Файл $subdir/$fname НОВЫЙ, его нет в CVS-репозитории"
else
 lockfile="$CVSROOT/$subdir/Locks/$fname-$OARG1"

 if [ -e $lockfile ]; then
  # Проверка владеете ли Вы редакцией...
  aa=` ls -l $lockfile | awk '{print $3}' `
  userid=`id | cut -d'(' -f2 | cut -d')' -f1 `
  if [ "$aa" != "$userid" ]; then
   print " "
   print "Файл $subdir/$fname заблокирован не Вами!!"
   print "А пользователем с именем Unix-бюджета $aa; Ваше имя входа -- $userid"
#                       print "Если Вы работаете одновременно с другим разработчиком"
#                       print "и воспользовались опцией -F команды sedit."
   print "Необходимо подождать до выполнения другим разработчиком"
   print "команды scommit или sunlock"
   print "Завершение $cmdname ...."
   print " "
   exit 2
  fi
 else
  # Файл должен существовать в CVS
  if [ -f "$CVSROOT/$subdir/$fname,v" ]; then
   print "Вы не заблокировали файл $subdir/$fname с помощью sedit!!"
   print "Завершение $cmdname ...."
   exit 2
  else
   print "\nФайл $subdir/$fname еще не существует CVS-репозитории!!"
   print "Следует выполнить sadd для $subdir/$fname ...."
   exit 2
  fi
 fi
fi

# Действуем внутри дочерней оболочки и из корневого каталога
(
 cd $homedir

 # Не позволять фиксацию каталогов с этого момента...
 #if [ -d "$subdir/$fname" ]; then
 # cvs commit "$subdir/$fname"
 #fi

 if [ "$subdir" = "." ]; then  # не использовать точку -- это смешает CVS
  cvs commit $fname
 else
  cvs commit "$subdir/$fname"
 fi
 exit_status=$?

 if [ $exit_status -eq 0 ]; then
  lockfile="$CVSROOT/$subdir/Locks/$fname-$OARG1"
  if [ -e $lockfile ]; then
   \rm -f $lockfile
  fi

  # В случае отсутствия изменений в файле, нужно
  # изменить права доступа к файлу
  chmod a-w "$HOME/$subdir/$fname"
  print "\n$cmdname удачно выполнен."
  #print "\nTip (Usage): $cmdname <filename/directory name>\n"
 fi
)


supdate

Замечание: оболочка Korn /bin/ksh устанавливается инсталляцией pdksh*.rpm с компакт-диска дистрибутива Linux

Сохраните этот файл как текст и выполните для него "chmod a+rx".

#!/bin/ksh

# CVS-программа supdate
# Программа для обновления файла из CVS в режиме чтения/записи

# Имя каждого файла составляется из 3 частей -- домашнего каталога,
# подкаталога и имени файла. Полный путь -- $HOME/$subdir/$fname
# В CVS сохраняется такая же структура каталогов (с помощью переменной
# $subdir), поэтому в CVS мы будем иметь $CVSROOT/$subdir/$fname
# В данной программе эти 4 переменные $HOME, $CVSROOT, $subdir и $fname
# играют важную роль. Примеры их значений:
# HOME=/home/aldev, subdir=myproject/src CVSROOT=/home/cvsroot 
# и fname=foo.cpp

# Предупреждение: заключите значения переменных, содержащих пробелы
# в двойные кавычки: "$HOME/$subdir", если subdir равен "some foo.cpp"

cmdname=`basename $0`

if [ $# -lt 1 ]; then
 print "\nВызов: $cmdname <файл>"
 exit
fi

# Двойные кавычки для защиты пробелов в $1
tmpaa="$1"

# Проверка существования файла...
if [ $# -gt 0 -a  -f $tmpaa ]; then
 user_perms=" "
 group_perms=" "
 other_perms=" "
 user_perms=`ls -l $tmpaa | awk '{print $tmpaa }' | cut -b3-3 `
 group_perms=`ls -l $tmpaa | awk '{print $tmpaa }' | cut -b6-6 `
 other_perms=`ls -l $tmpaa | awk '{print $tmpaa }' | cut -b9-9 `
 if [ "$user_perms" = "w" -o "$group_perms" = "w"  \
   -o "$other_perms" = "w" ]; then
  while :
  do
   print "\n$cmdname сделает резервную копию Вашего рабочего файла "
   print "$tmpaa в $tmpaa.supdate_bak перед выполнением слияния."
   print "Вы уверены в желании объединения изменений из"
   print -n "CVS-репозитория с Вашим рабочим файлом? <y/n> [n]: "
   read ans
   if [ "$ans" = "y" -o "$ans" = "Y" ]; then
    if [ -f $tmpaa.supdate_bak ]; then
     print "\nВнимание: файл $tmpaa.supdate_bak уже существует!!"
     print "Пожалуйста просмотрите файл $tmpaa.supdate_bak и удалите его,"
     print "а затем повторно выполните эту команду $cmdname "
     print "Завершение $cmdname ...."
     exit
    else
     cp $tmpaa $tmpaa.supdate_bak
     break
    fi
   elif [ "$ans" = "n" -o "$ans" = "N" -o "$ans" = "" -o "$ans" = " " ]; then
    exit
   fi
  done
 fi
fi

if [ -d $tmpaa ]; then
 print "\nОбновление каталога недоступно, потому что CVS update"
 print "объединяет изменения из репозитория с Вашим рабочим каталогом."
 print "Поэтому укажите файл для обновления, как показано ниже: "
 print " Вызов: $cmdname <файл>"
 exit
#       cvs update
else
 cvs update $tmpaa
fi

print "\n$cmdname удачно выполнен."
print "\n\nСделана резервная копия исходного файла как $tmpaa.supdate_bak"
print "\nПоэтому Ваш исходный файл СОХРАНЕН в $tmpaa.supdate_bak"
print "\n\n"
#print "\nTip (Usage): $cmdname <filename/directory name>\n"


sunlock

Замечание: оболочка Korn /bin/ksh устанавливается инсталляцией pdksh*.rpm с компакт-диска дистрибутива Linux

Сохраните этот файл как текст и выполните для него "chmod a+rx".

#!/bin/ksh

# CVS-программа sunlock
# Программа разблокировки файла, заблокированного sedit

# Имя каждого файла составляется из 3 частей -- домашнего каталога,
# подкаталога и имени файла. Полный путь -- $HOME/$subdir/$fname
# В CVS сохраняется такая же структура каталогов (с помощью переменной
# $subdir), поэтому в CVS мы будем иметь $CVSROOT/$subdir/$fname
# В данной программе эти 4 переменные $HOME, $CVSROOT, $subdir и $fname
# играют важную роль. Примеры их значений:
# HOME=/home/aldev, subdir=myproject/src CVSROOT=/home/cvsroot 
# и fname=foo.cpp

# Предупреждение: заключите значения переменных, содержащих пробелы
# в двойные кавычки: "$HOME/$subdir", если subdir равен "some foo.cpp"

cmdname=`basename $0`

Usage()
{
 print "\nВызов: $cmdname [-r номер_редакции] <файл>"
 print "Опции -r необязательны "
 print "Например: "
 print " $cmdname -r 1.1 foo.cpp"
 print " $cmdname foo.cpp "
 print " "
}

# Каманда getopt не будет поддерживаться в следующей версии.
# Вместо нее используем getopts.
while getopts r: ii
do
 case $ii in
 r) FLAG1=$ii; OARG1="$OPTARG";;
 ?) Usage; exit 2;;
 esac
done
shift ` expr $OPTIND - 1 `

if [ $# -lt 1 ]; then
 Usage
 exit
fi

homedir=` echo $HOME | cut -f1 -d' '  `
if [ "$homedir" = "" ]; then
        print "\nОшибка: \$HOME не установлен!!\n"
 exit
fi

cur_dir=`pwd`
#echo $cur_dir

len=${#homedir}
len=$(($len + 2))
#echo $len

subdir=` echo $cur_dir | cut -b $len-2000 `
#echo "subdir is : " $subdir
tmpaa=`dirname $1`
if [ "$tmpaa" = "." ]; then
 fname=$1
 if [ "$subdir" = "" ]; then
  subdir=$tmpaa
 fi
else
 fname=`basename $1`
 if [ "$subdir" = "" ]; then
  subdir=$tmpaa
 else
  subdir="$subdir/$tmpaa"
 fi
fi
#echo "subdir is : " $subdir
#echo "fname is : " $fname

cvs_root=` echo $CVSROOT | cut -f1 -d' '  `
if [ "$cvs_root" = "" ]; then
        print "\nОшибка: \$CVSROOT не установлен!!\n"
 exit
fi

if [ ! -e "$CVSROOT/$subdir/$fname,v" ]; then
 print "\nОшибка: файл $fname отсутствует в CVS-репозитории!!\n"
 exit
fi

# Для всех команд требуется каталог CVS в Вашем локальном каталоге...
if [ ! -d  "$homedir/$subdir/CVS" ]; then
 tmpaa=` (cd "$CVSROOT/$subdir"; find * -prune -type f -print | head -1 ) `
 tmpbb=`basename $tmpaa | cut -d',' -f1 `
 if [ "$tmpaa" = "" -o ! -f "$CVSROOT/$subdir/$tmpbb,v" ]; then
  print "\nКаталог $homedir/$subdir/CVS не существует"
  print "Вы должны выполнить sget в каталоге `basename $subdir`. Наберите"
  print "       cd $homedir/`dirname $subdir` "
  print "       sget `basename $subdir` "
  exit
 else
  # Теперь попытка создать CVS в локальном каталоге с помощью sget
  (
   cd "$homedir"
   if [ "$subdir" = "." ]; then  # не использовать точку -- это смешает CVS
    cvs -r checkout -A $tmpbb
   else
    cvs -r checkout -A "$subdir/$tmpbb"
   fi
  )
 fi
fi

# Получение старшего номера редакции файла...
# Используем временный файл tmpfile, так как аргумент не может быть задан
# внутри дочерней оболочки
tmpfile=$homedir/sunlock-lock.tmp
\rm -f $tmpfile 2>/dev/null
if [ "$FLAG1" = "" ]; then
 # Действуем внутри дочерней оболочки и из корневого каталога
 (
        cd $homedir
  if [ "$subdir" = "." ]; then  # не использовать точку -- это смешает CVS
   cvs log $fname | head -6 | grep head: | awk '{print $2}' > $tmpfile
  else
   cvs log "$subdir/$fname" | head -6 | grep head: | awk '{print $2}' > $tmpfile
  fi
 )
 OARG1=`cat $tmpfile`
 \rm -f $tmpfile 2>/dev/null
fi

lockfile="$CVSROOT/$subdir/Locks/$fname-$OARG1"
#echo lockfile is : $lockfile
if [ ! -e $lockfile ]; then
 print "\nФайл $fname редакции $OARG1 НЕ заблокирован никем"
 print " "
 exit
fi

ans=""
while :
do
 print "\n\n***************************************************"
 print "ВНИМАНИЕ: $cmdname уберет блокировку и другие разработчики"
 print "         смогут редактировать файл. Рекомендуется сохранить"
 print "         Ваши изменения командой scommit"
 print "***************************************************"
 print -n "\nВы действительно хотите разблокировать файл <y/n>? [n]: "
 read ans
 if [ "$ans" = "" -o "$ans" = " " -o "$ans" = "n" -o "$ans" = "N" ]; then
  print "\nЗавершение $cmdname..."
  exit
 fi
 if [ "$ans" = "y" -o "$ans" = "Y" ]; then
  print "\n\n\n\n\n "
  print "ПРЕДУПРЕЖДЕНИЕ: Вы можете потерять все изменения файла!!"
  print -n "Вы уверены? Действительно ли Вы хотите разблокировать файл <y/n>? [n]: "
  read ans
  if [ "$ans" = "y" -o "$ans" = "Y" ]; then
   break
  elif [ "$ans" = "" -o "$ans" = " " -o "$ans" = "n" -o "$ans" = "N" ]; then
   exit
  else
   print "\n\nОшибка ввода. Попробуйте снова..."
   sleep 1
  fi
 else
  print "\n\nОшибка ввода. Попробуйте снова..."
  sleep 1
 fi
done

if [ -e $lockfile ]; then
 \rm -f $lockfile
 print "\n$cmdname выполнен"
else
 print "\nФайл $fname больше никем НЕ заблокирован"
 print " "
fi


slist

Замечание: оболочка Korn /bin/ksh устанавливается инсталляцией pdksh*.rpm с компакт-диска дистрибутива Linux

Сохраните этот файл как текст и выполните для него "chmod a+rx".

Заметьте, что есть другая Unix-команда с именем slist (список доступных серверов Netware), следует удостовериться, что CVS-скрипт slist встречается раньше другого в Вашей переменной окружения PATH.

#!/bin/ksh

# CVS-программа slist
# Программа перечисления всех отредактированных файлов исходного кода из CVS

# Имя каждого файла составляется из 3 частей -- домашнего каталога,
# подкаталога и имени файла. Полный путь -- $HOME/$subdir/$fname
# В CVS сохраняется такая же структура каталогов (с помощью переменной
# $subdir), поэтому в CVS мы будем иметь $CVSROOT/$subdir/$fname
# В данной программе эти 4 переменные $HOME, $CVSROOT, $subdir и $fname
# играют важную роль. Примеры их значений:
# HOME=/home/aldev, subdir=myproject/src CVSROOT=/home/cvsroot 
# и fname=foo.cpp

# Предупреждение: заключите значения переменных, содержащих пробелы
# в двойные кавычки: "$HOME/$subdir", если subdir равен "some foo.cpp"

# Вызов:
#   $ slist      (Все файлы и подкаталоги)
#   $ slist *.*      (Все файлы)
#   $ slist *      (Все файлы и подкаталоги)
#   $ slist ab*      (Все файлы, начинающиеся на "ab")

homedir=` echo $HOME | cut -f1 -d' '  `
if [ "$homedir" = "" ]; then
        print "\nОшибка: \$HOME не установлен!!\n"
 exit
fi

cur_dir=`pwd`
#echo $cur_dir

len=${#homedir}
len=$(($len + 2))
#echo $len

subdir=` echo $cur_dir | cut -b $len-2000 `
#echo "subdir is : " $subdir

# Если файл уже извлечен другим разработчиком...
cvs_root=` echo $CVSROOT | cut -f1 -d' '  `
if [ "$cvs_root" = "" ]; then
        print "\nОшибка: \$CVSROOT не установлен!!\n"
        exit
fi

# Если текущий каталог не находится в корне CVS, то выход
if [ ! -d $CVSROOT/$subdir ]; then
 print "\nКаталог $subdir не существует в $CVSROOT"
 exit
fi

#echo "no of params : " $#
#echo "The arg $ 1 is : " $1
#echo "all args : " $@

if [ $# -eq 0 ]; then
 tmpbb=` find * -prune -type d `
elif [ $# -eq 1 ]; then
 if [ "$1" = "." ]; then
  tmpbb=` find * -prune -type d `
 else
  if [ -d $1 -a ! -d $CVSROOT/$subdir/$1 ]; then
   print "\nКаталог $subdir/$1 не существует в $CVSROOT"
   exit
  fi
  tmpbb=$@
 fi
else
 tmpbb=$@
fi

#echo "The tmpbb is : " $tmpbb

# Теперь удалим все имена каталогов, не существующих в корне CVS 
dirnames=""
for ii in $tmpbb ; do
 if [ -d $CVSROOT/$subdir/$ii ]; then
  dirnames="$dirnames $ii "
 fi
done
#echo "The dirnames is : " $dirnames

if [ "$dirnames" != "" ]; then
 find $dirnames  -type f |
 while read ii
 do
  # Перечислить только те файлы, которые находятся в CVS-системе
  if [ -f "$CVSROOT/$subdir/$ii,v" ]; then
   #echo "ii is : " $ii
   ls -l $ii | grep ^\-rw
  fi
 done;
fi

# Получить все файлы в текущем каталоге
listfiles=`ls $tmpbb `
find * -prune -type f |
while read ii
do
 for jj in $listfiles ; do
  if [ "$jj" = "$ii" ]; then
   # Перечислить только те файлы, которые находятся в CVS-системе
   if [ -f "$CVSROOT/$subdir/$ii,v" ]; then
    #echo "ii is : " $ii
    ls -l $ii | grep ^\-rw
   fi
  fi
 done
done;


sinfo

Замечание: оболочка Korn /bin/ksh устанавливается инсталляцией pdksh*.rpm с компакт-диска дистрибутива Linux

Сохраните этот файл как текст и выполните для него "chmod a+rx".

#!/bin/ksh

# CVS-программа sinfo
# Программа для получения статуса файлов в рабочем каталоге

# Имя каждого файла составляется из 3 частей -- домашнего каталога,
# подкаталога и имени файла. Полный путь -- $HOME/$subdir/$fname
# В CVS сохраняется такая же структура каталогов (с помощью переменной
# $subdir), поэтому в CVS мы будем иметь $CVSROOT/$subdir/$fname
# В данной программе эти 4 переменные $HOME, $CVSROOT, $subdir и $fname
# играют важную роль. Примеры их значений:
# HOME=/home/aldev, subdir=myproject/src CVSROOT=/home/cvsroot 
# и fname=foo.cpp

# Предупреждение: заключите значения переменных, содержащих пробелы
# в двойные кавычки: "$HOME/$subdir", если subdir равен "some foo.cpp"

cmdname=`basename $0`

if [ $# -lt 1 ]; then
 print "\nВызов: $cmdname [имя файла/каталога] "
 print "Например: "
 print " $cmdname foo.cpp"
 print " $cmdname some_directory "
 print " "
 exit
fi

homedir=` echo $HOME | cut -f1 -d' '  `
if [ "$homedir" = "" ]; then
        print "\nОшибка: \$HOME не установлен!!\n"
 exit
fi

cur_dir=`pwd`
#echo $cur_dir

len=${#homedir}
len=$(($len + 2))
#echo $len

subdir=` echo $cur_dir | cut -b $len-2000 `
#echo "subdir is : " $subdir
tmpaa=`dirname $1`
if [ "$tmpaa" = "." ]; then
 fname=$1
 if [ "$subdir" = "" ]; then
  subdir=$tmpaa
 fi
else
 fname=`basename $1`
 if [ "$subdir" = "" ]; then
  subdir=$tmpaa
 else
  subdir="$subdir/$tmpaa"
 fi
fi
#echo "subdir is : " $subdir
#echo "fname is : " $fname

# Для всех команд требуется каталог CVS в Вашем локальном каталоге...
if [ ! -d  "$homedir/$subdir/CVS" ]; then
 tmpaa=` (cd "$CVSROOT/$subdir"; find * -prune -type f -print | head -1 ) `
 tmpbb=`basename $tmpaa | cut -d',' -f1 `
 if [ "$tmpaa" = "" -o ! -f "$CVSROOT/$subdir/$tmpbb,v" ]; then
  print "\nКаталог $homedir/$subdir/CVS не существует"
  print "Вы должны выполнить sget в каталоге `basename $subdir`. Наберите"
  print "       cd $homedir/`dirname $subdir` "
  print "       sget `basename $subdir` "
  exit
 else
  # Теперь попытка создать CVS в локальном каталоге с помощью sget
  (
   cd "$homedir"
   if [ "$subdir" = "." ]; then  # не использовать точку -- это смешает CVS
    cvs -r checkout -A $tmpbb
   else
    cvs -r checkout -A "$subdir/$tmpbb"
   fi
  )
 fi
fi

# Создание дочерней оболочки
if [ -f $1 ]; then
 (
        cd $homedir
  clear
  print "\nстатус CVS: "
        cvs status "$subdir/$fname"
 )
elif [ -d $1 ]; then
 (
  cd $homedir
  clear
  print "\nстатус CVS: "
  tmpfile="$homedir/cvs_sinfo.tmp"
  rm -f $tmpfile
        echo "  " >> $tmpfile
        echo "  ****************************************" >> $tmpfile
        echo "        Полный статус каталога" >> $tmpfile
        echo "  ****************************************" >> $tmpfile
        cvs release "$subdir/$fname" 1>>$tmpfile 2>>$tmpfile << EOF
N
EOF
        echo "\n   -------------------------------\n" >> $tmpfile

        aa=`cat $tmpfile | grep ^"M " | awk '{print $2}' `
        for ii in $aa
        do
   jj="(cd $homedir; cvs status \"$subdir/$ii\" );"
   echo $jj | /bin/sh  \
     | grep -v Sticky | awk '{if (NF != 0) print $0}' \
     1>>$tmpfile 2>>$tmpfile
        done

        cat $tmpfile | grep -v ^? | grep -v "Are you sure you want to release" \
        | less
        rm -f $tmpfile
 )
else
 print "\nАргумент $1 не файл или каталог"
 exit
fi


slog

Замечание: оболочка Korn /bin/ksh устанавливается инсталляцией pdksh*.rpm с компакт-диска дистрибутива Linux

Сохраните этот файл как текст и выполните для него "chmod a+rx".

#!/bin/ksh

# CVS-программа slog
# Программа перечисления истории файла в CVS

# Имя каждого файла составляется из 3 частей -- домашнего каталога,
# подкаталога и имени файла. Полный путь -- $HOME/$subdir/$fname
# В CVS сохраняется такая же структура каталогов (с помощью переменной
# $subdir), поэтому в CVS мы будем иметь $CVSROOT/$subdir/$fname
# В данной программе эти 4 переменные $HOME, $CVSROOT, $subdir и $fname
# играют важную роль. Примеры их значений:
# HOME=/home/aldev, subdir=myproject/src CVSROOT=/home/cvsroot 
# и fname=foo.cpp

# Предупреждение: заключите значения переменных, содержащих пробелы
# в двойные кавычки: "$HOME/$subdir", если subdir равен "some foo.cpp"

cmdname=`basename $0`

if [ $# -lt 1 ]; then
        print "\nВызов: $cmdname <файл> \n"
        exit
fi

# Проверка существования файла...
if [ ! -f "$1" ]; then
        print "\nОшибка: $1 НЕ файл. Завершение $cmdname ......"
        exit
fi

homedir=` echo $HOME | cut -f1 -d' '  `
if [ "$homedir" = "" ]; then
        print "\nОшибка: \$HOME не установлен!!\n"
 exit
fi

cur_dir=`pwd`
#echo $cur_dir

len=${#homedir}
len=$(($len + 2))
#echo $len

subdir=` echo $cur_dir | cut -b $len-2000 `
#echo "subdir is : " $subdir
tmpaa=`dirname $1`
if [ "$tmpaa" = "." ]; then
 fname="$1"
 if [ "$subdir" = "" ]; then
  subdir=$tmpaa
 fi
else
 fname=`basename $1`
 if [ "$subdir" = "" ]; then
  subdir=$tmpaa
 else
  subdir="$subdir/$tmpaa"
 fi
fi
#echo "subdir is : " $subdir
#echo "fname is : " $fname

# Для всех команд требуется каталог CVS в Вашем локальном каталоге...
if [ ! -d  "$homedir/$subdir/CVS" ]; then
 tmpaa=` (cd "$CVSROOT/$subdir"; find * -prune -type f -print | head -1 ) `
 tmpbb=`basename $tmpaa | cut -d',' -f1 `
 if [ "$tmpaa" = "" -o ! -f "$CVSROOT/$subdir/$tmpbb,v" ]; then
  print "\nКаталог $homedir/$subdir/CVS не существует"
  print "Вы должны выполнить sget в каталоге `basename $subdir`. Наберите"
  print "       cd $homedir/`dirname $subdir` "
  print "       sget `basename $subdir` "
  exit
 else
  # Теперь попытка создать CVS в локальном каталоге с помощью sget
  (
   cd "$homedir"
   if [ "$subdir" = "." ]; then  # не использовать точку -- это смешает CVS
    cvs -r checkout -A $tmpbb
   else
    cvs -r checkout -A "$subdir/$tmpbb"
   fi
  )
 fi
fi

# Действовать внутри дочерней оболочки
(
 cd $homedir
 cvs log "$homedir/$subdir/$fname" | less
)

print "\n$cmdname удачно завершен."
#print "\nTip (Usage): $cmdname <filename>\n"


sdif

Замечание: оболочка Korn /bin/ksh устанавливается инсталляцией pdksh*.rpm с компакт-диска дистрибутива Linux

Сохраните этот файл как текст и выполните для него "chmod a+rx".

#!/bin/ksh

# CVS-программа sdif
# Программа просмотра отличий рабочего файла от CVS-копии

# Имя каждого файла составляется из 3 частей -- домашнего каталога,
# подкаталога и имени файла. Полный путь -- $HOME/$subdir/$fname
# В CVS сохраняется такая же структура каталогов (с помощью переменной
# $subdir), поэтому в CVS мы будем иметь $CVSROOT/$subdir/$fname
# В данной программе эти 4 переменные $HOME, $CVSROOT, $subdir и $fname
# играют важную роль. Примеры их значений:
# HOME=/home/aldev, subdir=myproject/src CVSROOT=/home/cvsroot 
# и fname=foo.cpp

# Предупреждение: заключите значения переменных, содержащих пробелы
# в двойные кавычки: "$HOME/$subdir", если subdir равен "some foo.cpp"

cmdname=`basename $0`

Usage()
{
 print "\nВызов: $cmdname <файл> "
 print "$cmdname -r<rev1> -r<rev2> <файл> \n"
 exit
}

homedir=` echo $HOME | cut -f1 -d' '  `
if [ "$homedir" = "" ]; then
        print "\nОшибка: \$HOME не установлен!!\n"
 exit
fi

FLAG1=""
FLAG2=""
OARG1=""
OARG2=""
# Каманда getopt не будет поддерживаться в следующей версии.
# Вместо нее используем getopts.
while getopts r:r: ii
do
 case $ii in
 r)
  if [ "$FLAG1" = "" ]; then
   FLAG1=$ii;
   OARG1="$OPTARG"
  else
   FLAG2=$ii;
   OARG2="$OPTARG"
  fi
  ;;
 ?) Usage; exit 2;;
 esac
done
shift ` expr $OPTIND - 1 `

if [ "$FLAG2" = "" ]; then
 FLAG2=r
 OARG2=HEAD
fi

cur_dir=`pwd`
#echo $cur_dir

len=${#homedir}
len=$(($len + 2))
#echo $len

subdir=` echo $cur_dir | cut -b $len-2000 `
#echo "subdir is : " $subdir
tmpaa=`dirname $1`
if [ "$tmpaa" = "." ]; then
 fname="$1"
 if [ "$subdir" = "" ]; then
  subdir=$tmpaa
 fi
else
 fname=`basename $1`
 if [ "$subdir" = "" ]; then
  subdir=$tmpaa
 else
  subdir="$subdir/$tmpaa"
 fi
fi
#echo "subdir is : " $subdir
#echo "fname is : " $fname

# Для всех команд требуется каталог CVS в Вашем локальном каталоге...
if [ ! -d  "$homedir/$subdir/CVS" ]; then
 tmpaa=` (cd "$CVSROOT/$subdir"; find * -prune -type f -print | head -1 ) `
 tmpbb=`basename $tmpaa | cut -d',' -f1 `
 if [ "$tmpaa" = "" -o ! -f "$CVSROOT/$subdir/$tmpbb,v" ]; then
  print "\nКаталог $homedir/$subdir/CVS не существует"
  print "Вы должны выполнить sget в каталоге `basename $subdir`. Наберите"
  print "       cd $homedir/`dirname $subdir` "
  print "       sget `basename $subdir` "
  exit
 else
  # Теперь попытка создать CVS в локальном каталоге с помощью sget
  (
   cd "$homedir"
   if [ "$subdir" = "." ]; then  # не использовать точку -- это смешает CVS
    cvs -r checkout -A $tmpbb
   else
    cvs -r checkout -A "$subdir/$tmpbb"
   fi
  )
 fi
fi

# Действовать внутри дочерней оболочки
(
 cd $homedir
 if [ "$FLAG1" = "" ]; then
  cvs diff -r HEAD "$homedir/$subdir/$fname" | less
 else
  cvs diff -$FLAG1 $OARG1 -$FLAG2 $OARG2 "$homedir/$subdir/$fname" | less
 fi
)


sadd

Замечание: оболочка Korn /bin/ksh устанавливается инсталляцией pdksh*.rpm с компакт-диска дистрибутива Linux

Сохраните этот файл как текст и выполните для него "chmod a+rx".

#!/bin/ksh

# CVS-программа sadd
# Программа добавления файла в CVS

# Имя каждого файла составляется из 3 частей -- домашнего каталога,
# подкаталога и имени файла. Полный путь -- $HOME/$subdir/$fname
# В CVS сохраняется такая же структура каталогов (с помощью переменной
# $subdir), поэтому в CVS мы будем иметь $CVSROOT/$subdir/$fname
# В данной программе эти 4 переменные $HOME, $CVSROOT, $subdir и $fname
# играют важную роль. Примеры их значений:
# HOME=/home/aldev, subdir=myproject/src CVSROOT=/home/cvsroot 
# и fname=foo.cpp

# Предупреждение: заключите значения переменных, содержащих пробелы
# в двойные кавычки: "$HOME/$subdir", если subdir равен "some foo.cpp"

cmdname=`basename $0`
if [ $# -lt 1 ]; then
 print "\nВызов: $cmdname <файл/каталог> \n"
 exit
fi

onearg="$1"
if [ ! -f "$onearg" -a ! -d "$onearg" ]; then
 print "\nАргумент $onearg не файл или каталог!"
 print "Вызов: $cmdname <файл/каталог> \n"
 exit
fi

# Аргумент имя каталога .....
homedir=` echo $HOME | cut -f1 -d' '  `
if [ "$homedir" = "" ]; then
        print "\nОшибка: \$HOME не установлен!!\n"
 exit
fi

cvs_root=` echo $CVSROOT | cut -f1 -d' '  `
if [ "$cvs_root" = "" ]; then
        print "\nОшибка: \$CVSROOT не установлен!!\n"
        exit
fi

cur_dir=`pwd`
len=${#homedir}
len=$(($len + 2))
subdir=` echo $cur_dir | cut -b $len-2000 `
#echo "subdir is : " $subdir
tmpaa=`dirname "$onearg" `
if [ "$tmpaa" = "." ]; then
 fname="$onearg"
 if [ "$subdir" = "" ]; then
  subdir=$tmpaa
 fi
else
 fname=`basename "$onearg" `
 if [ "$subdir" = "" ]; then
  subdir=$tmpaa
 else
  subdir="$subdir/$tmpaa"
 fi
fi
#echo "subdir is : " $subdir
#echo "fname is : " $fname

# Для всех команд требуется каталог CVS в Вашем локальном каталоге...
if [ ! -d  "$homedir/$subdir/CVS" ]; then
 tmpaa=` (cd "$CVSROOT/$subdir"; find * -prune -type f -print | head -1 ) `
 tmpbb=`basename $tmpaa | cut -d',' -f1 `
 if [ "$tmpaa" = "" -o ! -f "$CVSROOT/$subdir/$tmpbb,v" ]; then
  print "\nКаталог $homedir/$subdir/CVS не существует"
  print "Вы должны выполнить sget в каталоге `basename $subdir`. Наберите"
  print "       cd $homedir/`dirname $subdir` "
  print "       sget `basename $subdir` "
  exit
 else
  # Теперь попытка создать CVS в локальном каталоге с помощью sget
  (
   cd "$homedir"
   if [ "$subdir" = "." ]; then  # не использовать точку -- это смешает CVS
    cvs -r checkout -A $tmpbb
   else
    cvs -r checkout -A "$subdir/$tmpbb"
   fi
  )
 fi
fi

# Проверка существования файла...
if [ $# -eq 1 ]; then
 if [ -f "$onearg" ]; then
  cvs add "$onearg"
  exit
 fi
elif [ $# -gt 1 ]; then
 print "\n\n\nДобавление всех файлов в текущем каталоге к CVS"
 print "Каталоги добавлены не будут"
 print -n "Нажмите ВВОД для продолжения или CTRL+C для прервания..."
 read ans
 for ii in $@
 do
  if [ -f "$ii" ]; then
   cvs add "$ii"
  fi
 done;
 exit
fi

# Когда $subdir равен ".", мы в корневом каталоге
if [ "$subdir" = "." ]; then
 # В этом месте $onearg -- каталог, а не файл...
 if [ -d "$CVSROOT/$onearg" ]; then
  print "\nКаталог $onearg уже существует в CVSROOT"
  exit
 else
  # Добавление в корневой каталог $CVSROOT
  if [ "$2" = "" -o "$3" = "" ]; then
   print "\nВызов: $cmdname <каталог> <тэг поставщика> <тэг редакции>"
   print "Например: "
   print " $cmdname foo_directory V_1_0 R_1_0"
   exit
  else
   (
    cd "$homedir/$subdir";
    cvs import "$onearg" $2 $3
   )
  fi
 fi
else
 # Если текущий каталог существует в CVS...
 if [ -d "$CVSROOT/$subdir/$onearg" ]; then
  print "\nКаталог $onearg уже в CVS-репозитории!"
  exit
 else
  (
   if [ -d "$homedir/$subdir/$onearg/CVS" ]; then 
    print "\nОшибка: Каталог $homedir/$subdir/$onearg/CVS существует!!"
    print "\nЗавершение работы..."
    exit
   fi

   # Для импорта мы ДОЛЖНЫ перейти в каталог назначения
   # и указать полный путь, начинающийся с $subdir
   cd "$homedir/$subdir/$onearg";
   cvs import "$subdir/$onearg" Ver_1 Rel_1
  )
 fi
fi


sdelete

Замечание: оболочка Korn /bin/ksh устанавливается инсталляцией pdksh*.rpm с компакт-диска дистрибутива Linux

Сохраните этот файл как текст и выполните для него "chmod a+rx".

#!/bin/ksh

# CVS-программа sdelete
# Программа удаления файла из CVS

# Имя каждого файла составляется из 3 частей -- домашнего каталога,
# подкаталога и имени файла. Полный путь -- $HOME/$subdir/$fname
# В CVS сохраняется такая же структура каталогов (с помощью переменной
# $subdir), поэтому в CVS мы будем иметь $CVSROOT/$subdir/$fname
# В данной программе эти 4 переменные $HOME, $CVSROOT, $subdir и $fname
# играют важную роль. Примеры их значений:
# HOME=/home/aldev, subdir=myproject/src CVSROOT=/home/cvsroot 
# и fname=foo.cpp

# Предупреждение: заключите значения переменных, содержащих пробелы
# в двойные кавычки: "$HOME/$subdir", если subdir равен "some foo.cpp"

cmdname=`basename $0`

if [ $# -lt 1 ]; then
 print "\nВызов: $cmdname <файл> \n"
 exit
fi

onearg="$1"

homedir=` echo $HOME | cut -f1 -d' '  `
if [ "$homedir" = "" ]; then
        print "\nОшибка: \$HOME не установлен!!\n"
 exit
fi

cur_dir=`pwd`
len=${#homedir}
len=$(($len + 2))
subdir=` echo $cur_dir | cut -b $len-2000 `
#echo "subdir is : " $subdir
tmpaa=`dirname "$onearg" `
if [ "$tmpaa" = "." ]; then
 fname="$onearg"
 if [ "$subdir" = "" ]; then
  subdir=$tmpaa
 fi
else
 fname=`basename "$onearg" `
 if [ "$subdir" = "" ]; then
  subdir=$tmpaa
 else
  subdir="$subdir/$tmpaa"
 fi
fi
#echo "subdir is : " $subdir
#echo "fname is : " $fname

# Для всех команд требуется каталог CVS в Вашем локальном каталоге...
if [ ! -d  "$homedir/$subdir/CVS" ]; then
 tmpaa=` (cd "$CVSROOT/$subdir"; find * -prune -type f -print | head -1 ) `
 tmpbb=`basename $tmpaa | cut -d',' -f1 `
 if [ "$tmpaa" = "" -o ! -f "$CVSROOT/$subdir/$tmpbb,v" ]; then
  print "\nКаталог $homedir/$subdir/CVS не существует"
  print "Вы должны выполнить sget в каталоге `basename $subdir`. Наберите"
  print "       cd $homedir/`dirname $subdir` "
  print "       sget `basename $subdir` "
  exit
 else
  # Теперь попытка создать CVS в локальном каталоге с помощью sget
  (
   cd "$homedir"
   if [ "$subdir" = "." ]; then  # не использовать точку -- это смешает CVS
    cvs -r checkout -A $tmpbb
   else
    cvs -r checkout -A "$subdir/$tmpbb"
   fi
  )
 fi
fi

# Действовать внутри дочерней оболочки...
(
 cd $homedir

 # Проверка существования файла...
 if [ ! -f "$subdir/$fname" ]; then
  # Попытка получения файла из CVS
  sget "$subdir/$fname"
  if [ ! -f "$subdir/$fname" ]; then
   print "\nОшибка: $subdir/$fname НЕ существует в CVS-репозитории."
   print "\nЗавершение $cmdname ......"
   exit
  fi
 fi

 bkextn=cvs_sdelete_safety_backup
 \mv -f "$subdir/$fname" "$subdir/$fname.$bkextn" 

 cvs remove "$subdir/$fname"

 print "\nКоманда sdelete удаляет файлы из CVS-репозитория и "
 print "складирует их "на чердаке" CVS (каталог Attic). Если этот "
 print "файл понадобится Вам, свяжитесь с Вашим администратором CVS"
 print " "

 print "\n$cmdname успешно завершен."
 print "Чтобы подтвердить сделанные изменения выполните scommit"
 print "для $homedir/$subdir/$fname"
 \mv -f "$subdir/$fname.$bkextn" "$subdir/$fname"
)


sfreeze

Замечание: оболочка Korn /bin/ksh устанавливается инсталляцией pdksh*.rpm с компакт-диска дистрибутива Linux

Сохраните этот файл как текст и выполните для него "chmod a+rx".

#!/bin/ksh

# CVS-программа sfreeze
# Программа для замораживания и вырезания редакции дерева исходного 
# кода из CVS

cmdname=`basename $0`

Usage()
{
 clear
 print "\nВызов: $cmdname символический_тэг <имя каталога> "

 print "\nНапример: "
 print "   cd \$HOME"
 print "   $cmdname  REVISION_1   myprojectsource_directory"
 print "Для просмотра списка редакций:"
 print "slog <файл> посмотрите символическое имя и выполните"
 print "cvs history -T"

 print "\nЧтобы создать ветку от основного ствола, используйте"
 print "опции -b и -r, что принимает тэг как тэг ветки. Это полезно"
 print "для создания \"заплатки\" к предыдущей редакции программного"
 print "обеспечения"
 print "Например: "
 print "   cd \$HOME"
 print "   cvs rtag -b -r REVISION_1   REVISION_1_1   myprojectsource_directory"
 print " "

#   print "\nИнформация о тэге расположена в \$CVSROOT/CVSROOT/taginfo,v"
#   print "Вы можете просмотреть этот файл так: cd $HOME; sget CVSROOT"
 exit
}

# Каманда getopt не будет поддерживаться в следующей версии.
# Вместо нее используем getopts.
#while getopts r: ii
#do
# case $ii in
#  r) FLAG1=$ii; OARG1="$OPTARG";;
#  ?) Usage; exit 2;;
# esac
#done
#shift ` expr $OPTIND - 1 `

#echo FLAG1 = $FLAG1 , OARG1 = $OARG1

if [ $# -lt 2 ]; then
 Usage
fi

if [ ! -d $2 ]; then
 print "\nОшибка: второй аргумент $2 не каталог!"
 print "       Завершение $cmdname...."
 print " "
 exit
fi

homedir=` echo $HOME | cut -f1 -d' '  `
if [ "$homedir" = "" ]; then
        print "\nОшибка: \$HOME не установлен!!\n"
 exit
fi

cur_dir=`pwd`
len=${#homedir}
len=$(($len + 2))
subdir=` echo $cur_dir | cut -b $len-2000 `
#echo "subdir is : " $subdir

# Для всех команд требуется каталог CVS в Вашем локальном каталоге...
if [ ! -d  "$homedir/$subdir/CVS" ]; then
 tmpaa=` (cd "$CVSROOT/$subdir"; find * -prune -type f -print | head -1 ) `
 tmpbb=`basename $tmpaa | cut -d',' -f1 `
 if [ "$tmpaa" = "" -o ! -f "$CVSROOT/$subdir/$tmpbb,v" ]; then
  print "\nКаталог $homedir/$subdir/CVS не существует"
  print "Вы должны выполнить sget в каталоге `basename $subdir`. Наберите"
  print "       cd $homedir/`dirname $subdir` "
  print "       sget `basename $subdir` "
  exit
 else
  # Теперь попытка создать CVS в локальном каталоге с помощью sget
  (
   cd "$homedir"
   if [ "$subdir" = "." ]; then  # не использовать точку -- это смешает CVS
    cvs -r checkout -A $tmpbb
   else
    cvs -r checkout -A "$subdir/$tmpbb"
   fi
  )
 fi
fi

if [ "$cur_dir" != "$homedir" ]; then
 print "\nВы находитесь не в каталоге $homedir!!"
 print "Команду sfreeze необходимо выполнять из"
 print "домашнего каталога $homedir"
 exit
fi

# cvs rtag symbolic_tag <directory name>
cvs rtag $1 $2

print "\n$cmdname удачно завершен."

[Источник: LinuxDoc.ru]

[ опубликовано 10/06/2003 ]

Alavoor Vasudevan (alavoor@yahoo.com). Перевод Султанбек Тезадов (st99@mail.ru) - CVS-RCS- HOW-TO документ для Linux (система контроля исходного кода)   Версия для печати