Когда над программным проектом работает более одного человека,
ситуация резко усложняется. Зачастую два разработчика одновременно пытаются
редактировать один и тот же файл. Одно из решений, известное как
блокировка файлов или блокированное извлечение, -- в
каждый момент времени позволять редактировать файл только одному
человеку. Это -- единственное решение при использовании
некоторых систем контроля версий, включая RCS и SCCS.
В настоящее время обычным способом совершить блокированное
извлечение рабочей копии с помощью CVS -- использовать
команду cvs admin -l
(see section Ключи команды admin). Эта возможность
не столь красиво интегрирована в CVS, как функции слежения,
описанные ниже, но кажется, что всех, кому требуется блокированное
извлечение, эта команда устраивает.
Во избежание одновременного редактирования файла двумя разработчиками можно также использовать возможность слежения, описанную ниже, вместе с соответствующими административными процедурами (не контролируемыми с помощью программы).
Модель, используемая в CVS по умолчанию, называется неблокированные извлечения. В этой модели разработчики редактируют свои собственные рабочие копии файла. Первый, зафиксировавший свои изменения, не может автоматически узнать, что второй также начал редактировать файл. Второй получит сообщения об ошибке, когда попытается зафиксировать файл. Он должен использовать соответствующие команды CVS, чтобы его рабочая копия соответствовала свежайшей ревизии, находящейся в репозитории. Весь этот процесс проходит почти автоматически.
CVS также поддерживает механизмы различных способов коммуникации, никак не настаивая на выполнении каких-либо правил, в отличие от блокированных извлечений.
Оставшаяся часть главы описывает, как работают все эти различные модели, а также некоторые вопросы, связанные с выбором того или иного варианта.
Основываясь на операциях, которые производятся над извлеченным
файлом, а также на операциях, которые производятся над этим
файлом в репозитории, можно классифицировать несколько состояний
файла. Команда status
рапортует об этих состояниях. Они
таковы:
cvs add
, и еще не
зафиксировали изменения.
cvs remove
и еще не
зафиксировали изменения.
cvs update
, а не cvs checkout
, чтобы
получить свежайшую версию.
cvs update
обнаружила конфликт. Если вы еще не
исправили его, сделайте это, как описано в section Пример конфликта.
cvs add
.
Чтобы уточнить состояние файла, cvs status
также сообщает
о Working revision
, являющейся ревизией, на основе которой
создан файл в рабочем каталоге, и Repository revision
,
являющейся свежайшей ревизией в репозитории, находящейся на
используемой ветке.
Ключи команды status
перечислены в section Краткий справочник по командам CVS.
Информация о Sticky tag
и Sticky date
находится в
section Липкие метки. Информация о Sticky options
находится
в описании флага `-k' в section Ключи команды update.
Команды status
и update
можно рассматривать как
соответствующие друг другу. update
используется для
извлечения самых свежих файлов, а status
-- для
выяснения, что же произойдет, если выполнить update
(конечно, состояние репозитория может измениться до того, как вы
выполните update
). В действительность, если вы хотите
узнать состояние файлов в более краткой форме, выполните
$ cvs -n -q update
Ключ командной строки `-n' указывает не выполнять
обновление, а просто сообщить о состоянии файлов; `-q' не
печатает имена каждого каталога. Прочую информацию о команде
update
можно найти в section Краткий справочник по командам CVS.
Если вы хотите получить новую ревизию файла или объединить его с
другой ревизией, используйте команду update
. Если вы
имеете старую ревизию файла, то эта команда эквивалентна
checkout
: свежая ревизия извлекается из репозитория и
помещается в рабочий каталог.
Ваши изменения в файле не теряются, когда вы используете
update
. Если более свежей ревизии не существует,
выполнение update
ничего не сделает. Если вы
редактировали файл, а в репозитории появилась его более новая
ревизия, изменения будут объединены с вашей рабочей копией.
Например, представим себе, что вы извлекли ревизию 1.4 и начали
редактировать ее. В это время кто-то еще поместил в репозиторий
ревизию 1.5 и, вскорости, ревизию 1.6. Если теперь вы выполните
команду update
, CVS внедрит изменения между ревизиями
1.4 и 1.6 в ваш файл.
Если изменения между ревизиями 1.4 и 1.6 случились слишком близко
к вашим изменениям, происходит пересечение. В таких
случаях на экран выдается предупреждение, а в результирующем
файле оказываются обе версии пересекающихся строк, разделенные
специальными маркерами. See section Команда update: обновить рабочий каталог из репозитория, где полностью описана
команда update
.
Предположим, что ревизия 1.4 файла `driver.c' содержит такой код:
#include <stdio.h> void main() { parse(); if (nerr == 0) gencode(); else fprintf(stderr, "No code generated.\n"); exit(nerr == 0 ? 0 : 1); }
Ревизия 1.6 файла `driver.c' содержит такой код:
#include <stdio.h> int main(int argc, char **argv) { parse(); if (argc != 1) { fprintf(stderr, "tc: No args expected.\n"); exit(1); } if (nerr == 0) gencode(); else fprintf(stderr, "No code generated.\n"); exit(!!nerr); }
Ваша рабочая копия файла `driver.c', основанная на ревизии 1.4, перед выполнением `cvs update' содержит такой код:
#include <stdlib.h> #include <stdio.h> void main() { init_scanner(); parse(); if (nerr == 0) gencode(); else fprintf(stderr, "No code generated.\n"); exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE); }
Вы выполняете `cvs update':
$ cvs update driver.c RCS file: /usr/local/cvsroot/yoyodyne/tc/driver.c,v retrieving revision 1.4 retrieving revision 1.6 Merging differences between 1.4 and 1.6 into driver.c rcsmerge warning: overlaps during merge cvs update: conflicts found in driver.c C driver.c
CVS сообщает, что вы встретились с конфликтами. Ваш исходный рабочий файл сохранен в `.#driver.c.1.4'. Новая версия `driver.c' содержит такой код:
#include <stdlib.h> #include <stdio.h> int main(int argc, char **argv) { init_scanner(); parse(); if (argc != 1) { fprintf(stderr, "tc: No args expected.\n"); exit(1); } if (nerr == 0) gencode(); else fprintf(stderr, "No code generated.\n"); <<<<<<< driver.c exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE); ======= exit(!!nerr); >>>>>>> 1.6 }
Заметьте, что непересекающиеся модификации включены в вашу рабочую копию, а пересекающаяся секция четко обозначена строками `<<<<<<<', `=======' and `>>>>>>>'.
Разрешить конфликт можно, отредактировав файл, удалив маркеры и неверный вариант. Предположим, в результате у вас получился такой файл:
#include <stdlib.h> #include <stdio.h> int main(int argc, char **argv) { init_scanner(); parse(); if (argc != 1) { fprintf(stderr, "tc: No args expected.\n"); exit(1); } if (nerr == 0) gencode(); else fprintf(stderr, "No code generated.\n"); exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE); }
Теперь вы можете поместить этот файл в репозиторий в качестве ревизии 1.7.
$ cvs commit -m "Initialize scanner. Use symbolic exit values." driver.c Checking in driver.c; /usr/local/cvsroot/yoyodyne/tc/driver.c,v <-- driver.c new revision: 1.7; previous revision: 1.6 done
Чтобы защитить вас, CVS откажется фиксировать файл, если в нем произошел конфликт и вы с ним не справились. В настоящий момент для разрешения конфликта нужно изменить дату модификации файла. В предыдущих версиях CVS вам также требовалось убедиться, что файл не содержит маркеров конфликта. Так как ваш файл действительно может содержать маркеры конфликтов (символы `>>>>>>>>' в начале строки, не обозначающие конфликта), то в текущей версии CVS выдает предупреждение и фиксирует файл.
Если вы используете pcl-cvs
(оболочка к CVS для
Emacs) версии 1.04 или позже, вы можете использовать пакет
emerge, помогающий разрешать конфликты. Смотрите документацию по
pcl-cvs
.
Часто бывает полезно информировать своих коллег, когда вы фиксируете новую ревизию файла. Можно использовать ключ `-i' в файле `modules' или файле `loginfo' для автоматизации этого процесса. See section Файл `modules'. See section Файл loginfo. Можно использовать эти возможности CVS для того, чтобы указать CVS, например, отсылать почтовые сообщения всем разработчикам или помещать сообщение в локальную группу новостей.
Если несколько разработчиков попытаются одновременно выполнить CVS, один из них получит такое сообщение:
[11:43:23] waiting for bach's lock in /usr/local/cvsroot/foo
CVS попытается повторить операцию каждые 30 секунд, и либо успешно выполнит ее, либо опять напечатает сообщение, если опять нужно ждать. Если блокировка сохраняется слишком долго, найдите того, кто создал ее и спросите его, что за команду он выполняет. Если он не выполняет команд CVS, загляните в каталог репозитория, упомянутый в сообщении, и удалите файлы, чьи имена начинаются с `#cvs.rfl', `#cvs.wfl', или `#cvs.lock', принадлежащие указанному пользователю.
Заметьте, что эти блокировки предназначаются для защиты внутренних структур данных CVS и не имеют никакого отношения к слову блокировка в том смысле, который используется в RCS и означает блокированные извлечения (see section Несколько разработчиков).
Неограниченное количество пользователей может одновременно читать репозиторий; только когда кто-либо пишет туда, блокировки препятствуют прочим как читать, так и писать.
Можно было бы надеяться, что верно следующее утверждение:
Если кто-либо фиксирует несколько изменений одной командой
CVS, то команда update
, выполненная кем-то еще,
получит либо все изменения, либо ни одно из них.
К сожалению, при работе с CVS это утверждение неверно. Например, если имеются файлы
a/one.c a/two.c b/three.c b/four.c
и кто-то выполняет
cvs ci a/two.c b/three.c
а затем кто-то еще в то же самое время выполняет cvs
update
, то он может получить изменения для `b/three.c', и
не получить изменения в `a/two.c'.
Для большинства групп использования CVS в режиме по умолчанию совершенно достаточно. Пользователи иногда могут, попытавшись зафиксировать изменение, обнаружить, что мешает другое изменение, но они справятся с этим и все же зафиксируют свое изменение. В других группах предпочитают знать, кто какие файлы редактирует, так что если два человека захотят редактировать один и тот же файл, то они предпочтут договориться друг с другом, кто что будет делать, чтобы не получать проблем при каждом фиксировании. Возможности, описанные в этой главе, помогают такой координации, сохраняя возможность редактирования одного файла двум разработчикам одновременно.
Для получения максимального преимущества разработчики должны
использовать cvs edit
(а не chmod
), чтобы сделать
файлы доступными для чтения/записи, и cvs release
(а не
rm
) для удаления рабочего каталога, который более не
используется. CVS не может вынудить их делать так.
Для того, чтобы включить использование функции слежения, сначала укажите, за какими файлами нужно следить.
-lR
] файлы ...
Команда означает, что разработчикам нужно выполнить команду
cvs edit
перед редактированием файлов. Для того,
чтобы напомнить об этом разработчикам, CVS создаст рабочие
копии файлов в режиме только для чтения.
Если среди файлов есть имя каталога, CVS включает
слежение за всем файлами, находящимися в соответствующем каталоге
репозитория и автоматически включает режим слежения за всеми
файлами, которые будут в дальнейшем добавлены в каталог; это
позволяет пользователю задать стратегию уведомлений для каждого
каталога. Содержимое каталога обрабатывается рекурсивно, если
только не задан ключ командной строки -l
. Ключ -R
позволяет включить рекурсивное поведение, если в файле
`~/.cvsrc' оно было выключено с помощью ключа -l
(see section Ключи по умолчанию и файл ~/.cvsrc).
Если список файлов пропущен, по умолчанию обрабатывается текущий каталог.
-lR
] файлы ...
Команда означает, что при извлечении не нужно создавать
файлы в режиме только для чтения; таким образом,
разработчики не будут получать напоминания о необходимости
использования cvs edit
и cvs unedit
. CVS
будет извлекать файлы в обычном режиме, если только на
файле не установлены специальные права доступа, разрешенные с
помощью ключевого слова PreservePermissions
в
административном файле `config'; см. section Специальные файлы, а также See section Файл конфигурации CVSROOT/config.
Файлы и ключи командной строки обрабатываются точно так же,
как и для cvs watch on
.
Вы можете сказать CVS, что хотели бы получать уведомления о
разнообразных действиях, совершенных с файлом. В принципе вы
можете сделать это без использования cvs watch on
, но
обычно все же будете использовать как раз cvs watch on
,
чтобы другие разработчики использовали команду cvs edit
.
-a
действие] [-lR
] файлы ...
Добавить текущего пользователя в список лиц, которые будут получать уведомления о действиях, совершавшихся с файлами.
Ключ командной строки -a
задает тип событий, о которых
следует посылать уведомления. действие -- это
edit
cvs edit
(описанную ниже).
unedit
cvs unedit
(описанную
ниже) или команду cvs release
, или удалил файл и позволил
команде cvs update
создать его заново.
commit
all
none
cvs edit
,
описанной ниже.)
Ключ -a
можно указать несколько раз или вообще не
указывать, в этом случае по умолчанию используется all
.
Файлы и ключи командной строки обрабатываются так же, как и
в команде cvs watch
.
-a
действие] [-lR
] файлы ...
Удалить запрос на уведомление, созданный с помощью cvs
watch add
; аргументы те же самые. Если присутствует ключ
командной строки -a
, то только удаляются только слежения
за указанными действиями.
Когда требуется отправить уведомление, CVS обращается к административному файлу `notify'. Этот файл можно отредактировать точно так же, как и другие административные файл (see section Административные файлы). Синтаксис этого файла подобен другим административным файлам (see section Обычный синтаксис), где каждая строка состоит из регулярного выражения и команды, которую надо выполнить. Команда должна содержать одно единственное упоминание символов `%s', которые будут заменены на имя пользователя, которого нужно уведомить; остальная информация передается этой команде на стандартный вход. Обычно в файл `notify' помещается такая строка:
ALL mail %s -s \"CVS notification\"
В результате всего этого пользователи получают уведомления по электронной почте.
Заметьте, что если вы настроите все именно так, как рассказано выше, то пользователи будут получать уведомления на сервере. Конечно же, можно написать скрипт `notify', который перенаправляет уведомления на другой адрес, но, для простоты, CVS позволяет задать адрес, по которому следует отсылать уведомления пользователю. Для этого создайте в `CVSROOT' файл `users', в котором каждая строка имеет вид пользователь:адрес. Тогда вместо того, чтобы использовать имя пользователя, CVS будет использовать адрес.
CVS не уведомляет вас о ваших собственных изменениях. В настоящий момент проверка производится, основываясь на имени пользователя, который совершает действия, приводящие к отсылке уведомления. Вообще, функция слежения каждый раз сообщает только об одном изменении, сделанном одним пользователем. Вероятно, было бы более полезно, если бы отдельно отслеживались целые рабочие каталоги, поэтому такое поведение было бы полезно изменить.
Так как файл, за которым следит кто-либо, извлекается в режиме
только для чтения, то вы не можете просто взять и отредактировать
его. Для того, чтобы сделать его доступным для записи и сообщить
остальным, что вы планируете отредактировать этот файл,
используйте команду cvs edit
. Некоторые системы называют
это извлечение, но пользователи CVS уже используют
этот термин в смысле "получение копии исходных текстов"
(see section Получение исходного кода), а эту операцию, в свою
очередь, другие системы называют взять.
Подготовить для редактирования рабочие файлы. CVS делает файлы доступными для чтения и записи и уведомляет пользователей, которые уведомления о редактировании какого-нибудь из указанных файлов.
Команда cvs edit
принимает такие же ключи командной
строки, что и команда cvs watch add
, и устанавливает
временное слежение за файлами для пользователя; CVS
прекратит слежение, когда будет выполнена команда unedit
или команда commit
. Если пользователь не хочет получать
уведомления, он должен указать ключ -a none
.
Файлы и ключи командной строки обрабатываются точно так же,
как и для команды cvs watch
.
Предупреждение: если в репозитории разрешена опция
PreservePermissions
(see section Файл конфигурации CVSROOT/config), то CVS не
будет менять прав доступа к файлам. Причина этого
изменения -- убедиться, что cvs edit
не мешает хранению
прав доступа к файлам в CVS-репозитории.
Обычно, когда вы закончите редактирование файлов, используйте
команду cvs commit
, которая проверит ваши изменения и
вернет файлы, за которыми производилось слежение, в обычное
состояние только для чтения. Если же вы вместо этого решите
отменить изменения, или просто не станете ничего менять,
используйте команду cvs unedit
.
-lR
] files ...
Отбросить все изменения в рабочих файлах files и привести
их в соответствие с ревизией в репозитории. Если кто-либо
запросил уведомление об изменениях каких-либо файлов, то CVS
делает эти файлы доступными только для чтения. CVS
уведомляет пользователей, которые запросили уведомление о команде
unedit
.
Ключи командной строки и список файлов обрабатываются точно так
же, как для команды cvs watch
.
Если слежение не используется, команда unedit
, вероятно,
не работает, и единственный способ вернуть файл в то состояние, в
котором он находится в репозитории -- удалить его и использовать cvs update
для
получения новой копии. Семантика этой операции идентична команде
unedit
: удаление и обновление может внести также и
изменения, которые были помещены в репозиторий с тех пор, как вы
в последний раз обновляли свою рабочую копию.
При использовании сетевого CVS вы можете использовать
команды cvs edit
и cvs unedit
, даже если CVS
не смогла успешно соединиться с сервером. Уведомления будут
посланы при следующем успешном выполнении какой-либо команды
CVS.
-lR
] files ...
Выдает список пользователей, которые отслеживают изменения в files. Сообщаются имена файлов и почтовые адреса каждого следящего.
Ключи командной строки и список файлов обрабатываются так же, как
и в команде cvs watch
.
-lR
] files ...
Выдает список пользователей, которые в текущий момент работают над файлами files. Сообщаются почтовые адреса пользователей, время, когда пользователь начал работу с файлом, а также машина и рабочий каталог на ней, в котором находится каждый файл.
Список файлов и ключи командной строки обрабатываются точно так
же, как и в команде cvs watch
.
Если вы используете возможность слежения за репозиторием, то в нем создаются каталоги `CVS/', в которых хранится информация о слежениях за файлами из соответствующего каталога. Если вы попытаетесь использовать в этом репозитории CVS версии 1.6 и ранее, вы получите такое сообщение об ошибке:
cvs update: cannot open CVS/Entries for reading: No such file or directory
Выполняемая команда, скорее всего, будет прервана. Для
использования возможности слежения обновите все копии CVS,
которые используют этот репозиторий в локальном или серверном
режиме. Если вы не можете совершить обновление, используйте
команды watch off
и watch remove
, чтобы удалить все
слежения, а затем восстановите репозиторий в состояние, с которым
может работать @cvsver{1.6}.
Блокированные и неблокированные извлечения имеют свои "за" и "против". Достаточно сказать, что это в основном вопрос мнения, или же принятого в группе стиле работы. Впрочем же, вот краткое описание некоторых возникающих вопросов. Существует множество способов организовать команду разработчиков. CVS не пытается насильно внедрить какой-либо способ. CVS -- это просто инструмент, который можно использовать различными способами.
Блокированные извлечения могут оказывать отрицательное влияние на производительность. Если два человека хотят отредактировать различные части файла, какие могут быть причины помешать кому-нибудь из них сделать это? Обычным делом также является заблокировать файл, предполагая поредактировать его, а затем забыть снять блокировку.
Люди, обычно те, кто хорошо знаком с блокированными извлечениями, обычно спрашивают, как часто случаются конфликты при использовании неблокированных извлечений, и сколь сложно их разрешить. Опыт разнообразных групп показал, что такие конфликты случаются редко и обычно их можно разрешить относительно спокойно.
Редкость серьёзных конфликтов может удивить, пока не осознаешь, что они случаются только когда два разработчика расходятся во мнениях о должном дизайне определенного куска кода; такое расхождение свидетельствует о том, что команда, прежде всего, не общалась друг с другом должным образом. Для того, чтобы сотрудничать в условиях любой системы контроля исходных текстов, разработчики должны не иметь разногласий по поводу общего дизайна системы; при отсутствии таковых, пересекающиеся изменения обычно разрешаются напрямую.
В некоторых случаях неблокированные извлечения совершенно точно являются неподходящими. Если для файлов, которые вы редактируете, не существует инструмента для слияния (например, файлы, созданные текстовым процессором, или же файлы, созданные с помощью CAD-системы), а переход на программу, которая использует формат файлов с возможностью слияния, нежелателен, то разрешение конфликтов, скорее всего, будет столь неприятным, что будет проще избежать их, используя блокированные извлечения.
Возможность слежения, описанная выше, в главе section Как отследить, кто редактирует файлы?, может считаться промежуточной моделью между блокированными и неблокированными изменениями. Когда вы редактируете файл, можно узнать, кто ещё редактирует его. Система, вместо того, чтобы просто запретить двум людям редактировать файл, может описать ситуацию и позволить вам самому решить, является ли этот конкретный случай проблемой или нет. Таким образом, для некоторых групп механизм слежения может считаться объединением лучших черт блокированных и неблокированных изменений.
Go to the first, previous, next, last section, table of contents.