CVS позволяет вам выделить какие-то изменения проекта в отдельную линию разработки, которую называют ветвь (branch). Когда вы меняете файлы в одной из ветвей, то эти изменения не появятся в основном стволе или в других ветвях.
Позднее вы сможет переместить ваши изменения из одной ветви в другую или в основной ствол посредством объединения (merging). Объединение включает прежде всего выполнение команды cvs update -j, чтобы объединить изменения в рабочем каталоге. После этого вы может утвердить (commit) эту версию, тем самым реально скопировав изменения в другую ветвь разработки.
Предположим, что версия вашего продукта tc 1.0 вышла и начала использоваться. Вы продолжаете разрабатывать продукт tc, очередная версия которого 1.1 выйдет в ближайшие несколько месяцев. Однако, в это время ваши заказчики или партн©ры стали жаловаться на фатальные ошибки в версии 1.0. Вы начали искать и быстро обнаружили ошибку, которую немедленно следует устранить. Однако наиболее свежие версии файлов представляют весьма нестабильное состояние и станут стабильными лишь через месяц или более. Таким образом, вы не можете исправить ошибку в наиболее свежих версиях и предоставить их заказчикам.
В такой ситуации удобнее всего создать отдельную ветвь для всех файлов, которые составляют ваш продукт tc версии 1.0. Там вы сможете менять файлы, исправляя текущие ошибки в программах. Эти исправления никак не будут влиять на основной ствол разработки. Когда срочные исправления внесены и заказчики удовлетворены, вы можете выбрать стиль поведения: оставить ваши исправления в ветви или инкорпорировать их в основной ствол разработки.
Вы может создать ветвь командой tag -b; например, предполагая, что
вы в рабочем каталоге
cvs tag -b rel-1-0-patches
Эта команда отделяет ветвь с именем rel-1-0-patches, которая
базируется на текущих версиях файлов в рабочем каталоге.
Важно понять, что ветви создаются в хранилище, а не в рабочем каталоге. Создание ветви базирующейся на текущих версиях файлов, как показано в предыдущем примере, не означает, что рабочая копию комплекта файлов в рабочем каталоге немедленно начн©т рассматриваться как новая ветвь. Как это сделать мы узнаем чуть позже.
Новую ветвь можно создать, не используя рабочей копии, посредством команды
rtag
cvs rtag -b -r rel-1-0 rel-1-0-patches tc
Здесь параметр -r rel-1-0 говорит, что новая ветвь должна корениться
(отрастать) в версии, которая соответствует тегу rel-1-0. Совсем не
обязательно, что это будет наиболее свежая версия. Часто удобно выделить
ветвь в старой версии продукта (той версии, где была исправлена ошибка).
Как и с командой tag параметр -b созда©т новую ветвь и с командой rtag. Заметим однако, что числовое значение номера версии, который удовлетворяет rel-1-0 может быть различным для каждого файла.
Таким образом, полный эффект команды состоит в создании новой ветви с именем rel-1-0-patches в модуле tc и основывающейся на комплекте файлов, входящих в версию rel-1-0 модуля (продукта) tc.
Вы можете получить копию ветви одним из двух способов: прочесть ветвь из хранилища с помощью команды checkout или переключить существующую рабочую копию на требуемую ветвь проекта.
Чтение конкретной ветви из хранилища с помощью команды checkout
выполняется следующим образом:
cvs checkout -r rel-1-0-patches tc
Здесь за параметром -r следует имя тега с именем rel-1-0-patches, который описывает ветвь.
Переключить рабочий каталог, в котором уже имеется рабочая
копия, на требуемую ветвь можно следующим образом:
cvs update -r rel-1-0-patches tc
Несущественно, если содержимое рабочего каталога соответствовало основному
стволу или другой ветви. По команде update -r будет выполнено
слияние (объединение) тех изменений, которые вы уже сделали в рабочем
каталоге,
и содержимое ветви в хранилище. Если при слиянии возникнут конфликты, то
вы получите соответствующую диагностику.
Раз содержимое вашего рабочего каталога соответствует конкретной ветви, то это соответствие таким и останется, пока вы не скажете явно что-то другое. Это значит, что любые подтверждения (commit) изменений в файлах будут проявляться лишь в конкретной ветви. В то же время никаких изменений не будет происходить ни в других ветвях, ни в основном стволе.
Чтобы определить какая ветвь находится в данный момент в рабочем каталоге,
можно использовать команду status:
cvs status -v driver.c backend.c
=================================================================== File: driver.c Status: Up-to-date Version: 1.7 Sat Dec 5 18:25:54 1992 RCS Version: 1.7 /u/cvsroot/yoyodyne/tc/driver.c,v Sticky Tag: rel-1-0-patches (branch: 1.7.2) Sticky Date: (none) Sticky Options: (none) Existing Tags: rel-1-0-patches (branch: 1.7.2) rel-1-0 (revision: 1.7) =================================================================== File: backend.c Status: Up-to-date Version: 1.4 Tue Dec 1 14:39:01 1992 RCS Version: 1.4 /u/cvsroot/yoyodyne/tc/backend.c,v Sticky Tag: rel-1-0-patches (branch: 1.4.2) Sticky Date: (none) Sticky Options: (none) Existing Tags: rel-1-0-patches (branch: 1.4.2) rel-1-0 (revision: 1.4) rel-0-4 (revision: 1.4)В выводимой информации обратите внимание на липкий тег (Sticky Tag). Он содержит информацию о конкретной ветви, если таковая есть.
Не стоит смущаться тем фактом, что номера версий ветви для каждого файла различны (1.7.2 и 1.4.2 соответственно). Тег ветви является тем же самым (rel-1-0-patches) и, следовательно, эти файлы находятся в одной ветви. Номера 1.7.2 и 1.4.2 отражают лишь конкретное состояние соответствующих файлов в момент создания ветви. По этим числам из вышепривед©нного примера можно лишь заключить, что файл driver.c менялся чаще, чем файл backend.c до момента создания данной ветви.
Как уже отмечалось, обычно история последовательных версий продукта имеют линейную структуру:
+-----+ +-----+ +-----+ +-----+ +-----+ ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 ! +-----+ +-----+ +-----+ +-----+ +-----+Однако CVS не ограничивается лишь линейными представлениями процесса разработки. Основное дерево (ствол) версий может быть разбито на несколько независимых ветвей. Изменения, которые имеют место в конкретной ветви, могут быть позже перемещены как в основной ствол, так и в другую ветвь.
Каждая ветвь имеет номер ветви, который состоит из неч©тного числа десятичных целых, раздел©нных точками. Номер ветви составляется из номера версии программного продукта с добавлением десятичного целого. Наличие номера ветви позволяет иметь несколько ветвей от одной версии продукта.
Все версии в ветви составлены из номера ветви, за которым следует порядковый номер версии. Нижеследующая картинка поясняет нумерацию ветвей на примерах.
+-------------+ Ветвь 1.2.2.3.2 -> ! 1.2.2.3.2.1 ! / +-------------+ / / +---------+ +---------+ +---------+ Ветвь 1.2.2 -> _! 1.2.2.1 !----! 1.2.2.2 !----! 1.2.2.3 ! / +---------+ +---------+ +---------+ / / +-----+ +-----+ +-----+ +-----+ +-----+ ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 ! <- Основной +-----+ +-----+ +-----+ +-----+ +-----+ ствол ! ! ! +---------+ +---------+ +---------+ Ветвь 1.2.4 -> +---! 1.2.4.1 !----! 1.2.4.2 !----! 1.2.4.3 ! +---------+ +---------+ +---------+Обычно вы не нуждаетесь в точном описании того, как образуются новые номера ветвей, поэтому кратко обрисуем как это работает в целом. Когда CVS образует ветвь, она бер©т первое неиспользуемое ч©тное десятичное целое начиная с 2. Таким образом, если вы захотите образовать ветвь от версии 7.6, то номер ветви будет равен 7.6.2. Все ветви с номерами оканчивающимися на 0 (нуль) используются самой системой CVS.
Этот раздел описывает возможности CVS называемые магические ветви. Они не требуются пользователю при обычной работе, однако они видны иногда в диагностике, поэтому полезно представлять для чего они служат.
Номера ветвей состоят из неч©тного числа десятичных целых, раздел©нных точками. Однако это не полная правда. В целях повышения эффективности своей работы CVS иногда вставляет дополнительный ноль (0) во вторую справа позицию номера ветви (таким образом 1.2.4 становится 1.2.0.4, 8.9.10.11.12 становится 8.9.10.11.0.12 и так далее).
CVS выполняет всю работу связанную с магическими номерами внутри, но иногда они могут появляться снаружи:
Вы можете объединить изменения в отдельной ветви и изменения в вашем рабочем каталоге используя параметр -j branch в команде update. С одним параметром -j branch система CVS объединяет все изменения, сделанные в ветви от момента е© создания и содержимое рабочего каталога. Очевидно, что -j означает объединение (join).
Рассмотрим следующее дерево версий:
+-----+ +-----+ +-----+ +-----+ ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 ! <- Основной +-----+ +-----+ +-----+ +-----+ ствол ! ! ! +---------+ +---------+ Ветвь R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 ! +---------+ +---------+Ветви 1.2.2 присвоено символическое имя (тег) R1fix. Следующий пример предполагает, что модуль mod содержит один файл m.c.
$ cvs checkout mod # Поместить в рабочий каталог # последнюю версию, 1.4 $ cvs update -j R1fix m.c # Объединить все изменения сделанные # в ветви, т.е. изменения между версиями # 1.2 и 1.2.2.2, с изменениями, которые # вы сделали в рабочем каталоге $ cvs commit -m "Included R1fix" # Создать версию 1.5.
Во время объединения разных версий могут возникнуть конфликты. Если такое случится, то конфликты должны быть разрешены до утверждения (commit) изменений.
Продолжая наш пример, дерево версий теперь выглядит так:
+-----+ +-----+ +-----+ +-----+ +-----+ ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 ! <- основной +-----+ +-----+ +-----+ +-----+ +-----+ ствол ! * ! * ! +---------+ +---------+ Ветвь R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 ! +---------+ +---------+Здесь зв©здочками обозначены линии слияния ветви R1fix с основным стволом, как мы обсуждали в прошлом разделе.
Теперь, предположим, разработка ветви R1fix продолжается.
+-----+ +-----+ +-----+ +-----+ +-----+ ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 ! <- Основной +-----+ +-----+ +-----+ +-----+ +-----+ ствол ! * ! * ! +---------+ +---------+ +---------+ Ветвь R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 !----! 1.2.2.3 ! +---------+ +---------+ +---------+Теперь вы захотите объединить эти новые изменения и основной ствол разработки. Если вы просто попытаетесь использовать команду
Чтобы избежать побочного эффекта, вам следует определить, что вы хотите
объединить изменения в ветви, которая ещ© не была объединена с основным
стволом. Чтобы так сделать, вы определяете два параметра -j, тогда
CVS объединит изменения из первой версии во вторую. Например, в данном
простейшем случае могло бы быть так:
cvs update -j 1.2.2.2 -j R1fix m.c
объединить изменения в рабочем каталоге с ветвью 1.2.2.2, а затем с ветвью
R1fix (т.е. 1.2.2.3). Проблема здесь лишь в том, что версию 1.2.2.2
вам следует указать вручную. Чуть лучшее решение могло бы быть
применено с использованием даты, когда имело место последнее объединение:
cvs update -j R1fix:yesterday -j R1fix m.c
Еще чуть лучше, помечать тегом ветвь R1fix каждый раз, когда
производится объединение в основном стволе, и позднее использовать этот
тег в
последующих объединениях:
cvs update -j merged_from_R1fix_to_trunk -j R1fix m.c
С двумя параметрами -j REVISION команды update (и checkout) могут объединить отличия между любыми двумя версиями, записав
результат в ваш рабочий файл. Так
cvs update -j 1.5 -j 1.3 backend.c
удалит все изменения, сделанные между версиями 1.3 и 1.5. Обратите
внимание на порядок версий в командной строке!
Если вы попытаетесь использовать эту возможность сразу на множестве файлов, то помните, что числовые значения версий могут весьма отличаться для различных файлов, которые вместе составляют модуль в смысле системы CVS. Почти всегда вы используете символические теги, а не номера версий, когда имеете дело сразу со многими файлами.
Если изменения, которые вы объединяете, влючают удаление одних файлов или
добавление других, то команда update -j будет отражать такие
изменения. Например
cvs update -A touch a b c cvs add a b c ; cvs ci -m "added" a b c cvs tag -b branchtag cvs update -r branchtag touch d ; cvs add d rm a ; cvs rm a cvs ci -m "added d, removed a" cvs update -A cvs update -jbranchtag
После выполнения этих команд и после выполнения подтверждения (команда commit) файл a будет удал©н, а файл d будет добавлен к основной ветви.
Раз мы обсуждаем некоторые детали работы хранилища CVS, то полезно кратко
описать, что помещает система CVS в ваш рабочий каталог в подкаталог
с именем CVS.
В некоторых случаях может оказаться полезным заглянуть внутрь подкаталога
CVS в
вашем рабочем каталоге. Напомним, что такой подкаталог появится, когда вы
выполните команду
cvs checkout ProJ
Здесь ProJ есть имя каталога в хранилище CVS. По этой команде
в вашем
рабочем каталоге будет создан подкаталог с именем ProJ, в который
будет скопировано содержимое каталога ProJ из хранилища CVS. Когда вы
перейд©те в каталог ProJ, то увидите подкаталог с именем CVS,
который используется системой CVS.
Каталог CVS содержит несколько файлов, каждый из которых просто текстовый файл. Рассмотрим их чуть детальнее.