Журнал LinuxFormat - перейти на главную

LXF71:Subversion

Материал из Linuxformat
Версия от 21:58, 4 февраля 2009; Yaleks (обсуждение | вклад)

(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

Содержание

Subversion ветви, тэги и слияния

чАстЬ 3 Грэхем моррисон объясняет, как управлять репозитарием по мере того, как проект начинает расширяться

Это – финальная статья из цикла, посвященного системе контроля версий Subversion. После изучения базовых вопросов настройки, администрирования сервера и работы с клиентом Subversion, вы уже можете представить себе преимущества от использования данной системы в вашем проекте. Впрочем, спустя некоторое время вам потребуется некоторая дополнительная информация, касающаяся в первую очередь ветвей (branches). Именно об этом мы и поговорим сегодня.

Мы будем использовать некоторые из предложенных ранее концепций, чтобы проиллюстрировать удачные решения на серверной стороне. они окажут некоторое влияние на то, как вы работаете со своим репозитарием Subversion, хотя все необходимые действия будут выполняться со стороны клиента. Вам также потребуется материал предыдущих лекций, поэтому можете освежить его, прежде чем переходить к данной статье.

Лесоводство: повторение

Настоящие деревья (те, что растут в лесу) имеют ветви. Ветви являются отростками от главного ствола дерева. Ветви Subversion играют аналогичную роль с одним небольшим отличием: со временем одна из них может сама стать стволом, что не так-то просто проделать в случае с реальным деревом. Ветви Subversion укрепляют процесс разработки, а не расшатывают его.

Существует несколько причин для организации ответвлений от главной линии разработки. Самой распространенной из них является создание новой версии таким образом, чтобы позволить выпускать критичные исправления и для предыдущей. Например, для KDE 3.4 вышло обновление, имеющее номер 3.4.1. оно устраняет некоторые ошибки, добавляет пару переводов, но не содержит в себе новых функций. Последние припасены для ближайшего «большого» обновления.

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

этап 1 – Разветвляемся

(thumbnail)
История Subversion

Ветвь удобно представлять себе как простую копию основного репозитария кода (main trunk), сделанную в определенный момент времени. Строго говоря, никто не мешает использовать вам для реализации задуманного и локальную копию, но в этом нет нужды. Для Subversion, ветвь – не более, чем копия, хотя исходный вариант ее истории изменений является общим с основным деревом. Это оказывает свое влияние на процесс создания ветви.

Для иллюстрации мы по-прежнему будем использовать простое приложение «Здравствуй, мир» из предыдущих выпусков. О но состоит из маленького файла с исходным кодом (helloworld.cpp) и отвечающего ему файла Makefile. Сейчас они оба располагаются в одном каталоге, но по мере «ветвления» будут разнесены по разным веткам.

$ svn mkdir branches
A branches
$ svn mkdir branches/stable_1_0
A branches/stable_1_0
$ svn mv helloworld.cpp branches/stable_1_0/
A branches/stable_1_0/helloworld.cpp
D helloworld.cpp
$ svn mv Makefile branches/stable_1_0/
A branches/stable_1_0/Makefile
D Makefile

Мы создали в нашей локальной рабочей копии каталог «branches» и разместили в нем подкаталог «stable_1_0», в котором будет хранится стабильная версия. Затем, в рамках подготовки к разветвлению кода, мы переместили оба файла в директорию stable_1_0. Следующим шагом будет копирование каталога, соответствующего ветви stable_1_0, в каталог, который отвечает нашей нестабильной разрабатываемой ветви. О днако, прежде чем Subversion позволит нам это сделать, необходимо зафиксировать (commit) предыдущие изменения.

$ svn commit -m “Created new branch structure.”
Deleting Makefile
Adding branches
Adding branches/stable_1_0
Adding branches/stable_1_0/Makefile
Adding branches/stable_1_0/helloworld.cpp
Deleting helloworld.cpp
Committed revision 5.

Флаг -m позволяет вам прокомментировать фиксируемые изменения, не запуская внешний текстовый редактор. Т еперь, когда с предыдущими ревизиями покончено, можно начать разрабатываемую ветвь, сделав копию каталога stable_1_0.$ cd branches/

$ svn copy stable_1_0 HEAD
A HEAD
$ svn commit
Adding branches/HEAD
Committed revision 6.

В данном примере, мы использовали копию стабильной ветви (stable branch) для создания разрабатываемой (development branch), в которую планируется добавлять новые функции и исправления найденных ошибок. Поскольку мы идем во главе процесса разработки, назовем ее «HEAD».

Управление доступом

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

Если вы заботитесь о безопасности, то можете захотеть ограничить доступ к существующим ветвям и дать лишь некоторым участникам проекта право на создание новых. Чтобы предоставить избранным разработчикам права на модификацию тех или иных ветвей, для доступа к репозитарию необходимо использовать Apache. Причина этого состоит в следующем: наиболее простым способом разграничения доступа по пользователям является установка модуля Apache под названием mod_authz_svn.

Теперь из каталога HEAD можно получить новую копию разрабатываемой ветви.

$ svn checkout file:///usr/share/subres/branches/HEAD
A HEAD/helloworld.cpp
A HEAD/Makefile
Checked out revision 6.

История изменений для каталога HEAD будет распространяться назад лишь до точки ветвления. О днако, внутри каждой ветви, история изменения индивидуальных файлов будет перенесена из их прежнего местоположения. О тличие состоит в том, что helloworld.cpp сейчас скопирован в два каталога (содержится в двух ветвях). История изменения файла helloworld.cpp также будет разветвлена, чтобы хранить сведения для каждого файла по отдельности. В этом легко убедиться, просмотрев журнал команд. Ниже представлена урезанная версия вывода svn log helloworld.cpp для ветви HEAD:

r7 | Added a cutting-edge feature.
r6 | Added HEAD development branch.
r5 | Moved project into a branch structure
r4 | Resolved conflict by incorporating both changes.

Как видите helloworld.cpp наследует историю со времени, предшествующего созданию ветви в момент r6. В зависимости от организации проекта, процесс добавления новых функций в HEAD может потребовать переноса некоторых исправлений ошибок и тому подобных вещей назад, в стабильную ветвь. Чтобы сделать это, нам придется слить (merge) изменения со стабильной ветвью.

этАп 2 – сЛивАем одну ветвЬ с друГой

(thumbnail)
Код в дереве разработки наследуется каждой последовательной версией
[1] оригинальная версия (1.0).
[2] исправления для оригинальной версии (1.1).
[3] Функции, запланированные для следующей версии (2.0).

работа над тестовой ветвью часто подразумевает решение проблем, которые имеют отношение и к стабильной ветви, особенно если речь идет о безопасности. В нашем примере с helloworld.cpp в разрабатываемую ветвь была добавлена еще одна строка, выводящая надпись «a cutting-edge feature». конечно, в реальном случае изменения будут куда более серьезными, но обсуждаемые принципы останутся неизменными.

Несмотря на общее происхождение, Subversion рассматривает эти два файла как полностью различные. В прошлый раз мы использовали команду svn diff для поиска различий между двумя ревизиями одного и того же файла. На сей раз перед нами стоит несколько другая задача: надо найти отличие между одним и тем же файлом, но принадлежащим двум разным ветвям. Для этого нам потребуется команда svn merge. Перво-наперво, необходимо сравнить изменения, произведенные в стабильной и разрабатываемой ветвях.

Просматривая журнал для helloworld.cpp из стабильной ветви, становится очевидно, что здесь нет изменений, относящихся к разрабатываемой ветви:

r5 | Moved project into a branch structure
r4 | Resolved conflict by incorporating both changes.

ревизии r6 и r7 ветки HEAD отсутствуют. как было видно из предыдущих листингов, r6 – это процесс копирования файлов в новую ветвь, а r7 – добавление новой, очень интересной функции (r7 | added a cutting-edge feature). разность между этими двумя ревизиями может быть определена с помощью svn diff:

$ svn diff -r 6:7 file:///usr/share/subres/branches/
Index: HEAD/helloworld.cpp
=================
--- HEAD/helloworld.cpp (revision 6)
+++ HEAD/helloworld.cpp (revision 7)
@@ -6,6 +6,7 @@
{
cout << “Hello World!” << endl;
cout << “Both modified additions.” << endl;
+ cout << “Cutting edge feature.” <<endl;
return(0);
}

Единственное добавление – это «суперновая функция» («cutting edge feature»), отмеченная в листинге знаком «+», расположенным в начале строки. как мы видели в прошлом месяце, вывод svn diff можно использовать для создания патча. В случае с Subversion в этом нет необходимости, поскольку для применения всех необходимых изменений к вашей рабочей копии можно использовать команду svn merge. Начните с локальной копии файла helloworld.cpp и добавьте в него изменения, отвечающие нужным ревизиям:

$ svn merge -r 6:7 file:///usr/share/subres/branches/HEAD/helloworld.cpp
U helloworld.cpp
$ svn status
M helloworld.cpp

Согласно нашему коду, изменения, сделанные в ветви HEAD, были перенесены в локальную копию того же файла, отмеченного буквой M в первой колонке вывода команды svn merge. теперь можно просмотреть эти изменения и зафиксировать их в стабильной ветви. Между слитой и оригинальной версиями может возникнуть конфликт, поэтому будьте внимательны, объединяя изменения между двумя ветвями.

перемотка

Использование номеров ревизий в качестве идентификаторов применяемых к вашему коду изменений может иметь нестандартные побочные эффекты. Например, их можно не указывать при переходе от одной ревизии к другой. Их также можно переворачивать. Написав «7:6» вместо «6:7», вы осуществите откат изменений седьмой ревизии до уровня шестой. В духе предыдущего примера, можно написать:

svn merge -r 7:6 file:///usr/share/subres/branches/HEAD/helloworld.cpp
G helloworld.cpp

буква «G» обозначает, что Subversion удачно применил изменения, хранящиеся в репозитарии, к локальному файлу. Здесь уместно упомянуть команду svn revert, представляющую собой куда более безопасный метод для отката локально сделанных изменений и восстановления нужной версии из репозитария.

Другим удобным трюком является смена ветви, которая соотвествует вашей локальной копии на сервере. Это достигается командой svn switch. На самом деле, она не делает ничего экстраординарного – просто подменяет URL, на который ссылается рабочая копия. текущий URL можно просмотреть с помощью команды svn info:

$ svn info
URL: file:///usr/share/subres/branches/stable_1_0

В нашем примере можно изменить ветвь со stable_1_0 на HEAD, введя команду:

$ svn switch file:///usr/share/subres/branches/HEAD
U helloworld.cpp
Updated to revision 7.
$ svn info
URL: file:///usr/share/subres/branches/HEAD

чАстЬ 3 – КЛеймЛение

Ветви сторонних поставщиков (vendor banches) позволяют включать в ваш проект разработки других людей, например, внешние библиотеки. С помощью ветвей поставщиков можно следить за изменениями в других проектах и, более того, быть уверенным, что все ваши разработчики используют одну и ту же версию. CVS имеет специальную поддержку для ветвей сторонних поставщиков, однако, Subversion достаточно универсален, чтобы интегрировать их без особых трудов.

Ветвь стороннего поставщика обычно существует в своей структуре каталогов под общим корнем репозитария Subversion. Ее часто размещают в директории с названием «vendor» - отсюда и название «vendor branch». В этот каталог необходимо импортировать весь сторонний проект целиком. когда выходит новая версия данного продукта, необходимо применять все изменения к текущей рабочей версии, чтобы ваши собственные правки не потерялись. После этого можно зафиксировать изменения в репозитории с тем, чтобы другие разработчики получили возможность использовать более новую версию стороннего приложения.

игры с тегами

Для эффективного использования ветви стороннего поставщика необходимо быть уверенным, что она не может быть изменена. В терминах системы контроля версий это известно как «теггинг» (tagging), а с точки зрения Subversion, это просто ветвь, которую нельзя редактировать. как и ветвь, тег (tag) – это копия репозитария, сделанная в некоторый момент времени. тег похож на установку точки ревизии, более того, так оно и есть, однако, на него возлагаются некоторые дополнительные функции. тег - хороший способ отметить прохождение контрольной точки в цикле разработки.

одной из главных причин для создания тега является выпуск важной версии, например, stable_1_0 в нашем примере. как и ветви, теги – не более чем копии репозитария, и для их создания можно использовать команду svn copy. Единственным отличием является необходимость явно указать создание тега в комментарии к ревизии и запрет на редактирование помеченных ветвей со стороны других разработчиков.

Чтобы сделать тег в нашем предыдущем примере, выполните следующие команды:

$ svn mkdir file:///usr/share/subres/tags
Committed revision 8.
$ svn copy file:///usr/share/subres/branches/stable_1_0 file:///usr/share/subres/tags/release_1
Committed revision 9.

такой подход обладает очевидным недостатком: ничто не мешает разработчику взять и изменить содержимое данной директории. В большинстве случаев это не проблема, так как «неприкосновенность» тегов регулируется политикой проекта. однако, в случае необходимости вы можете «затянуть гайки».

Это потребует от нас перейти к первом руководству из данной серии, поскольку для решения данной проблемы используются ловушки (hooks) системы Subversion. Напомним, что ловушка – это сценарий, который выполняется в качестве реакции на некоторое событие. С их помощью можно легко отменить изменения, случайно сделанные в отмеченной тегом ветви. кроме этого, можно использовать уже упоминавшийся ранее модуль mod_authz_svn.

И вот оно, долгожданное окончание! C’est tout. Je suis un sandwich! я надеюсь, что этого краткого введения хватит не только для поддержания своего собственного сервера, но и для полноценного участия в других проектах. Если этот проект будет успешным, вам непременно придется объединять изменения и выполнять прочие описанные здесь операции, двигая вперед весь цикл разработки.


Персональные инструменты
купить
подписаться
Яндекс.Метрика