LXF71:Subversion

Материал из Linuxformat.

Перейти к: навигация, поиск
Subversion

Содержание

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

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

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

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

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

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

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

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

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

Пузырение

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

Это напоминает жесткую ссылку в терминологии Linux. Жесткая ссылка выглядит и ведет себя как обычный файл, но является лишь указателем на расположение файла на диске. По сути, имена файлов тоже являются жесткими ссылками, поскольку они не содержат никаких данных – только имя и указатель.

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

Для сравнения: в случае «ветвящегося» репозитария, CVS приходится открывать каждый файл в каталоге.

История Subversion
История 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 – сЛивАем одну ветвЬ с друГой

Код в дереве разработки наследуется каждой последовательной версией[1] оригинальная версия (1.0).[2] исправления для оригинальной версии (1.1).[3] Функции, запланированные для следующей версии (2.0).
Код в дереве разработки наследуется каждой последовательной версией
[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». В этот каталог необходимо импортировать весь сторонний проект целиком. когда выходит новая версия данного продукта, необходимо применять все изменения к текущей рабочей версии, чтобы ваши собственные правки не потерялись. После этого можно зафиксировать изменения в репозитории с тем, чтобы другие разработчики получили возможность использовать более новую версию стороннего приложения.

игры с тегами

нАш совет
структурируйте репозитарий

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

Если в одном репозитарии разрабатываются разные приложения, разумно завести для них отдельные каталоге верхнего уровня. Подумайте, как будет происходить управление ветвями и тегами. большинство проектов используют каталог «trunk» в качестве основного дерева разработки, а затем создает теги и ветви на одном уровне с ним. Это, конечно, не единственный способ – все зависит только от вас.

Для эффективного использования ветви стороннего поставщика необходимо быть уверенным, что она не может быть изменена. В терминах системы контроля версий это известно как «теггинг» (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! я надеюсь, что этого краткого введения хватит не только для поддержания своего собственного сервера, но и для полноценного участия в других проектах. Если этот проект будет успешным, вам непременно придется объединять изменения и выполнять прочие описанные здесь операции, двигая вперед весь цикл разработки.

удАЛенный доступ К проеКту с помоЩЬю SVNSERVE
после запуска svnserve с сервером можно будет работать из Konqueror.
после запуска svnserve с сервером можно будет работать из Konqueror.

В первом руководстве данной серии было показано, как использовать модуль Apache для обеспечения удаленного доступа. Но мы также можем использовать для этих целей протокол svn://. Серверное приложение, ответственное за предоставление такой возможности, называется svnserve и является частью стандартной установки Subversion. По умолчанию оно не используется, поскольку предназначается преимущественно для решения небольших, нетребовательных задач, но в этом случае может оказаться стоящей альтернативой Apache.

Запустить сервер очень просто. Введите команду с парой параметров (режимом работы и путем к репозитарию):

svnserve -d -r path_to_repository

Это запустит сервер в режиме демона (альтернативой является использование Internet Daemon, известного также как inetd). Путь к репозиторию указывается опцией -r. После запуска сервера вы можете сразу же получить к нему доступ по протоколу svn:

svn co svn://localhost

По умолчанию, svnserve предоставляет анонимный доступ в режиме «read-only». Это поведение можно изменить, отредактировав файл svnserve. conf, расположенный в конфигурационном каталоге репозитария. Этот файл хорошо документирован.

разрешение и запрет анонимного доступа производится в секции [general.

Чтобы контролировать доступ на уровне отдельных пользователей, включите эту возможность в поле Auth-access, укажите в password-db путь к файлу с паролями и создайте этот файл. Например:

svnserve.conf:
[general]
anon-access = none
auth-access = write
password-db = passwd
passwd:
[users]
graham = grahampassword

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

svn co svn://graham@localhost

Недостаток описанного выше метода состоит в том, что пароли отправляются открытым текстом. Это представляет собой угрозу безопасности. Для устранения данной проблемы следует использовать вездесущий SSH, чтобы защитить соединение между клиентом и сервером. Все, что вам потребуется – это установить SSH и создать учетную запись на сервере. Sunserve запускается при подключении пользователя, так что его не обязательно постоянно держать в памяти. однако, клиенту необходимо явно указать путь к репозитарию на файловой системе сервера. Например:

svn co svn+ssh://graham@localhost/usr/share/subres
Личные инструменты
  • Купить электронную версию
  • Подписаться на бумажную версию