Управление версиями


Вообще говоря, управление версиями (revision control) — это процесс отслеживания изменений. В мире UNIX под этим понимаются изменения в исходном коде и в файлах конфигурации. Управление версиями позволяет разработчику видеть, как некий фрагмент кода выглядел в определенный момент. Администратор может представить, как была сконфигурирована система до возникновения неполадок. Управление версиями может быть полезно даже скромному писателю — он может увидеть, как менялась рукопись с течением времени. Если не применять этот механизм, работа будет труднее, чем ей положено быть.

Несмотря на то, что существует много систем управления версиями, от системы управления исходным кодом SCCS (Source Code Control System) в UNIX до Visual SourceSafe компании Microsoft, здесь будет рассмотрена система управления версиями RCS (Revision Control System), входящая почти во все системы UNIX. После изучения RCS работать с большинством других систем управления версиями будет просто.

При управлении версиями, по существу, сохраняется информация обо всех изменениях, сделанных в файле, а также описание причин, вызвавших эти изменения. Во-первых, файл помечается как захваченный (checked out). Это знак системе, что файл будет изменяться. Далее файл можно отредактировать, затем записать изменения в системе, а затем файл можно передать (check in) другим пользователям для последующего редактирования. Для поддержки этих действий RCS применяет три команды: ci(1) (check in, регистрация), со(1) (check out, захват) и rcs(1).

Передовые методы управления версиями

В моей многолетней практике системного администратора я встречал множество методов управления версиями. Пожалуй, самый распространенный способ состоит в сохранении копий всех файлов с датой сохранения в виде расширения (например, rc.conf. 20060510). Однако такую методику никак нельзя назвать хорошей, более того — это плохая практика. Нет никакой гарантии, что при таком подходе будут сохраняться все изменения и отсутствует система слежения, с помощью которой можно было бы оставить комментарий, описывающий причины, вызвавшие эти изменения. Как сказал один мой товарищ: «RCS — это как горькое лекарство, которое необходимо пить, иначе вы не пойдете на поправку». Чтобы овладеть навыками работы с RCS, необходимо принуждать себя пользоваться ею, и через несколько месяцев вы будете удивляться — как вы вообще без нее обходились.

Управление версиями напоминает библиотеку — нет, не электронную библиотеку, а обычную, старую добрую библиотеку с книгами, отпечатанными на бумаге. Чтобы задействовать систему управления версиями, прежде всего надо указать системе RCS на необходимость отслеживания файла — поместить его в библиотеку. Чтобы приступить к работе с этим файлом, его необходимо получить, как книгу в библиотеке. Если файл выдан, то никто иной не может его сохранять или редактировать, хотя любой законный пользователь в то же время может просматривать, копировать, компилировать этот файл — обращаться к нему. После завершения работы с файлом он сдается обратно (check in) и становится доступен для редактирования другими пользователями. Такой порядок действий составляет основу любой системы управления версиями, а про файлы, находящиеся под контролем системы управлениями версиями, говорят, что они находятся в RCS.

В RCS каждый файл имеет номер версии. Всякий раз, когда отредактированный файл возвращается в систему, RCS сравнивает возвращаемый файл с выданным. При наличии хоть каких-то изменений эти изменения сохраняются, а номер версии увеличивается на единицу, вместе с датой и причиной изменений. Номер версии можно применять для идентификации отдельных версий файла.

Инициализация управления версиями

Процесс управления версиями начинается с регистрации файла с помощью ci(1), что напоминает сдачу книги в библиотеку. Например, хороший кандидат для защиты с помощью RCS — файл /etc/rc.conf. Для начала надо ввести ci filename, как показано в следующем листинге:

# ci rc.conf

При первой регистрации файла с помощью ci эта команда создает или редактирует файл управления версиями. Этот файл получает то же имя, что и оригинальный файл, но с расширением ,v. В данном примере файл rc.conf превращается в rc.conf,v (1). Далее система запрашивает описание файла, и его надо ввести, чтобы позднее каждый пользователь RCS мог понять, что это за файл. Это описание не так уж важно для стандартных системных файлов, таких как rc.conf, — для него вполне достаточно краткого описания system configuration file, как задано в этом примере (2). Более подробное описание будет очень полезно для исходного кода или файлов конфигурации самостоятельно разработанных или сложных программ. После того как описание набрано, для завершения работы ci следует ввести точку на отдельной строке (3). После этого будет выведен номер версии файла (4), который в первый раз всегда равен 1.1.

Если сразу после регистрации файла запустить ls, то можно увидеть, что файл как будто исчез. Вместо этого появится файл с тем же именем, но с замыкающими символами ,v. Это файл RCS, в котором хранятся сам файл и его изменения. Если в RCS хранится много файлов, то файлы с расширением ,v могут вносить некоторый хаос. Чтобы этого не происходило, достаточно создать каталог с именем RCS (все символы заглавные), и тогда программа ci будет сохранять файлы ,v в этот каталог, не засоряя рабочий каталог.

Для некоторых файлов не важно, что они «исчезают» при передаче, но файлы с настройками или веб-страницами не могут просто исчезнуть. Чтобы решить эту проблему, при регистрации файла нужно оставить его копию в рабочем каталоге. Для этого надо запустить ci -u. Если файл исчез, а его копию необходимо поместить в рабочий каталог без редактирования файла, надо выполнить команду co(1).

# co rc.conf

Так как компьютер не в состоянии выполнить корректную загрузку без файла rc.conf, очень важно обеспечить доступность этого файла. Система RCS извлекла файл rc.conf из rc.conf,v (1), и теперь версия 1.1 (2) этого файла доступна для использования. Если внимательнее приглядеться к этим файлам, можно увидеть нечто удивительное.

# ls -l rc.conf*

Владелец этого файла — пользователь root, однако права доступа — «только для чтения» (-r--r--r--). Даже при том, что я знаю пароль пользователя root, я не имею права редактировать свои файлы! Дело в том, что файл не был захвачен мной. Файл был зарегистрирован и передан библиотекарю Revision Control System. Я могу просматривать этот файл, но для его редактирования нужно попросить разрешения у системы RCS.

Предупреждение для тех, кто использует редактор vi(1)

Предупреждение для пользователей vi: если вы или ваша группа владеете файлом, команда w! вызовет изменение прав доступа и позволит вам осуществлять запись в файл даже без его регистрации. Все будет выглядеть замечательно, однако следующий пользователь, который зарегистрирует файл, перезапишет ваши изменения! Будьте осторожны с этой командой; если vi говорит, что у вас нет прав на сохранение файла, это весомое предупреждение, к которому лучше прислушаться. Вы можете проигнорировать это предупреждение на свой страх и риск.

Редактирование файлов, находящихся в RCS

Чтобы отредактировать файл, его сначала необходимо получить и заблокировать для единоличного использования. Это не позволит редактировать файл другим пользователям, пока тот, кто заблокировал файл, не сделает необходимые изменения. Чтобы получить и заблокировать файл, следует использовать команду co -l:

# co -l rc.conf

Операция получения файла выглядит почти так же, как и раньше, но обратите внимание на слово locked (1). Этот файл захвачен и заблокирован. Только пользователь, выполнивший блокировку, может сохранять этот файл, пока он не будет разблокирован. Запустив после этой операции ls -l еще раз, можно увидеть, что права доступа к файлу снова разрешают чтение и запись, а значит, этот файл можно сохранять (права доступа рассматриваются в главе 7). Любой, кто попытается захватить этот файл, получит предупреждение о том, что файл используется, при этом будет указано имя того, кто этот файл заблокировал.

Повторная регистрация

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

# ci -u rc.conf

При передаче файла в систему RCS команда ci присвоит ему новый номер версии (1) и запросит сообщение, которое будет записано в протоколе (2). Здесь надо ввести краткое описание внесенных изменений. В многопользовательской системе, возможно, понадобится описать причины, по которым были сделаны изменения. Если у вас работает система регистрации сообщений об ошибках, будет нелишним перечислить в описании номера сообщений, благодаря этому пользователи смогут получать полную историю изменений, сославшись на номер сообщения. Как и при первой регистрации, текст описания следует завершить символом точки на отдельной строке (3).

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

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

Просмотр протоколов RCS

Самый простой способ просмотреть историю изменений файла — это просмотреть протокол RCS с помощью команды rlog(1). Эта команда отобразит все сообщения, которые были введены для указанного файла. В приведенном ниже примере выполняется извлечение сообщений из протокола RCS для файла rc.conf, расположенного на другой машине:

# rlog rc.conf

Здесь представлена вся полезная информация. Здесь видно, что файл RCS находится в каталоге с именем RCS (1) и что файл имеет номер версии 1.3 (2). Описание файла, которое было введено при первой регистрации, расположено первым (3).

Затем следуют отдельные записи для каждой версии. Версия 1.3 (4) была зарегистрирована 17 февраля 2006 года (5) в 22:23. Файл был зарегистрирован пользователем mwlucas (6) — очевидно, я допоздна задержался на работе. Изменения были не очень большими — в файл были добавлены две новые строки и две строки были удалены (7). Наконец, протокольное сообщение говорит о том, что были переименованы два интерфейса (8). Я совершенно не помню, чтобы делал это, впрочем, это и неудивительно, раз я работал так поздно!

Самое интересное, что отсутствует описание для версии 1.2. Очевидно, в этот день я был небрежен. Интересно, что я изменил?

Просмотр истории версий файла

Увидеть отличия между двумя версиями файла позволяет команда rcsdiff(1). Эта программа принимает три аргумента: два номера версий и имя файла, как показано ниже. Я рекомендую добавлять ключ -u, чтобы различия выводились в более удобочитаемом виде.

# rcsdiff -u -rolderversionnumber -rnewerversionnumber filename

Например, запустив команду rcsdiff -u -r1.1 -r1.2 rс.conf, я мог бы увидеть примерно следующее:

Команда rcsdiff просто извлекает две версии указанного файла и затем передает их утилите diff(1) (1). Команда rcsdiff распознает большую часть ключей утилиты diff(1), поэтому, если вы знакомы с diff, то с помощью этих ключей вы можете настраивать вывод результатов под себя. Строки, начинающиеся с символа «плюс» (+) (2), были добавлены в файл, а строки, начинающиеся с символа «минус» (-) (3), были удалены. В данном случае было добавлено несколько пустых строк, удалена переменная syslog_flags (тем самым был выполнен возврат к поведению по умолчанию, которое описано в файле /etc/defaults/rc.conf) и добавлен запуск демона snmpd (4). Теперь все понятно. Жаль, что я не оставил описание для себя самого, чтобы потом не приходилось копаться в отличиях версий, но хотя бы я знаю, что было сделано. Наличие такой возможности очень удобно, особенно на рабочих системах, и особенно на тех, которые администрируются несколькими администраторами.

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

Комментарии запрещены.