next up previous contents
Next: 14.8 Конфигурационный файл modules Up: 14. CVS - система Previous: 14.6 Версии файлов и

Подраздел


14.7 Ветвление и объединение

CVS позволяет вам выделить какие-то изменения проекта в отдельную линию разработки, которую называют ветвь (branch). Когда вы меняете файлы в одной из ветвей, то эти изменения не появятся в основном стволе или в других ветвях.

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

14.7.1 Для чего удобны ветви?

Предположим, что версия вашего продукта tc 1.0 вышла и начала использоваться. Вы продолжаете разрабатывать продукт tc, очередная версия которого 1.1 выйдет в ближайшие несколько месяцев. Однако, в это время ваши заказчики или партн©ры стали жаловаться на фатальные ошибки в версии 1.0. Вы начали искать и быстро обнаружили ошибку, которую немедленно следует устранить. Однако наиболее свежие версии файлов представляют весьма нестабильное состояние и станут стабильными лишь через месяц или более. Таким образом, вы не можете исправить ошибку в наиболее свежих версиях и предоставить их заказчикам.

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

14.7.2 Создание ветви

Вы может создать ветвь командой 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.

14.7.3 Доступ к ветвям

Вы можете получить копию ветви одним из двух способов: прочесть ветвь из хранилища с помощью команды 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 до момента создания данной ветви.

14.7.4 Ветви и номера версий

Как уже отмечалось, обычно история последовательных версий продукта имеют линейную структуру:

     +-----+    +-----+    +-----+    +-----+    +-----+
     ! 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.

14.7.5 Магические номера ветвей

Этот раздел описывает возможности CVS называемые магические ветви. Они не требуются пользователю при обычной работе, однако они видны иногда в диагностике, поэтому полезно представлять для чего они служат.

Номера ветвей состоят из неч©тного числа десятичных целых, раздел©нных точками. Однако это не полная правда. В целях повышения эффективности своей работы CVS иногда вставляет дополнительный ноль (0) во вторую справа позицию номера ветви (таким образом 1.2.4 становится 1.2.0.4, 8.9.10.11.12 становится 8.9.10.11.0.12 и так далее).

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

Вы можете использовать команду admin, чтобы переприсвоить символическое имя ветви, как его ожидает увидеть система RCS. Если имя R4patches присвоено ветви 1.4.2 (магический номер ветви 1.4.0.2) в файле numbers.c, то вы можете сделать:
cvs admin -NR4patches:1.4.2 numbers.c
Это будет работать, если только хотя бы одна версия была уже утверждена (committed) в ветви. Будьте внимательны, чтобы не назначить тег неверному номеру, поскольку на другой день не будет возможности увидеть чему назначен тег.

14.7.6 Слияние ветвей

Вы можете объединить изменения в отдельной ветви и изменения в вашем рабочем каталоге используя параметр -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) изменений.

14.7.7 Слияние из ветвей несколько раз

Продолжая наш пример, дерево версий теперь выглядит так:

+-----+    +-----+    +-----+    +-----+    +-----+
! 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 !
                    +---------+    +---------+    +---------+
Теперь вы захотите объединить эти новые изменения и основной ствол разработки. Если вы просто попытаетесь использовать команду
cvs update -j R1fix m.c
снова, то CVS вновь попробует объединить изменения, но это может также иметь нежелательные побочные эффекты, поскольку объединение уже выполнялось однажды ранее.

Чтобы избежать побочного эффекта, вам следует определить, что вы хотите объединить изменения в ветви, которая ещ© не была объединена с основным стволом. Чтобы так сделать, вы определяете два параметра -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

14.7.8 Объединение различий между двумя любыми версиями

С двумя параметрами -j REVISION команды updatecheckout) могут объединить отличия между любыми двумя версиями, записав результат в ваш рабочий файл. Так
cvs update -j 1.5 -j 1.3 backend.c
удалит все изменения, сделанные между версиями 1.3 и 1.5. Обратите внимание на порядок версий в командной строке!

Если вы попытаетесь использовать эту возможность сразу на множестве файлов, то помните, что числовые значения версий могут весьма отличаться для различных файлов, которые вместе составляют модуль в смысле системы CVS. Почти всегда вы используете символические теги, а не номера версий, когда имеете дело сразу со многими файлами.

14.7.9 Объединение может добавить или удалить файлы

Если изменения, которые вы объединяете, влючают удаление одних файлов или добавление других, то команда 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 будет добавлен к основной ветви.

14.7.10 Каталог CVS в хранилище

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

14.7.11 Форма хранения данных в рабочем каталоге

Раз мы обсуждаем некоторые детали работы хранилища CVS, то полезно кратко описать, что помещает система CVS в ваш рабочий каталог в подкаталог с именем CVS. В некоторых случаях может оказаться полезным заглянуть внутрь подкаталога CVS в вашем рабочем каталоге. Напомним, что такой подкаталог появится, когда вы выполните команду
cvs checkout ProJ
Здесь ProJ есть имя каталога в хранилище CVS. По этой команде в вашем рабочем каталоге будет создан подкаталог с именем ProJ, в который будет скопировано содержимое каталога ProJ из хранилища CVS. Когда вы перейд©те в каталог ProJ, то увидите подкаталог с именем CVS, который используется системой CVS.

Каталог CVS содержит несколько файлов, каждый из которых просто текстовый файл. Рассмотрим их чуть детальнее.

Root
Этот файл содержит имя текущего каталога, в котором располагается хранилище CVS, то же что в переменной $CVSROOT.

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

Entries
Этот файл содержит списки файлов и каталогов в рабочем каталоге.

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

Entries.Backup
Временный файл.

Entries.Static
Служебный файл CVS. Для CVS важно лишь существует этот файл или нет.

Tag
Этото файл содержит теги (описатели) или даты для подкаталогов.

Checkin.prog | Update.prog
Эти файлы хранят программы, специфицированные параметрами -i и -u в файлах модулей соответственно.

Notify
Этот файл хранит сообщения, поке ещ© не посланные на сервер, например, edit или noedit.

Notify.tmp
Вспомогательный файл для поддержания файла Notify.

Base
Если используются наблюдатели (watches), тогда команда edit запоминает исходную копию файла в каталоге Base. Это позволяет выполнить команду unedit, даже если нет возможности связаться с сервером.

Baserev
Этот файл перечисляет версии всех файлов в каталоге Base.

Baserev.tmp
Временный файл, служит для поддержания Base.

Template
Этот файл содержит заготовку, определ©нную посредством файла rcsinfo. Файл используется только на клиентской стороне.


next up previous contents
Next: 14.8 Конфигурационный файл modules Up: 14. CVS - система Previous: 14.6 Версии файлов и
Andrei Chevel
Andrei.Chevel@pnpi.spb.ru