CVS -- Система Управления Параллельными Версиями - Создание ветвей и слияние
Go to the first, previous, next, last section, table of contents.
Создание ветвей и слияние
CVS позволяет изолировать изменения в отдельной линии разработки, называемой веткой. Когда вы изменяете файлы на ветке, эти изменения не появляются в основном стволе или на других ветках.
Позже вы можете переместить изменения с одной ветки на другую или
же с ветки в ствол, это называется слиянием. Сначала
выполняется cvs update -j
, чтобы слить изменения в
рабочий каталог, а затем эти изменения фиксируются, что приводит
к копированию изменения в другую ветку.
Для чего хороши ветви?
Предположим, был выпущен tc версии 1.0. Вы продолжаете его разработку, планируя выпустить версию 1.1 через пару месяцев. Через некоторое время ваши пользователи начинают жаловаться на серьезную ошибку. Вы извлекаете версию 1.0 (see section Метки ревизий) и находите ошибку, для исправления которой требуется всего лишь тривиальное изменение). Однако же, текущая версия исходников находится в крайне нестабильном состоянии и не стабилизируется по крайней мере еще месяц. Вы не можете выпустить исправленную версию, основываясь на свежих исходниках.
В подобной ситуации имеет смысл создать ветку в дереве ревизий, содержащую файлы, из которых состояла версия 1.0. Затем вы вносите изменения в ветвь без вторжения в основной ствол. Затем вы можете либо внести те же самые изменения в основной ствол, либо оставить их только на ветви.
Создание ветви
Вы можете создать ветвь, используя tag -b
. Например,
предполагая, что вы находитесь в каталоге с рабочей копией:
$ cvs tag -b rel-1-0-patches
Это отщепляет ветку, основанную на текущей ревизии рабочей копии, и присваивает этой ветке имя `rel-1-0-patches'.
Важно понимать, что ветки создаются в репозитории, а не в рабочей копии. Создание ветки, основанной на текущей ревизии, как в вышеприведенном примере, НЕ переключает рабочую копию на использование ветки (как сделать это -- описано в section Доступ к веткам).
Можно также создать ветку вообще без использования рабочей копии,
используя 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'.
Доступ к веткам
Вы можете извлечь ветку двумя способами: извлекая ее из репозитория в чистом каталоге или переключая существующую рабочую копию на ветку.
Для того, чтобы извлечь ветку из репозитория, выполните команду `checkout' с ключом командной строки `-r', с именем метки в качестве параметра (see section Создание ветви).
$ cvs checkout -r rel-1-0-patches tc
Если у вас уже есть рабочая копия, вы можете переключить ее на нужную ветку с помощью `update -r':
$ cvs update -r rel-1-0-patches tc
или, что то же самое:
$ cd tc $ cvs update -r rel-1-0-patches
Неважно, что рабочая копия была извлечена из основного ствола или какой-нибудь другой ветки: вышеприведенная команда переключит ее на указанную ветку. Подобно обычной команде `update', `update -r' сливает сделанные изменения, уведомляя вас о произошедших конфликтах.
Когда у вы связываете рабочую копию с какой-либо веткой, она будет находиться там, пока вы не укажете обратного. Это означает, что изменения, которые фиксируются из рабочей копии, будут добавлять новые ревизии на ветку, оставляя без изменений основной ствол и другие ветки.
Чтобы узнать, на какой ветви находится рабочая копия, можно использовать команду `status'. В том, что она вывела на экран, обратите внимание на поле, которое называется `Sticky tag' (see section Липкие метки) -- здесь CVS сообщает, на какой ветви находятся рабочие файлы:
$ 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)
Не смущайтесь тем, что номера ветвей для каждого файла различны (`1.7.2' и `1.4.2', соответственно). Метка ветви одна и та же, `rel-1-0-patches', и все файлы действительно находятся на одной и той же ветке. Номера лишь отражают точку в истории файла, в которой появилась ветвь. Из вышеприведенного примера можно узнать, что `driver.c' претерпел больше изменений, чем `backend.c', перед тем, как была создана ветка.
Смотри section Ветки и ревизии за деталями построения номеров ветвей.
Ветки и ревизии
Обычно история ревизий файла -- это линейная возрастающая последовательность номеров (see section Номера ревизий):
+-----+ +-----+ +-----+ +-----+ +-----+ ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 ! +-----+ +-----+ +-----+ +-----+ +-----+
Однако же, CVS не ограничен линейной разработкой. Дерево ревизий может быть расщеплено на ветви, где каждая ветвь -- самостоятельная линия разработки. Изменения, сделанные на одной ветке, легко могут быть внесены также и в основной ствол.
Каждая ветка имеет номер ветки, состоящий из нечетного числа десятичных чисел, разделенных точками. Номер ветки создается путем добавления целого числа к номеру ревизии, от которой была отщеплена ветка. Номера веток позволяют отщеплять от одной и той же ревизии несколько веток.
Все ревизии на ветке имеют номера ревизий, образованные путем добавления порядкового номера к номеру ветки. Вот иллюстрация создания веток.
+-------------+ Branch 1.2.2.3.2 -> ! 1.2.2.3.2.1 ! / +-------------+ / / +---------+ +---------+ +---------+ Branch 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 ! <- The main trunk +-----+ +-----+ +-----+ +-----+ +-----+ ! ! ! +---------+ +---------+ +---------+ Branch 1.2.4 -> +---! 1.2.4.1 !----! 1.2.4.2 !----! 1.2.4.3 ! +---------+ +---------+ +---------+
Обычно не требуется задумываться о точных деталях того, как строятся номера веток, но вот еще подробности: когда CVS создает номер ветки, он берет первое неиспользованное четное число, начиная с двойки. Поэтому, если вы хотите создать ветку от ревизии 6.4, она будет называться 6.4.2. Номера веток, заканчивающиеся на ноль (например, 6.4.0), используются для внутренних нужд CVS (see section Волшебные номера веток). Ветка 1.1.1 имеет специальное значение. See section Слежение за чужими исходными текстами.
Волшебные номера веток
В этой секции описана возможность CVS, называющаяся волшебные ветки. В большинстве случаев вам не потребуется беспокоиться о волшебных ветках, так как CVS сам следит за ними. Однако, вы можете увидеть их при определенных условиях, поэтому полезно было бы узнать, как они работают.
Номера веток состоят из нечетного количества десятичных целых, разделенных точками. See section Номера ревизий. Однако же, это не полная правда. Из соображений эффективности CVS иногда вставляет лишний ноль во вторую справа позицию (1.2.4 становится 1.2.0.4, а 8.9.10.11.12 становится 8.9.10.11.0.12 и так далее).
CVS довольно хорошо прячет такие "волшебные" ветки, но в нескольких местах ему это не удается:
-
Номера волшебных веток появляются в выдаче
cvs log
. -
Вы не можете указать символическое имя ветки в команде
cvs admin
.
Можно использовать команду admin
, чтобы переназначить
символическое имя ветки на то, которое ожидает увидеть CVS.
Например, если R4patches
присвоено ветке 1.4.2 (волшебный
номер 1.4.0.2) в файле `numbers.c', можно сделать так:
$ cvs admin -NR4patches:1.4.2 numbers.c
Это сработает, только если хотя бы одна ревизия уже была зафиксирована на ветке. Будьте очень осторожны, чтобы не присвоить метку неправильному числу, так как нет способа узнать, чему была присвоена эта метка вчера (за исключением ежедневного резервного копирования).
Слияние веток
Вы можете объединить изменения, сделанные на ветке, с вашей
рабочей копией, добавив флаг `-j ветка' к команде
update
. В результате 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.
В результате операции слияния может произойти конфликт. В это случае вам сначала надо справиться с ним перед фиксированием изменений. See section Пример конфликта.
Команда checkout
также поддерживает флаг `-j
ветка'. Можно добиться эффекта, обсуждавшегося выше, с
помощью
$ cvs checkout -j R1fix mod $ cvs commit -m "Добавлен R1fix"
Многократное слияние из ветки
Мы продолжаем обсуждение примера. Теперь дерево ревизий выглядит так:
+-----+ +-----+ +-----+ +-----+ +-----+ ! 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.2. Чуть лучшим подходом будет использование даты совершения последнего слияния.
cvs update -j R1fix:yesterday -j R1fix m.c
Еще лучше было бы помечать ветку `R1fix' после каждого слияния со стволом, и использовать эту метку для дальнейших слияний:
cvs update -j merged_from_R1fix_to_trunk -j R1fix m.c
Слияние изменений между двумя ревизиями
С помощью двух флагов `-j ревизия', команды update
и
checkout
могут сливать изменения между любыми двумя ревизиями в
ваш рабочий файл.
Команда
$ cvs update -j 1.5 -j 1.3 backend.c
отменит изменения, сделанные между ревизиями 1.3 и 1.5. Обратите внимание на порядок указания ревизий!
Если вы попробуете использовать эту опцию при работе с несколькими файлами, помните, что номера ревизий, вероятно, будут для разных файлов сильно отличаться. В таких случаях почти всегда следует использовать алфавитные метки, а не номера ревизий.
Указав два ключа командной строки `-j', можно также отменить удаления и добавления файлов. Например, предположим, у вас есть файл `file1', существовавший в ревизии 1.1. Затем вы удалили его, создав "мертвую" ревизию 1.2. Теперь предположим, что вы хотите добавить его опять, с тем же самым содержимым, что он имел ранее. Вот как сделать это:
$ cvs update -j 1.2 -j 1.1 file1 U file1 $ cvs commit -m test Checking in file1; /tmp/cvs-sanity/cvsroot/first-dir/file1,v <-- file1 new revision: 1.3; previous revision: 1.2 done $
При слиянии можно добавлять и удалять файлы
Если измененяи, которые вы сливаете, включают в себя удаление или
добавление каких-либо файлов, то команда update -j
учтет такие
добавления и удаления.
For example:
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
После того, как эти команды выполнены, а также выполнена команда `cvs commit', файл `a' будет удален, а файл `d' будет добавлен в основной ствол.
Go to the first, previous, next, last section, table of contents.