3. Работа с CVS

Подразумевается, что вы уже имеете опыт базовой работы с CVS.

Администраторы Главного CVS Репозитория являются ''владельцами'' репозитория CVS и ответственны за все прямые его изменения (в целях чистки или исправления каких-либо вопиющих ошибок коммиттеров при работе с CVS). Если в результате ваших действий с частью репозитория произошел несчастный случай, например, после неверной операции cvs import или cvs tag, пошлите письмо соответствующей подгруппе Администраторы Главного CVS Репозитория (см. следующую таблицу) и сообщите о проблеме. В наиболее серьезных случаях, касающихся не только какой-либо части репозитория, а дерева CVS в целом, вы можете написать Администраторы Главного CVS Репозитория . Пожалуйста, не надо писать группе Администраторы Главного CVS Репозитория по поводу репозиторного копирования и прочих вопросов, которые может решить соответствующая подгруппа.

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

Замечание: Адреса, на которые следует посылать запросы, зависят от области репозитория, которую требуется поправить:

  • ncvs@ - репозиторий /home/ncvs, основные исходные тексты

  • pcvs@ - репозиторий /home/pcvs, порты

  • dcvs@ - репозиторий /home/dcvs, документация

  • projcvs@ - репозиторий /home/projcvs, прочие проекты

Дерево CVS в настоящее время разделено на четыре независимых репозитория: doc, ports, projects и src. Для удобства работы пользователей при распространении через CVSup различные деревья комбинируются в одно, с одним служебным каталогом CVSROOT.

Замечание: Обратите внимание, что модуль www, содержащий исходные тексты веб-сайта FreeBSD, расположен в репозитории doc.

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

Таблица 1. Репозитории CVS FreeBSD, хосты и каталоги

Репозиторий Хост Каталог
doc dcvs.FreeBSD.org /home/dcvs
ports pcvs.FreeBSD.org /home/pcvs
projects projcvs.FreeBSD.org /home/projcvs
src ncvs.FreeBSD.org /home/ncvs

Операции с CVS производятся удаленно, путем установки переменной окружения CVSROOT (она должна указывать на соответствующий хост и каталог верхнего уровня, например ncvs.FreeBSD.org:/home/ncvs) и последующего выполнения команд выгрузки и коммита. Многие коммиттеры определяют команды-синонимы, разворачивающиеся в запуск cvs с правильными параметрами. В частности, пользователи оболочки tcsh(1) могут добавить следующие строки в свой скрипт начальной загрузки .cshrc:

alias dcvs cvs -d user@dcvs.FreeBSD.org:/home/dcvs
alias pcvs cvs -d user@pcvs.FreeBSD.org:/home/pcvs
alias projcvs cvs -d user@projcvs.FreeBSD.org:/home/projcvs
alias scvs cvs -d user@ncvs.FreeBSD.org:/home/ncvs

Теперь все операции с CVS могут выполняться на локальной машине, а для внесения изменений в официальное дерево CVS следует использовать команду Xcvs commit. Если вам нужно добавить в проект что-либо совершенно новое (например, исходные тексты сторонних разработчиков), нужно использовать команду cvs import; обратитесь к странице справочника по cvs(1) за подробностями.

Замечание: Пожалуйста, не используйте команды cvs checkout или cvs update для синхронизации ваших исходных текстов. Протокол CVS не оптимизирован для удаленной работы и требует значительных накладных расходов со стороны сервера. Пожалуйста, используйте метод синхронизации посредством cvsup, а основной хост используйте только для собственно коммитов. Наша распределенная сеть серверов cvsup достаточно развита. При необходимости синхронизации с самыми свежими изменениями вы можете пользоваться машиной cvsup-master, которая обладает достаточными ресурсами для удаленной работы с CVS; за нее отвечает Jun Kuriyama .

Если вам нужно использовать команды CVS add и delete, так чтобы в реальности переместить часть исходных текстов подобно действию команды mv(1), нужно запросить операцию ''репозиторного копирования'' (repository copy). При этом кто-либо из CVS-мастеров скопирует необходимые файлы внутри репозитория на нужное место и даст вам знать об этом. Репозиторное копирование производится для сохранения истории (журналов изменения). Возможность отследить историю изменений очень ценна для всего проекта FreeBSD.

Документация по CVS, учебные материалы и FAQ можно найти по адресу: http://www.cvshome.org/docs/. Очень полезна также книга Карла Фогеля (Karl Fogel) Open Source Development with CVS. Некоторая полезная информация о CVS на русском языке может быть найдена здесь.

Dag-Erling C. Smørgrav написал такой ''мини-пример'' работы с CVS:

  1. Извлечение нужного модуля из репозитория: команда co или checkout.

    % cvs checkout shazam
    

    Эта команда извлечет копию модуля shazam. Если модуль с таким именем не существует (не описан в файле modules), будет произведена попытка извлечь директорию верхнего уровня shazam.

    Таблица 2. Полезные опции команды cvs checkout

    -P Не создавать (точнее, удалить после завершения выполнения) пустые каталоги
    -l Извлекать один уровень каталогов (без подкаталогов)
    -rrev Извлечь ревизию, ветвь или тег rev для указанного модуля
    -Ddate Извлечь состояние модуля в репозитории на момент date

    Примеры в применении к FreeBSD:

    • Извлечь модуль miscfs, расположенный в каталоге репозитория src/sys/miscfs:

      % cvs co miscfs
      

      После выполнения вы получите каталог miscfs, содержащий подкаталоги CVS, deadfs, devfs и т.д. Один из них (linprocfs) будет пустым.

    • Извлечь те же файлы, но с полным путем:

      % cvs co src/sys/miscfs
      

      Теперь у вас есть каталог src, содержащий подкаталоги CVS и sys. Каталог src/sys содержит подкаталоги CVS и miscfs и т.д.

    • Извлечь те же файлы, удалив при этом пустые подкаталоги:

      % cvs co -P miscfs
      

      Вы получите каталог miscfs с подкаталогами CVS, deadfs, devfs... однако без подкаталога linprocfs, поскольку он не содержит файлов.

    • Извлечь каталог miscfs без подкаталогов:

      % cvs co -l miscfs
      

      Теперь в каталоге miscfs будет только один подкаталог CVS.

    • Извлечь модуль miscfs из ветви 6.X:

      % cvs co -rRELENG_6 miscfs
      

      Теперь вы можете изменить исходные тексты и произвести коммит в эту ветвь.

    • Извлечь модуль miscfs по состоянию на момент выхода 6.0-RELEASE:

      % cvs co -rRELENG_6_0_0_RELEASE miscfs
      

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

    • Извлечь модуль miscfs по состоянию на 15 января 2000 г:

      % cvs co -D'01/15/2000' miscfs
      

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

    • Извлечь модуль miscfs, каким он был неделю назад:

      % cvs co -D'last week' miscfs
      

      И вновь, изменения не могут быть записаны.

    Обратите внимание, что мета-данные хранятся в подкаталогах CVS.

    Аргументы опций -D and -r сохраняются (являются ''клейкими'', sticky), например, при последующем использовании команды cvs update.

  2. Проверка состояния извлеченных файлов: команда status.

    % cvs status shazam
    

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

    Up-to-date Файл соответствует репозиторию и не модифицировался
    Needs Patch Файл не изменялся, но репозиторий содержит обновленную версию
    Locally Modified Файл соответствует репозиторию, но был изменен локально
    Needs Merge Файл изменен локально; вместе с тем, файл изменен и в репозитории
    File had conflicts on merge После последнего обновления возникли конфликты, и они все еще не устранены

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

  3. Обновление извлеченного модуля: команда update.

    % cvs update shazam
    

    Эта команда обновит состояние файла shazam или файлов в каталоге shazam до наиболее свежих версий выбранной вами при извлечении ветви. Если выбирался ''момент времени'', не произойдет ничего, если только за истекшее время в репозитории не был перемещен тег или не произошло чего-нибудь еще непредвиденного.

    Полезные опции в дополнение к уже описанным для команды checkout:

    -d Извлечь вновь появившиеся или пропущенные ранее подкаталоги
    -A Обновиться до текущего состояния головной ветви
    -jrev магическая опция (см. ниже)

    Если вы извлекали модуль с опциями -r или -D, выполнение команды cvs update с другими параметрами -r или -D или с опцией -A приведет к выбору новой ветви, ревизии или даты. Использование опции -A удаляет использованные ранее клейкие свойства; опции -r и -D, наоборот, фиксируют их.

    Теоретически использование HEAD в качестве аргумента опции -r должно дать тот же результат, что и указание опции -A, однако это верно лишь в теории.

    Опция -d полезна, если:

    • после извлечения вами модуля кем-либо еще в него были добавлены дополнительные каталоги;

    • вы извлекали верхний уровень модуля при помощи опции -l, а в дальнейшем решили извлечь и подкаталоги;

    • вы удалили какие-либо подкаталоги и теперь хотите вновь извлечь их.

    Обращайте внимание на вывод команды cvs update. Действие, произведенное с файлом, обозначается буквой перед его именем:

    U Файл был успешно обновлен.
    P Файл был успешно обновлен (произведен успешный патч из удаленного репозитория).
    M Файл был изменен, и при этом обновлен успешно.
    C Файл был изменен, и при объединении изменений возникли конфликты.

    Объединение (merging) производится, если вы выгрузили рабочую копию какого-то модуля, изменили его, затем кто-либо еще произвел коммит собственных изменений, и, наконец, вы выполняете команду cvs update. CVS знает, что производились локальные изменения, и пытается объединить ваши изменения с теми, что произошли в репозитории (от состоянии версии, которую вы выгружали, до версии, до которой вы пытаетесь обновиться). Если изменения происходили с различными частями файла, объединение почти всегда произойдет успешно (хотя результат при этом может не быть синтаксически или семантически корректным).

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

    Если в результате вы видите букву C, ваши изменения конфликтуют с изменениями, внесенными в репозиторий (изменения были в одних и тех же или рядом расположенных строках, либо вы изменили файл настолько, что при сравнении cvs не смогла удержать контекст и приложить изменения из репозитория). Вам необходимо устранить конфликты, вручную редактируя файл. Конфликтующие фрагменты помечаются строками из знаков <, = и >. В начале каждого из конфликтов присутствует строка из семи знаков < и имени файла, затем идет фрагмент, содержащий внесенные вами изменения, разделитель из семи знаков =, соответствующий фрагмент из версии файла, содержащейся в репозитории, и, наконец, строка из семи знаков > совместно с номером версии, до которой вы обновляли файл.

    Опция -j содержит некоторое количество черной магии. При ее наличии локальный файл обновляется до указанной версии так же, как и при использовании опции -r, но отслеживаемые номер версии или ветвь не изменяются. Эта опция умеет смысл лишь при парном использовании: при этом делается попытка применить изменения между двумя указанными версиями к локальной копии файла.

    К примеру, вы внесли изменения и произвели коммит в файл shazam/shazam.c в FreeBSD-CURRENT, а позднее хотите перенести обновления в FreeBSD-STABLE (Merge-From-Current, MFC). Версия, которая требует переноса — 1.15:

    • Извлеките текущую версию модуля shazam для ветви FreeBSD-STABLE:

      % cvs co -rRELENG_6 shazam
      
    • Приложите изменения между версиями 1.14 и 1.15:

      % cvs update -j1.14 -j1.15 shazam/shazam.c
      

    Почти наверняка вы получите конфликт в строках, содержащих идентификатор файла ($Id: article.xml,v 1.19 2007-05-09 06:08:50 bvs Exp $ или, в случае FreeBSD, $FreeBSD$). Вам потребуется отредактировать файл для устранения конфликта (в данном случае достаточно убрать строки-разделители и вторую строку $Id: article.xml,v 1.19 2007-05-09 06:08:50 bvs Exp $, оставив лишь строку с $Id: article.xml,v 1.19 2007-05-09 06:08:50 bvs Exp $ для FreeBSD-STABLE).

  4. Просмотр изменение между локальной версией и версией из репозитория: команда diff.

    % cvs diff shazam
    

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

    Таблица 3. Полезные опции команды cvs diff

    -u Использовать унифицированный (unified) формат.
    -c Использовать контекстный (context) формат.
    -N Показывать отсутствующие или созданные файлы.

    Всегда имеет смысл пользоваться опцией -u, поскольку унифицированный формат гораздо удобнее и лучше читаем, чем почти все другие (в некоторых случаях контекстный формат, генерируемый опцией -c может быть несколько лучше, но он гораздо более громоздок). Унифицированный формат различий состоит из серии фрагментов, каждый из которых начинается со строки, состоящей из двух символов @ и номеров строк, описывающих положение изменившегося участка. Затем следует группа строк: те, что начинаются с пробела, описывают контекст, начинающиеся с символа - определяют удаленные строки, наконец, начинающиеся с символа + — добавленные.

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

  5. Просмотр журнала изменений: команда log.

    % cvs log shazam
    

    Если shazam является обычным файлом, эта команда выдаст на экран заголовок с информацией о файле, в частности, его местоположении в репозитории, какая версия соответствует текущему состоянию (HEAD), в каких ветвях разработки файл присутствует, а также перечислит теги, которыми он помечен. Затем, для каждой версии файла выводится соответствующее ей журнальное сообщение, включающее дату, время и автора коммита, количество добавленных и удаленных строк и собственно журнального сообщения, написанного коммиттером.

    Если shazam является каталогом, вышеописанная процедура выполняется для каждого файла в каталоге. Если при этом команде log не был указан флаг -l, процедура рекурсивно повторяется для всех подкаталогов.

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

    % cvs log -r1.2 shazam
    

    Эта команда покажет журнальное сообщение для версии 1.2 файла shazam (или для версий 1.2 каждого из файлов в каталоге shazam).

  6. Кто что делал: команда annotate. Эта команда показывает перед каждой строкой указанного файла (файлов) имя пользователя, вносившего последние изменения в эту строку.

    % cvs annotate shazam
    
  7. Добавление новых файлов: команда add.

    Создайте файл, выполните для него команду cvs add, затем произведите запись в репозиторий (коммит): cvs commit.

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

  8. Удаление устаревших файлов: команда remove.

    Удалите файл, затем выполните команду cvs rm с его именем в качестве параметра, наконец, выполните для него cvs commit.

  9. Внесение изменений в репозиторий: команда commit или checkin.

    Таблица 4. Useful cvs commit options

    -f Форсировать внесение изменений для не модифицированного файла.
    -mmsg Указать сообщение для журнала в командной строке (не запускать текстовый редактор).

    Опцию -f следует использовать, если вы поняли, что забыли указать какую-либо важную информацию в журнале изменений.

    Хорошие журнальные сообщения очень важны. Они дают возможность другим узнать, зачем вы производили изменения, причем не только в момент их произведения, но и месяцы или годы спустя, когда кто-либо заинтересуется, почему выглядящий нелогично или неэффективно фрагмент кода попал в каши исходные тексты. Кроме того, это очень помогает в оценке того, нужно ли переносить соответствующий код в FreeBSD-STABLE (MFC).

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

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

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

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

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

    Перед коммитом, обязательно:

    • проверьте, что вы будете выполнять коммит в правильную ветвь, посредством команды cvs status.

    • проверьте ваши изменения при помощи команды cvs diff

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

Еще несколько полезных советов:

  1. Часто используемые опции можно занести в файл ~/.cvsrc, например:

    cvs -z3
    diff -Nu
    update -Pd
    checkout -P
    

    Для данного случая:

    • всегда использовать компрессию уровня 3 для связи с удаленным сервером CVS. В случае медленного соединения это избавит вас от лишней головной боли.

    • всегда использовать опции -N (показывать добавленные или удаленные файлы) и -u (унифицированный формат) для diff(1).

    • всегда использовать опции -P (удалять пустые каталоги) и -d (добавлять новые каталоги) при обновлении.

    • всегда использовать опцию -P (удалять пустые каталоги) при извлечении файлов и модулей.

  2. Пользуйтесь скриптом Эйвинда Эклунда (Eivind Eklund) cdiff для просмотра изменению унифицированного формата. Он является оберткой для less(1), добавляющей цветовые коды ANSI для выделения заголовком, добавленных и удаленных строк; прочие строки не модифицируются. Помимо этого, скрипт корректно разворачивает табуляции (которые часто выглядят неправильно в изменениях из-за дополнительного символа в начале строки).

    textproc/cdiff

    Просто используйте его вместо more(1) или less(1):

    % cvs diff -Nu shazam | cdiff
    

    Помимо этого, некоторые текстовые редакторы, такие как vim(1) (editors/vim) поддерживают цветовую синтаксическую разметку многих типов файлов, в том числе файлов изменений и журналов CVS/RCS.

    % echo "syn on" >> ~/.vimrc 
    % cvs diff -Nu shazam | vim -
    % cvs log shazam | vim -
    
  3. CVS — старая, загадочная и порой слабо предсказуемая в своем поведении программа. Ни один человек не способен удержать в голове все тонкости ее работы, так что не бойтесь спрашивать совета у Искусственного Интеллекта (а именно Администраторы Главного CVS Репозитория ).

  4. Не оставляйте компьютер в процессе работы команды cvs commit (в редакторе при написании журнального сообщения) слишком надолго (более чем на 2–3 минуты). Эта команда блокирует каталог репозитория, в котором она запущена, и не позволяет другим разработчикам изменять его содержимое. Если вам нужно написать длинное журнальное сообщение, подготовьте его заранее и вставьте в редакторе во время выполнения команды cvs commit, либо запишите его в файл и используйте опцию CVS -F:

    % vi logmsg
    % cvs ci -F logmsg shazam
    

    Это самый быстрый способ передать журнальное сообщение CVS; однако, вы должны быть внимательны при редактировании файла logmsg, поскольку при выполнении коммита у вас не будет шансов его поправить.

  5. Вы можете существенно ускорить скорость работы CVS с центральным репозиторием, используя постоянное соединение с репозиторием. Для этого добавьте в файл ~/.ssh/config строки

    Host ncvs.FreeBSD.org
          ControlPath /home/user/.ssh/cvs.cpath
    Host dcvs.FreeBSD.org
          ControlPath /home/user/.ssh/cvs.cpath
    Host projcvs.FreeBSD.org
          ControlPath /home/user/.ssh/cvs.cpath
    Host pcvs.FreeBSD.org
          ControlPath /home/user/.ssh/cvs.cpath
    

    Затем откройте постоянное соединение с машиной repoman:

    % ssh -fNM ncvs.FreeBSD.org
    

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

Этот, и другие документы, могут быть скачаны с ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

По вопросам, связанным с FreeBSD, прочитайте документацию прежде чем писать в <questions@FreeBSD.org>.
По вопросам, связанным с этой документацией, пишите <doc@FreeBSD.org>.
По вопросам, связанным с русским переводом документации, пишите в рассылку <frdp@FreeBSD.org.ua>.
Информация по подписке на эту рассылку находится на сайте проекта перевода.