<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>web-dev.info &#187; Техники</title>
	<atom:link href="http://web-dev.info/category/tech/feed/" rel="self" type="application/rss+xml" />
	<link>http://web-dev.info</link>
	<description>Информация о web-разработке для web-разработчиков.</description>
	<lastBuildDate>Tue, 02 Sep 2008 19:55:08 +0000</lastBuildDate>
	
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Ветвление в Subversion</title>
		<link>http://web-dev.info/2008/02/vetvlenie-v-subversion/</link>
		<comments>http://web-dev.info/2008/02/vetvlenie-v-subversion/#comments</comments>
		<pubDate>Tue, 19 Feb 2008 21:48:59 +0000</pubDate>
		<dc:creator>wd</dc:creator>
				<category><![CDATA[Техники]]></category>
		<category><![CDATA[branch]]></category>
		<category><![CDATA[merge]]></category>
		<category><![CDATA[subversion]]></category>
		<category><![CDATA[svn]]></category>
		<category><![CDATA[switch]]></category>
		<category><![CDATA[tag]]></category>

		<guid isPermaLink="false">http://web-dev.info/2008/02/vetvlenie-v-subversion/</guid>
		<description><![CDATA[Рано или поздно руки любого кто однажды притронулся к SVN, дотягиваются и до одного из самых мощных инструментов этой системы&#160;&#8212;&#160;ветвления. Поразительно как кажущаяся видимая сложность этого механизма оборачивается эффективным решением многих задач, которые возникают при любой разработке.
Данная статья основывается на предыдущей, а также на мысли, что лучший способ что-либо понять&#160;&#8212;&#160;сделать это самому.
Что такое ветвление
Ветвление (branching) [...]]]></description>
			<content:encoded><![CDATA[<p>Рано или поздно руки любого кто однажды притронулся к SVN, дотягиваются и до одного из самых мощных инструментов этой системы&nbsp;&mdash;&nbsp;ветвления. Поразительно как кажущаяся видимая сложность этого механизма оборачивается эффективным решением многих задач, которые возникают при любой разработке.</p>
<p>Данная статья основывается на предыдущей, а также на мысли, что лучший способ что-либо понять&nbsp;&mdash;&nbsp;сделать это самому.</p>
<h3 class="floatBar">Что такое ветвление</h3>
<p>Ветвление (branching) SVN&nbsp;&mdash;&nbsp;это именно то, что стоит за этим словом: создание ветвей. Ничем большим или меньшим это понятие не обладает.</p>
<p>То чем мы занимались до этого (см. статью &laquo;<a href="/">Введение в Subversion</a>&raquo;), было движением по единственной координате&nbsp;&mdash;&nbsp;времени. Однако представьте себе некий проект, в котором одновременно идет работа по многим направлениям разом, но в неком одном общем. Например, это может быть разработка &laquo;ПрограммаХ&raquo;, когда один отдел работает над известными ошибками, другой занимается разработкой плагинов, а третий работает по главному вектору разработки. Вся работа, проделываемая ими, сказывается на разнице &laquo;ПрограммаХ&raquo; от самой себя, например, в какой-то момент времени в основной версии программы содержится некая ошибка, в то время как в версии отдела по борьбе с ошибками ее уже нет.</p>
<h6>краткий итог:</h6>
<p class="notice">Чтобы обеспечить удобную работу различных разработчиков в рамках одного хранилища, дать им эффективный инструмент совмещения изменений и существует ветвление.</p>
<h3 class="floatBar">Зачем нужны ветки</h3>
<p>Представьте себе, что вам поручили оптимизировать схему подключения к основной программе плагинов. Или другой случай&nbsp;&mdash;&nbsp;в вашей среде разработки принято делать технический релиз в субботу вечером, чтобы группа по работе над качеством могла приступить к своему делу в понедельник. Как бы то ни было, из-за того, что потребуется внести много мешающих основной линии разработки изменений, самое эффективное решение&nbsp;&mdash;&nbsp;создание отдельной ветки, в то время как в основной не прекращает кипеть работа по своим графикам. Суть в примерах только в том, что они порождают различные &laquo;типы&raquo; веток. Таких несколько:</p>
<ul>
<li>Функциональные ветки;</li>
<li>Ветки релизов;</li>
<li>Метки.</li>
</ul>
<h6>это принципиально:</h6>
<p class="notice">Тип ветки&nbsp;&mdash;&nbsp;условное понятие. С точки зрения SVN любая ветка&nbsp;&mdash;&nbsp;это обычная директория в хранилище. То, что делает эту директорию тем или иным типом ветки находится в вашем ее восприятии. Это порой путает, но является исключительно простым по сути, надо только запомнить.</p>
<p>Именно наличие нескольких типов веток и объясняют странную на первый взгляд структуру хранилища по умолчанию:</p>
<p class="image"><img src="/wp-content/uploads/2008/02/structdefault.png" width="300" height="77" alt="Структура хранилища по умолчанию" /></p>
<p>Если ветками релизов и основной линией разработки все ясно, то в тени остались ветки функциональные и метки. Разница в них только во времени существования&nbsp;&mdash;&nbsp;тогда как метка может существовать сколь угодно долго, функциональная ветка вскоре по окончанию работы в ней удаляется.</p>
<h3 class="floatBar indent">Функциональные ветки</h3>
<p>Функциональная ветка создается по мере необходимости произвести некий набор изменений, который или прилично растянут по времени, или до окончательной реализации вступает в конфликт с остальными ведущимися изменениями&nbsp;&mdash;&nbsp;первый пример из начала этой главы.</p>
<h3 class="floatBar indent">Метки</h3>
<p>Может возникнуть вопрос о причине вынесения меток в отдельную директорию. Дело в том, что обычно это просто ссылка на ту или иную правку какой-либо ветки. Почему ссылка? Вспомните, <cite class="footNote" post="vvedenie-v-subversion" place="1">что говорилось о &laquo;дельте данных&raquo;</cite> в предыдущей статье. Точно такая же схема используется и при создании ветки, а в случае метки&nbsp;&mdash;&nbsp;копии ветки. Т.к. при создании метки ничего нового не появляется &laquo;дельта&raquo; по сути равна нулю и создаются просто ссылки на объекты ветки из которых создается метка. Таким образом, метки уменьшают многословность и неопределенность вида &laquo;ветка <span class="filePath">branches/version_3.14@364</span>&raquo; сводя ее к примерно следующему <span class="filePath">&laquo;tags/october&raquo;</span>&nbsp;&mdash;&nbsp;октябрьский релиз. Данные при этом не копируются, хранилище не растет вширь, навигация по множеству релизов упрощается. Совокупность меток, релизов, а при необходимости и функциональных веток, помогает организовать работу для решения задачи из второго примера в начале этой главы.</p>
<h6>краткий итог:</h6>
<p class="notice">Ветки&nbsp;&mdash;&nbsp;простые директории. То, что заставляет директории быть ветками различного типа, кроется в нашем их восприятии. Однако именно это восприятие и дает нам возможность решать широкий круг задач, будь то борьба с ошибками или предоставление клиентам регулярных релизов. Мы помогаем сами себе, а ветки&nbsp;&mdash;&nbsp;лишь инструмент.</p>
<h3 class="floatBar">Использование веток</h3>
<p>Разберемся с ветвлением на примере движка блога <a href="http://www.wordpress.org">WordPress</a>, сопровождая процесс знакомства временными диаграммами правок хранилища и иллюстрациями изменяющейся файловой структуры проекта.</p>
<p>Пусть нашей целью будет обновление WordPress v2.2.3 на v2.3.0. Также предположим, что в нашем распоряжении имеется хранилище, расположенное по адресу <span class="filePath">http://127.0.0.1/svn/web-dev</span> причем со структурой директорий как это рассматривалось выше. Главная ветка разработки с номером правки 35 содержит WordPress v2.2.3.</p>
<h6>уступка реальности:</h6>
<p class="notice">для тех, кто имеет дело с WordPress не секрет, что переход на v2.3.0 сопряжен также и с изменением БД ввиду введения в понятие движка меток-тегов. Также не во всех случаях обновление возможно простым &laquo;копированием поверх&raquo;. Для упрощения примера опустим эти тонкости. Вопрос синхронного закрепления в хранилище, как файлов, так и содержимого БД&nbsp;&mdash;&nbsp;предмет дальнейшей статьи &laquo;smarty commit&raquo;.</p>
<p>Таким образом, начальная картина хранилища и ее временная диаграмма будут иметь вид:</p>
<p class="image"><img src="/wp-content/uploads/2008/02/structwebdev.png" width="515" height="206" alt="Начальное состояние хранилища" /></p>
<p>Каковы будут действия для выполнения поставленной задачи:</p>
<ol>
<li>Создадим метку <span class="filePath">tags/v223</span> для текущего состояния <span class="filePath">trunk</span>&nbsp;&mdash;&nbsp;по сути именованный backup;</li>
<li>Создадим ветку <span class="filePath">branches/v230</span> на основе <span class="filePath">trunk</span>&nbsp;&mdash;&nbsp;поле деятельности, в котором и будет происходить файловые операции по обновлению WordPress;</li>
<li>Выполним все операции, требующиеся для обновления;</li>
<li>Сольем <span class="filePath">trunk</span> и <span class="filePath">branches/v230</span> чтобы в будущем вести в <span class="filePath">trunk</span> работу над v2.3.0.</li>
</ol>
<h3 class="floatBar indent">Создание</h3>
<p>Создание ветки осуществляется обычным копированием того, что будет ответвлено (обычно это <span class="filePath">trunk</span>) в ту директорию хранилища, которая соответствует типу создаваемой ветки.</p>
<h6>чтобы никто не ошибся:</h6>
<p class="notice">Перед тем как создавать ветки закрепите в хранилище все свои изменения, чтобы их потом не пришлось лишний раз копировать между ветвями.</p>
<p>Обратимся к нашему примеру, где для начала необходимо создать метку. Откройте хранилище <span class="filePath">http://127.0.0.1/svn/web-dev</span> посредством пункта контекстного меню <span class="contextMenu">TortoiseSVN&#8594;Repo-browser</span> на любой директории любого локального диска. Выделите директорию <span class="filePath">trunk</span> и для команды контекстного меню <span class="contextMenu">Copy to…</span> задайте адрес <span class="filePath">http://127.0.0.1/svn/web-dev/tags/v223</span>. Копирование произойдет очень быстро т.к., по сути, никакие данные не копируются, о чем уже говорилось выше. Ветка успешно создана, а о том, что это метка говорит нам только ее месторасположение.</p>
<h6>на заметку:</h6>
<p class="notice">При каждом создании ветки создается новая правка, именно поэтому в нашем примере номер правки с которой метка начинает жить самостоятельно&nbsp;&mdash;&nbsp;36.</p>
<p>Для того чтобы выполнить второй пункт нашего алгоритма повторите действия по созданию ветки (сначала, если вы поспешили закрыть браузер хранилища), но конечной целью укажите <span class="filePath">branches/v230</span>.</p>
<h6>можно иначе:</h6>
<p class="notice">клиент TortoiseSVN предоставляет альтернативный способ ветвления посредством команды <span class="contextMenu">TortoiseSVN&#8594;Branch/Tag…</span> Смысл у нее тот же самый, все изменения также производятся на стороне хранилища без передачи данных клиенту, и команда, по сути, является просто быстрым способом создания ветки без обозревания хранилища.</p>
<p>Мы добились некоторых результатов, которые можно было бы отразить следующим образом:</p>
<p class="image"><img src="/wp-content/uploads/2008/02/structwebdev_branchescreate.png" width="515" height="206" alt="Состояние хранилища после создания веток" /></p>
<h6>краткий итог:</h6>
<p class="notice">Ветка&nbsp;&mdash;&nbsp;копия чего-либо. Но технически копия &laquo;легкая&raquo;. Это означает, что при ее создании создается новая правка, все объекты которой указывают (ссылаются) на объекты предыдущей правки. Настоящее копирование произойдет только при изменении чего-либо в ветке. Все это напоминает обычное закрепление изменений и по сути таковым и является, с той лишь разницей, что добавляется дополнительная информация об истории.</p>
<h3 class="floatBar indent">Изменение</h3>
<p>Подкупающей простотой в ветках является заложенная в них очевидность: создание&nbsp;&mdash;&nbsp;копирование, изменение&nbsp;&mdash;&nbsp;работа как с обычной рабочей копией, об удалении и говорить нечего.</p>
<p>Теперь, когда у нас есть новая ветка <span class="filePath">branches/v230</span> мы можем поступить по-разному:</p>
<ol>
<li>Сделать <cite class="footNote" post="vvedenie-v-subversion" place="2">checkout</cite> ее содержимого в какую-то директорию и начать с ней работать;</li>
<li>Переключить нашу, уже существующую рабочую копию, которая указывает на <span class="filePath">trunk</span> так, чтобы она стала отражать содержимое <span class="filePath">branches/v230</span>;</li>
<li>Скопировать рабочую копию <span class="filePath">trunk</span> в какую-нибудь директорию и поступить с ней как это описано в предыдущем пункте.</li>
</ol>
<p>Первый способ в большинстве случаев будет удобен пользователям <a href="http://denwer.ru">denwer</a> ввиду возможности автосоздания виртуальных хостов&nbsp;&mdash;&nbsp;очень удобно произвести выгрузку ветки в отдельную директорию в home комплекса, перезагрузить его и работать в отдельной ветке с возможностью всегда изменить и копию соответствующую <span class="filePath">trunk</span>.</p>
<h6>чтобы никто не забыл:</h6>
<p class="notice">Мы исходим из web-ориентированности повествования. У нас тут всякие Apache и прочие www.</p>
<p>Третий вариант является частным случаем второго, который, в свою очередь, будет работать максимально эффективно при следующих условиях:</p>
<ul>
<li>Нет необходимости работать одновременно в нескольких рабочих копиях разных ветвей;</li>
<li>Хранилище расположено удаленно;</li>
<li>Переключение предполагается произвести между <span class="filePath">trunk</span> и только что созданной на ее основе ветки.</li>
</ul>
<p>Первый пункт обуславливает меньшее количество телодвижений&nbsp;&mdash;&nbsp;не надо ничего создавать, выгружать, конфигурировать, перезагружать (если вы используете не denwer) и прочее. Последний пункт экономит наш трафик при условии выполнении второго пункта и просто время, если это не так. Дело во все той же &laquo;дельте&raquo;&nbsp;&mdash;&nbsp;при создании рабочей копии мы передали бы некоторую часть хранилища полностью, в то время как при переключении&nbsp;&mdash;&nbsp;только разницу, которая в этом частном случае теоретически равна нулю.</p>
<h6>о вечном:</h6>
<p class="notice">В теории все замечательно, однако на практике немного информации все же передается, но по сравнению с checkout ее объем пренебрежительно мал.</p>
<p>Так как в способе первом ничего интересного нет, попытаемся освоить другой метод. Освоение будет заключаться в выполнении над рабочей копией trunk команды <span class="contextMenu">TortoiseSVN&#8594;Switch…</span> с указанием того на что мы будем переключаться <span class="filePath">branches/v230</span>. После завершения операции рабочая копия будет представлять собой содержимое этой самой ветки, <span class="command">update</span>, <span class="command">commit</span> и некоторые прочие операции по умолчанию будут работать уже не с <span class="filePath">trunk</span>, а с <span class="filePath">branches/v230</span>. В общем, произошло нечто ожидаемое&nbsp;&mdash;&nbsp;переключение на другую ветку разработки без утомительных выгрузок в новую рабочую копию и прочего. Теперь можно работать, как это делалось прежде. Для нашего примера это все необходимые действия по обновлению WordPress&nbsp;&mdash;&nbsp;копирование поверх обновленных файлов движка, проверке все ли в порядке, доводка напильником и прочими подручными средствами. Естественно, что в ходе этих действий можно и нужно использовать всю мощь SVN: <span class="command">update</span>, <span class="command">commit</span>, <span class="command">revert</span> и прочее.</p>
<h6>если подумать:</h6>
<p class="notice">Команды <span class="command">switch</span> и <span class="command">update</span> очень похожи&nbsp;&mdash;&nbsp;обе изменяют рабочую копию на основе анализа хранилища. На самом деле <span class="command">update</span> является частным случаем <span class="command">switch</span>, которая может сравнивать и изменять текущую рабочую копию с различными ветками в хранилище. Это более гибкий и мощный инструмент. Оправданием существования <span class="command">update</span> может послужить то, что это менее гибкий и мощный инструмент.</p>
<p>Для того чтобы продолжить линию нашего примера представим, что в ходе изменений было создано 7 правок и мы остановились на правке №44:</p>
<p class="image"><img src="/wp-content/uploads/2008/02/structwebdev_branchesedit.png" width="515" height="206" alt="Состояние хранилища после изменения ветки" /></p>
<h3 class="floatBar indent">Копирование изменений между ветками</h3>
<p>Очень распространенный вопрос, который решается в ходе интенсивного использования ветвления&nbsp;&mdash;&nbsp;копирование изменений между ветками.</p>
<p>То как часто это следует делать, необходимо ли делать вовсе и прочие вопросы, связанные с этой операцией решаются исходя из типа ветки, внутренней политики разработки и чувства меры. Например, самый распространенный случай, когда имеется главная ветка разработки и несколько функциональных ветвей. Тогда если в ветвях делаются изменения по каким-то причинам выходящие за рамки целей создания этих ветвей, их необходимо копировать в главную ветку разработки как можно скорее. Примером такого рода изменений может служить обнаруженная и исправленная ошибка, в то время как ветки не предназначались для их отлова и исправления. Как видно существует довольно много &laquo;если&raquo; и вопрос своевременности копирования изменений из ветки в ветку по праву можно считать тонким.</p>
<h6>из чувства справедливости:</h6>
<p class="notice">Тонким, но не сложным. Руководствуйтесь логикой, создавайте ветки, когда это покажется вам необходимым&nbsp;&mdash;&nbsp;довольно рутинная операция копирования изменений быстро отучит вас создавать ветки, когда в этом нет надобности.</p>
<h3 class="floatBar indent2">Копирование части изменений</h3>
<p>Пусть в ходе работ по обновлению было выяснено, что в обеих ветках (<span class="filePath">trunk</span> и <span class="filePath">branches/v230</span>) в файле <span class="filePath">www/wp-config.php</span>, который не был перезаписан обновлением, была замечена ошибка. Таким образом, ошибка содержится в обеих ветках. Предположим, что мы справили ее в текущей на данный момент <span class="filePath">branches/v230</span>, и закрепили исправление в правке №44. Задача состоит в копировании исправления в <span class="filePath">tags/v223</span>.</p>
<p>Предыдущая мысль&nbsp;&mdash;&nbsp;типичный пример засады, которые встречаются на пути не только начинающих пользователей SVN. Ошибка заключается в предании забвению факта, что все правки любой из веток&nbsp;&mdash;&nbsp;фотографии, слепки всего дерева хранилища на какой-то момент времени, а значит, мы не можем изменить уже закрепленные правки&nbsp;&mdash;&nbsp;<span class="filePath">tags/v223</span> &laquo;потеряна&raquo; для нас. К тому же эта метка, как и другие ветки, живет отдельно и изменения в ней не будут видны, например пользователям <span class="filePath">trunk</span>.</p>
<p>Следует поступить по следующей схеме:</p>
<ul>
<li>Портировать изменения в самую общую ветвь&nbsp;&mdash;&nbsp;<span class="filePath">trunk</span>, обязательно указав в комментарии, что это порт и описав его суть, чтобы для людей пользующихся одновременно <span class="filePath">trunk</span> и <span class="filePath">branches/v230</span> не поставил в тупик неожиданный могущий возникнуть конфликт;</li>
<li>Удалить <span class="filePath">tags/v223</span> или оставить ее на месте;</li>
<li>В зависимости от выбранного действия над <span class="filePath">tags/v223</span> нужно или портировать в нее изменения из <span class="filePath">trunk</span>, или создать на основе <span class="filePath">trunk</span> новую метку, назвав ее, например, <span class="filePath">tags/v223_patched1</span> с комментарием о сути патча.</li>
</ul>
<p>Теперь у нас полный порядок в логике и хоть сказанное выше звучит устрашающе, но на практике все очень просто.</p>
<p>Портирование изменений осуществляет консольная команда <span class="command">svn merge</span> или ее представитель <span class="contextMenu">TortoiseSVN&#8594;Merge…</span>. Команда принимает адреса сравниваемых деревьев и рабочую копию, к которой разница между деревьями будет применена в виде локальных (!!!) изменений. Потом их можно будет закрепить или отменить.</p>
<p>Ветви, которые участвуют в портировании изменений, дадут адреса деревьев, а направление ответит на вопрос к рабочей копии какой ветки применять разницу. В нашем примере from&nbsp;&mdash;&nbsp;<span class="filePath">http://127.0.0.1/svn/branches/v230/www/wp-config.php</span>, to&nbsp;&mdash;&nbsp;также <span class="filePath">http://127.0.0.1/svn/branches/v230/www/wp-config.php</span>, а рабочая копия для ветки <span class="filePath">trunk</span>.</p>
<h6>обратите внимание:</h6>
<p class="notice">В качестве деревьев выступает один единственный файл, частный случай обуславливаемый названием и смыслом текущей главы.</p>
<p>Адреса деревьев будут не полными без указания номеров правок. Это уточняющая координата. Обратимся к логике: мы условились, что исправления, которые мы должны портировать, закреплены в правке №44, а значит, в правке №43 их не было. Следует вывод, что диапазон номеров правок будет 43-44. Это все необходимые данные.</p>
<h6>чтобы не ошибиться:</h6>
<p class="notice">Рекомендуется запускать тестовое слияние посредством кнопки &laquo;dry run&raquo; перед тем как запустить его по-настоящему.</p>
<p>Теперь исправление ошибки находится в ветке <span class="filePath">trunk</span> под правкой №45, но оно никак не отражено в метке <span class="filePath">tags/v223</span>. Логично хранить все изменения в одном месте, значит, ничего удалять не будем, а портируем только что портированные в <span class="filePath">trunk</span> изменения и туда. В этом случае адрес дерева from будет таким же, как и в предыдущем портировании, to&nbsp;&mdash;&nbsp;аналогично. Диапазон номеров правок также останется без изменений. Изменится лишь рабочая копия, которая должна будет отражать состояние <span class="filePath">tags/v223</span>. В этом нам поможет уже известная нам <span class="contextMenu">TortoiseSVN&#8594;Switch…</span>. Теперь все логически верно: все состояния, на которые можно откатиться при неудачном обновлении WordPress до v2.3.0, у нас находятся в <span class="filePath">tags/v223</span>, причем с возможностью выбора момента отката&nbsp;&mdash;&nbsp;до исправления ошибки (правка №36) и после ее портирования (правка №46).</p>
<p>Все изменения, произошедшие с хранилищем, можно отобразить следующей диаграммой, где жирная линия означает портирование изменение с последующим закреплением:</p>
<p class="image"><img src="/wp-content/uploads/2008/02/structwebdev_branchesmerge.png" width="515" height="206" alt="Состояние хранилища после портирования части изменений" /></p>
<p>Обратите внимание на жирную линию со штрихом. Это альтернативный способ портирования изменений в <span class="filePath">tags/v223</span> достигаемый при параметрах from и to равными <span class="filePath">http://127.0.0.1/svn/trunk/www/wp-config.php</span>, с диапазоном правок 35-45. Аналогичный результат даст команда и для правок 35-44 при неизменном адресе сравниваемых деревьев. Это обусловлено тождественностью правок 44 и 45. Как видите, результата можно достигнуть множеством путей. Однакое необходимо заметить, что эти способы работают только в конкретном случае примера, когда между правками 35 и 37 не было изменений <span class="filePath">trunk</span>, что помешало бы использованию альтернативных способов, но об этом ниже.</p>
<h6>краткий итог:</h6>
<p class="notice">При слиянии необходимо всегда руководствоваться логикой и запомнить, что merge выполняется для двух деревьев хранилища заданных адресами и диапазоном правок, а разница всегда применяется к рабочей копии или части ее, если команда была выбрана не для всей копии. Никакие изменения в хранилище при этом не вносятся&nbsp;&mdash;&nbsp;вам нужно будет сделать это самостоятельно позже обычным commit, если потребуется. Сломать что-либо слиянием очень сложно, хотя запутаться есть где. Затем и логика.</p>
<h3 class="floatBar indent2">Слияние веток полностью</h3>
<p>Мы только что закончили все операции по обновлению WordPress до v2.3.0 и остались довольными качеством работы. Время за слиянием функциональной ветки <span class="filePath">branches/v230</span> в основную линию разработки <span class="filePath">trunk</span>.</p>
<p>Опять прибегаем к логике: необходимо сравнить <span class="filePath">trunk@35</span> и <span class="filePath">branches/v230@44</span> чтобы получить разницу которую надо применить к <span class="filePath">trunk</span>. Для нашего конкретного случая это сработает, все верно. Но это ошибочный путь, не думайте в таком ключе. Представьте себе, что кто-то из ваших товарищей все это время работал над <span class="filePath">trunk</span> и вносил туда изменения. Тогда при попытке вычислить разницу между <span class="filePath">trunk@35</span> и <span class="filePath">branches/v230@44</span> вы засечете и его изменения, которые, пересекаясь с вашими, могут дать непредсказуемые результаты. Гораздо легче и безопаснее сравнивать <span class="filePath">branches/v230@37</span> и <span class="filePath">branches/v230@44</span>, что оправдано и логически: взять все изменения в ветке <span class="filePath">branches/v230</span> с момента ее создания до последней правки.</p>
<p>Самое &laquo;сложное&raquo;&nbsp;&mdash;&nbsp;определить начальную правку ветки. Делается это посредством просмотра лога ветки при выбранной опции &laquo;stop on copy/rename&raquo;, что в свою очередь достигается через контекстное меню нужной ветки в repo-browser.</p>
<p>Остальные моменты слияния ничем не отличаются от уже делавшихся нами в предыдущей части этой статьи.</p>
<h6>для внимательных:</h6>
<p class="notice">Можно заметить, что для trunk часть изменений применяется дважды, что объясняется неспособностью автора придумать более элегантный пример. Однако ничего страшного в этом двойном применении нет т. к. второго, по сути, не произойдет&nbsp;&mdash;&nbsp;в этом месте &laquo;дельта&raquo; изменений и рабочей копии будет равна нулю.</p>
<p>Теперь ветку <span class="filePath">branches/v230</span> можно удалить или оставить и создать метку <span class="filePath">tags/v230</span>, что уже не является сложной задачей.</p>
<h3 class="floatBar">Подводные камни и нюансы</h3>
<ol>
<li>Ветки&nbsp;&mdash;&nbsp;простые копии;</li>
<li>Можно переключать с ветки на ветку не только всю рабочую копию, но и один единственный файл или директорию. Все, что необходимо&nbsp;&mdash;&nbsp;знать, что только с ними будет вестись работа. Также имеется возможность переключаться и на любую правку ветки;</li>
<li>Обязательно комментируйте портирование изменений вплоть до номеров правок&nbsp;&mdash;&nbsp;это поможет вам в ряде случаев. Например, предположим, что <span class="filePath">branches/v230</span> не была удалена после полного слияния с <span class="filePath">trunk</span> и в ней продолжилась работа, которая привела к появлению правок 48-55. Пусть необходимо также портировать эти изменения в <span class="filePath">trunk</span>. В этом случае по комментариям в логе хранилища легче всего определить, что первая волна изменений охватывала правки 37-44 и была закреплена в правке 47. Значит, вторая волна должна охватывать правки 48-55 и никак не 37-50, что приведет к захвату изменений первой волны дважды;</li>
<li>Никто не обязывает вас делать хранилище со структурой, о которой говорилось в этой статье. Организация хранилища – личное дело каждого. Однако стоит помнить, что вещи проверенные временем заслуживают внимания;</li>
<li>Совсем не обязательно иметь на локальной машине такую же структуру, как и у хранилища. Может случиться, что у вас на компьютере в один момент времени будет лишь одна рабочая копия, расположенная в неком DocumentRoot некоего сайта и вы будете интенсивно использовать svn switch для доступа к иным местам хранилища. Экономьте свое место на диске и время.</li>
</ol>
<h3 class="floatBar">Заключение</h3>
<p>Ветки&nbsp;&mdash;&nbsp;это просто. Все, что необходимо в работе с ними&nbsp;&mdash;&nbsp;логика и четкое понимание происходящего. Ну и практика, конечно. Не опасайтесь их, просто используйте.</p>
]]></content:encoded>
			<wfw:commentRss>http://web-dev.info/2008/02/vetvlenie-v-subversion/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Введение в Subversion</title>
		<link>http://web-dev.info/2008/02/vvedenie-v-subversion/</link>
		<comments>http://web-dev.info/2008/02/vvedenie-v-subversion/#comments</comments>
		<pubDate>Fri, 15 Feb 2008 04:26:38 +0000</pubDate>
		<dc:creator>wd</dc:creator>
				<category><![CDATA[Техники]]></category>
		<category><![CDATA[beginning]]></category>
		<category><![CDATA[subversion]]></category>
		<category><![CDATA[svn]]></category>

		<guid isPermaLink="false">http://web-dev.info/2008/02/vvedenie_v_subversion/</guid>
		<description><![CDATA[Системы контроля версий. Согласитесь, звучит. А чем дольше пользоваться одной из них, тем все более соблазнительные для искушенных умов рисуются перспективы. Начнем.
В этой статье мы поговорим, установим и попытаемся использовать в своих корыстных целях одну из разновидностей СКВ&#160;&#8212; Subversion. Почему так? Subversion очень популярна среди разработчиков, предоставляется многими хостерами, а возможная тесная интеграция с web-сервером [...]]]></description>
			<content:encoded><![CDATA[<p>Системы контроля версий. Согласитесь, звучит. А чем дольше пользоваться одной из них, тем все более соблазнительные для искушенных умов рисуются перспективы. Начнем.</p>
<p>В этой статье мы поговорим, установим и попытаемся использовать в своих корыстных целях одну из разновидностей <acronym title="Система контроля версий">СКВ</acronym>&nbsp;&mdash; Subversion. Почему так? Subversion очень популярна среди разработчиков, предоставляется многими хостерами, а возможная тесная интеграция с web-сервером Apache только добавляет ей очков. Чем-то Subversion походит в этом отношении на PHP — также много отличных альтернатив, но…</p>
<h6>на заметку</h6>
<p class="notice">Примечание: не стоит думать, что Subversion это «только под web и для web». <a href="#h33">Соответствующим образом настроенная</a> эта СКВ подойдет всем кто к ней готов.</p>
<h3 class="floatBar">Причины использования</h3>
<p>Подавляющее большинство разработчиков приходят к СКВ, когда им перестает хватать резервного копирования проекта в виде стека директорий (оставим в стороне случай, когда использование СКВ — требование «свыше», мы все не любим насилие). Кто-то пытается подвести под наименование таких директорий некую систему (к примеру, в виде дат), кто-то хранит описание копий в файлах, кто-то находит решение в соответствующем ПО вроде <a href="http://nncron.ru/index_ru.shtml#nnbackup">nnbackup</a>. Однако приходит определенный момент и мысли тянутся к более эффективным решениям&nbsp;&mdash; СКВ. Установив одну из них, можно не беспокоиться о создании резервных копий данных — все будет сделано автоматически. Более того, вскоре вы даже забудете о таком явлении как резервирование, вы будете пользоваться широкими возможностями СКВ, не замечая, что создается один backup за другим. И это хорошо.</p>
<p>Также одной из самых распространенных причин применения СКВ может служить командная разработка. В таком случае контроль монопольного редактирования, отслеживание изменений и их слияние являются настоящим кошмаром, если не использовать СКВ.</p>
<h6>малый итог</h6>
<p class="notice">Использование СКВ оправдано как в случае одиночного разработчика, так и для ситуации когда их несколько.</p>
<h3 class="floatBar">Общая теория</h3>
<p>Для начала необходимо усвоить базовые понятия и термины, единые для большинства различных СКВ. Их не много:</p>
<ul>
<li>repository (хранилище) — место где СКВ хранит данные, информацию об их изменениях и другую системную информацию;</li>
<li><!-- footnote2 -->checkout — извлечение части или всего содержимого хранилища и создание на их основе рабочей копии<!-- /footnote2 -->;</li>
<li>working copy (рабочая копия) — слепок хранилища расположенный на локальной машине. Именно рабочая копия подвергается изменениям перед тем как данные будут занесены в хранилище. Рабочая копия содержит также данные о версиях содержащихся в ней файлов. Именно их наличие и определяет, что директория и есть рабочая копия;</li>
<li>revision (версия, номер правки, правка) — каждый объект в понятиях СКВ имеет версию, номер которой назначается автоматически, если документ изменялся;</li>
<li>commit (закрепление изменений) — копирование изменений из рабочей копии в хранилище. При этом создается новая правка;</li>
<li>update (обновление) — операция получения данных из хранилища, если в рабочей копии они устарели;</li>
<li>merge (слияние) — объединение независимых изменений над одним файлом. Такое происходит, когда в разных правках менялся один и тот же файл.</li>
</ul>
<p>Также потребуется рассмотреть самые известные реализации СКВ, чтобы знать об их возможностях и недостатках:</p>
<ul>
<li>CVS (Concurrent Version System) — система, своими корнями уходящая в далекие 80-е, очень популярна и сейчас. Обладает почти всеми необходимыми инструментами для контроля изменений, сравнения, слияния и устранения конфликтов. Существенным минусом данной реализации является отсутствие контроля версий директорий;</li>
<li>VSS (MS Visual SourceSafe) — реализация СКВ софтверного гиганта, ориентированная на индивидуальных разработчиков или небольшие их группы. Доступна посредством установки Visual Studio. Имеет старшего брата Visual Studio Team Foundation Server. К недостаткам относится Win32-ориентация;</li>
<li>SVN (Subversion) — система контроля версий пришедшая на смену CVS и призванная устранить все ее недостатки. <!-- footnote3-->Имеет возможность интегрирования с web-сервером Apache, отслеживает версии не только файлов, но и директорий. За каждым объектом в хранилище можно закрепить любую информацию в так называемых свойствах и она также попадет под контроль версий.<!-- /footnote3--></li>
</ul>
<p>Дополнительную информацию о приведенных и других реализациях СКВ можно найти, запросив Google.</p>
<h6>малый итог</h6>
<p class="notice">Даже на первый взгляд видна исключительная аппетитность SVN. Возможно, дело в предвзятом изложении материала, но вероятнее всего, что это законное положение лидера.</p>
<h3 class="floatBar" title="Subversion">Subversion</h3>
<p>Будем последовательны — разовьем тему SVN.</p>
<p>Главное преимущество SVN — интеграция с Apache. Это настоящий подарок web-разработчикам — один привычный сервер, известные подходы в обеспечении безопасности, авторизованного доступа и прочего.</p>
<h6>замечание</h6>
<p class="notice">CVS также имеет модуль позволяющий использовать ее с Apache, но он слабо распространен и последний раз обновлялся в далеком 2003 году.</p>
<p>Свобода на пространстве файловых операций: файлы и директории как в рабочей копии, так и в хранилище можно свободно копировать, перемещать, удалять — никаких накладок это не вызовет.</p>
<p><!-- footnote1 -->SVN всегда передает в хранилище «дельту»&nbsp;&mdash; только измененные данные. Не важно, бинарный ли это файл или любимые цитаты с башорга, но на сервер отправятся только новые данные.<!-- /footnote1 --></p>
<p>Спокойствие за свои изменения при закреплении их в хранилище — SVN или закрепит все изменения, или не сделает этого вовсе, так что путаницы не будет.</p>
<h6>риторика</h6>
<p class="notice">Надо ли говорить, что SVN также наследует все положительные стороны своего родителя — CVS.</p>
<p>Отличным инструментом, предоставляемым SVN, является команда вычисления разницы, которая может применяться как к отдельным файлам, так и к правкам. Хотите узнать, что было изменено коллегой или левой рукой за вчерашний день? Это просто.</p>
<h6>примечание</h6>
<p class="notice">Нельзя <del>вычислить</del> <ins>отобразить</ins> разницу между двумя директориями, двумя фильмами или другими бинарными файлами. К слову, для некоторых бинарных файлов возможность сравнения все же имеется, но реализована она на уровне хака, надстройки. К файлам такого рода относятся в основном файлы офисного пакета MS Office и ограниченный набор  файлов изображений.</p>
<p>Несколько разработчиков могут редактировать один и тот же файл и если их изменения не пересекаются, то SVN даже не пикнет — оба изменения будут закреплены автоматически. Возможно, что вы об этом даже не узнаете.</p>
<p>Всегда в распоряжении возможность создания веток — самостоятельных линий разработки, начинающихся в точке ветвления и ничем не отличающихся от основной по принципам работы. Это очень удобно, когда требуется внедрить в проект некую функциональность, реализация которой потребует множества правок. Ваши действия будут мешать остальным разработчикам (или вам самим) просто тем, что какое-то продолжительное время не смогут быть завершены. По окончанию работы в ветке изменения, внесенные в проект на ее пути, можно «слить» в основную линию разработки с минимальными усилиями со стороны разработчиков.</p>
<h3 class="floatBar indent">Виды установки</h3>
<p><!-- footnote4--></p>
<p>Различают три способа установки SVN сказывающиеся на типе доступа к хранилищу:</p>
<ul>
<li>Под управлением web-сервера Apache посредством mod_dav_svn;</li>
<li>В виде самостоятельного сервиса <span class="command">svnserve</span> — небольшого демона, который для связи с клиентами использует собственный протокол;</li>
<li>Не устанавливать SVN вовсе.</li>
</ul>
<p><!-- /footnote4--></p>
<h6>важно</h6>
<p class="notice">В случае интеграции с Apache возможна установка только для Apache версии 2.x. Это связано с рядом архитектурных особенностей второй ветки сервера. Если вы используете Apache версии 1.x, можно порекомендовать установить Apache версии 2.x в виде второго web-сервера на другом порту.</p>
<p>Сравнение двух первых способов можно видеть в таблице ниже:</p>
<table class="data" width="100%">
<tr>
<th>Возможность</th>
<th>Apache + mod_dav_svn</th>
<th>svnserve</th>
</tr>
<tr>
<td>Авторизация:</td>
<td>стандартное установление личности средствами HTTP (S), сертификаты X.509, LDAP, NTLM, а также другие механизмы, доступные для использования в Apache</td>
<td>CRAM-MD5 или SSH</td>
</tr>
<tr>
<td>Хранение учетных записей:</td>
<td>внутренний файл «users»</td>
<td>внутренний файл «users» или использование существующих системных (SSH) учетных записей</td>
</tr>
<tr>
<td>Шифрование:</td>
<td>опционально через SSL</td>
<td>опционально через SSH-туннель</td>
</tr>
<tr>
<td>Логирование:</td>
<td>полное логирование каждого HTTP запроса как это настроено в Apache</td>
<td>не поддерживается</td>
</tr>
<tr>
<td>Просмотр через web:</td>
<td>ограниченная встроенная поддержка, или использование программ сторонних разработчиков, таких, как ViewVS</td>
<td>только при помощи программ сторонних разработчиков, таких, как ViewVS</td>
</tr>
<tr>
<td>Скорость:</td>
<td>более низкая</td>
<td>более высокая</td>
</tr>
<tr>
<td>Установка:</td>
<td>более сложная</td>
<td>менее сложная</td>
</tr>
</table>
<p>Оба вышеописанных варианта подразумевают, что доступ к хранилищам будет предоставляться на основе парадигмы «клиент-сервер». Это частая ситуация когда разработчиков много. Однако нередко нужно развернуть систему контроля версий без подобных сложностей. В таком случае потребуется только клиент — программа необходимая в любом случае. У подхода есть один минус — файловая система, на которой находится хранилище, должна быть локальной.</p>
<h6>краткий итог</h6>
<p class="notice">Если заниматься разработкой web-приложений под управлением Apache, то выбор очевиден — один и привычный сервер. В ином случае целесообразно использовать поставляемое с SVN <span class="command">svnserve</span>. Когда же требуется локальная реализация SVN, без доступа извне, то можно обратить внимание на третий вариант.</p>
<h3 class="floatBar indent">Настройка</h3>
<p>Так как статья носит web-ориентированный характер, мы коснемся только реализации «SVN через протокол WebDAV» под управлением сервера Apache. Этот способ даст нам следующие преимущества по сравнению с другими:</p>
<ul>
<li>Просмотр содержимого последней правки хранилища в браузере — мы все любим ссылки;</li>
<li>Передаваемые данные могут быть сжаты обычным образом с помощью mod_deflate;</li>
<li>С помощью скриптов на своем любимом языке можно оперировать данными хранилища.</li>
</ul>
<p>Условимся использовать в этой статье пути, которые используются мной в повседневности: мне удобно излагать, а вам не привыкать видеть чужие конфиги. Также «сразу» предупреждаю, что разговор будет идти на языке Windows. Извините.</p>
<p>Пусть Apache установлен у нас как это видно на рисунке ниже. Содержимое <span class="filePath">home</span> — ряд директорий, внутри которых имеется директория <span class="filePath">www</span> — DocumentRoot соответствующего виртуального хоста.</p>
<p class="image"><img src="/wp-content/uploads/2008/02/virtualhosts.gif" alt="Вид директорий с которыми мы будем иметь дело" height="260" width="201" /><br />
Вид директорий с которыми мы будем иметь дело</p>
<h6>вы заметили?</h6>
<p class="notice">Файловая организация популярного пакета <a href="http://denwer.ru">denwer</a> и используемая в данной статье, пересекаются в <span class="filePath">home</span> — функции этой директории идентичны и там, и там. Этот факт может помочь для перенесения  изложенного материала на рабочее пространство denwer.</p>
<p>Убедимся, что у нас есть, установлено и настроено все необходимое:</p>
<ul>
<li>Web-сервер Apache;</li>
<li>Модуль расширения mod_dav.so;</li>
</ul>
<p>Брать дистрибутив SVN из-за ОСзависимости лучше с <a href="http://subversion.tigris.org">сайта разработчика</a>. Установка не вызывает обычно вопросов, но есть пара нюансов:</p>
<ul>
<li>Снимите чекбокс конфигурации модулей с перезапуском Apache — мы все сделаем самостоятельно;</li>
<li>Не поддавайтесь на уговоры установщика и не редактируйте autoexec.bat. Найти смысл в этой рекомендации также сложно, как и сам файл.</li>
</ul>
<p>Ссылку на дистрибутив TortoiseSVN, визуального клиента SVN для Windows, можно найти во все том же разделе загрузок. Установка. Игнорирование предложения перезагрузиться.</p>
<p>Конфигурирование Apache. Многие используют комплект denwer, у меня своя сборка триады Apache, PHP, MySQL, есть иные варианты. Объединяет их одно — во всех случаях файл httpd.conf должен существовать. Им и займемся:</p>
<ul>
<li>Там где у вас скопление директив загрузки модулей «LoadModule» добавьте еще одну:
<pre name="code" class="html">LoadModule dav_svn_module "@SubversionDir@/Subversion/bin/mod_dav_svn.so"</pre>
</li>
<li>Убедитесь, что также активна директива загрузки модуля WebDAV, модуль существует, а его загрузка идет до загрузки dav_svn_module:
<pre name="code" class="html">LoadModule dav_module modules/mod_dav.so</pre>
</li>
<li>Там где вам это кажется уместным, но обязательно в файле httpd.conf создайте описание «директории» для SVN:
<pre name="code" class="html">&lt;Location /svn&gt;
	DAV svn
	SVNParentPath "d:/www/svn_repository"
&lt;/Location&gt;</pre>
</li>
</ul>
<p>Создаем <span class="filePath">d:\www\svn_repository</span>, перезагружаемся и пытаемся запустить Apache. В случае удачи ничто вас не побеспокоит. Если же что-то пошло не так, то следует разобраться в ошибке с помощью чтения логов и действий по обстоятельствам.</p>
<h3 class="floatBar indent">Использование</h3>
<p>Теперь, когда все необходимое установлено и работает можно вручить свой проект в надежные руки SVN.</p>
<p>Обычный процесс работы с SVN можно изобразить, как это сделано на схеме ниже, которая отражает полный цикл жизни: от создания хранилища до его использования.</p>
<p class="image"><img src="/wp-content/uploads/2008/02/scheme1.gif" alt="Схема действий при работе с SVN" height="180" width="340" /><br />
Схема действий при работе с SVN</p>
<h6>Примечание</h6>
<p class="notice">Кружочек с вложенным кружочком на схеме означает, что действие составное — может состоять из многих различных действий.</p>
<p>Разберемся со всем по порядку:</p>
<ol>
<li><a href="#svnWork1">Создание хранилища</a>;</li>
<li><a href="#svnWork2">предимпортная настройка</a>;</li>
<li><a href="#svnWork3">импорт проекта в хранилище</a>;</li>
<li><a href="#svnWork4">создание рабочей копии</a>;</li>
<li><a href="#svnWork5">редактирование рабочей копии</a>;</li>
<li><a href="#svnWork6">закрепление изменений</a> (правки);</li>
<li><a href="#svnWork7">выборка данных из хранилища</a>;</li>
<li><a href="#svnWork8">отмена изменений</a>.</li>
</ol>
<p>Для того чтобы различные действия были понятны договоримся каждый из шагов снабжать популярным объяснением которое будет основано на двух персонажах:</p>
<ul>
<li>Разработчик — человек, который выполняет работу. К такой работе сводится создание, удаление, изменение файлов составляющих некий продукт или гордость за все вместе взятое;</li>
<li>Лидер — человек, который определяет линию разработки, а также обеспечивает наличие всех необходимых в разработке вещей, например, данных.</li>
</ul>
<p>Подобная, очень упрощенная, организация процесса труда принята для повышения эффективности разработки в целом. Но представьте себе ситуацию, когда разработчик, например в ситуации с личным блогом, один. Никто не возьмет на себя роль лидера, ее придется выполнять самостоятельно. Поэтому, если какие-то действия покажутся вам странными и непонятными, попытайтесь распределить роли и все встанет на свои места.</p>
<ol>
<li> 		<a id="svnWork1">Создание хранилища</a>. Хранилище или иначе репозиторий — особое место, где SVN в собственном формате хранит все наши данные в виде правок. Директорией, где мы решили разместить хранилища, будет <span class="filePath">d:\www\svn_repository</span>, а хранилище будет называться <span class="filePath">web-dev</span>. Тогда создаем директорию <span class="filePath">d:\www\svn_repository\web-dev</span> и через контекстное меню для нее выбираем <span class="contextMenu">TortoiseSVN→Create repository here…</span> Тип репозитория должен быть FSFS. Хранилище создано и готово к работе;<br />
<h6>метафора</h6>
<p class="notice">Этот шаг можно сравнивать с примерным лидером который готовит рабочее место для разработчика наряду с созданием ftp аккаунтов и прочих подобных вещей.</p>
</li>
<li> 		<a id="svnWork2">Предимпортная настройка</a>. Этот шаг опционален и не является каноническим, однако я бы порекомендовал делать его всегда, когда его есть к чему применить. Речь пойдет о настройке рабочей копии в плане задания свойства игнорирования файлов, для которых не нужно хранить информацию о версии (версионировать). Примером таких файлов могут быть «скомпилированные» шаблоны Smarty, файлы проекта редактора PhpED, дампы баз и прочее, что по каким-то причинам расположено в рамках рабочей копии, но не нуждается в отслеживании изменений. Создайте простую копию проекта, а в оригинале удалите все то, что не считаете нужным отдать под версионирование. Пока это все;<br />
<h6>метафора</h6>
<p class="notice">Лидер уже располагает какими-то данными, но он также понимает, что не все из них нужно отдавать в хранилище даже если эти «излишки» нужны в работе. Своими действиями он готовит чистую заготовку рабочей копии без всякого мусора — базовую редакцию.</p>
</li>
<li> 		<a id="svnWork3">Импорт проекта в хранилище</a>. Здесь необходимо сообщить хранилищу базовую редакцию проекта на основе которой он будет, подобно пирамиде из правок (часто очень причудливой — подумайте о ветвлении), хранить наши изменения. Пусть это будет проект блога в котором размещена эта статья: <span class="filePath">d:\www\ApachePhpMysql\apache\home\web-dev.info\</span>. Импорт осуществляется посредством пункта контекстного меню <span class="contextMenu">TortoiseSVN→Import…</span> В качестве запрошенного URL к хранилищу укажите <span class="filePath">http://127.0.0.1/svn/web-dev/trunk</span>.<br />
<h6>для ясности</h6>
<p class="notice">Частичка <span class="filePath">svn</span> в этом пути взялась из httpd.conf, где мы указали ее в директиве <span class="command">Location</span>, с тем же успехом можно было бы написать в обоих местах <span class="filePath">my_pretty_good_svn_directory</span>. Что касается частички <span class="filePath">trunk</span>, то по ее поводу забегите <a href="#nuancePaths">немного вперед</a>, если вам интересно.</p>
<p>В зависимости от объема импортируемых данных зрелище будет более или менее впечатляющее… и длительное;</p>
<h6>метафора</h6>
<p class="notice">Лидер создает фундамент на котором силами разработчика будет строиться вся разработка. Таковым фундаментом является первая правка в хранилище — результат прошедшего импорта.</p>
</li>
<li> 		<a id="svnWork4">Создание рабочей копии</a>. Теперь самое время… удалить оригинал вашего проекта.<br />
<h6>Внимание!</h6>
<p class="notice">До тех пор пока не будете уверенно использовать SVN, всегда делайте резервирование данных проекта привычным для вас образом. В процессе обучения, чтобы начать все с чистого листа, обычно не раз удаляется хранилище — а значит и резервные копии.</p>
<p>Делается это потому, что оригинал проекта не содержит еще данных о версиях файлов, а значит, не является рабочей копией. Директорию нужно таковой сделать. Для этого и производится удаление, чтобы потом создать под этим же именем директорию, которая будет рабочей копией с точки зрения SVN и файлами, составляющими блог, с точки зрения Apache. Далее, для пустой директории <span class="filePath">web-dev.info</span> запустите команду контекстного меню <span class="contextMenu">SVN→Checkout…</span>, URL хранилища нужно взять из предыдущего шага: <span class="filePath">http://127.0.0.1/svn/web-dev/trunk</span>. Теперь, после завершения, у вас есть рабочая копия вашего хранилища, с которой можно производить любые действия, вплоть до забрасывания проекта;</p>
<h6>метафора</h6>
<p class="notice">Лидер продолжает заботиться о разработчике и делать свою работу. На этом этапе он создал собственную рабочую копию т.к. необходимо навести порядок с файлами, исключенными на этапе предимпортной настройки. Тем, что над лидером нет никого, кто сделал бы эту работу для него и обусловлена эта чехарда с удалением оригинала и созданием пустой директории.</p>
</li>
<li> 		<a id="svnWork5">Редактирование рабочей копии</a>.<br />
Тут можно дать волю фантазии, например, отбросить ее в сторону и заняться делом. Под редактированием понимается любое изменение содержимого файлов, их переименование, изменение свойств и прочее. Все эти телодвижения скажутся на рабочей копии так, что нам надо будет их сохранить, а в терминах SVN — закрепить. Давайте потратим нашу первую правку на что-нибудь полезное: второй этап настройки списка игнорируемых объектов. Мысленно вернитесь к <a href="#svnWork2">этапу предимпортной настройки</a>. По его результатам у нас имеется оригинал, ставший после последующих шагов рабочей копией и старая резервная копия. Скопируйте резервную копию поверх рабочей копии. выполните для последней команду <span class="contextMenu">TortoiseSVN→Check for modifications</span> и вы увидите все файлы, которые решили не версионировать с пометкой «non-versioned». Можно отметить их как игнорируемые, в чем <a href="#nuanceIgnoreDir">клиент предоставляет нам довольно большую свободу</a> посредством контекстного меню, вызываемом при клике правой кнопкой мыши на не версионированных объектах. Дело за вами и пусть эти изменения будут пока единственными;</p>
<h6>метафора</h6>
<p class="notice">Лидер и разработчик на данном шаге одноправны — оба вносят различного рода изменения. То, что мы лишь добавили игнорирование некоторых объектов, не говорит, что это единственное действие, которое можно производить для изменения хранилища. Например, разработчик всегда будет менять файлы, находясь на этом этапе, самом часто посещаемом.</p>
</li>
<li><a id="svnWork6">Закрепление изменений</a>. Действие сводится к выбору команды контекстного меню <span class="contextMenu">SVN Commit…</span> Причем для какого объекта вы ее выбрали, тот и будет закреплен. Это открывает большие возможности по ветвлению в рамках одной ветки: можно разбить ряд внесенных изменений по правкам. Commit для всей рабочей копии, естественно приведет к закреплению всех изменений, что вы и сделали в конце предыдущего шага. Вообще, закрепление изменений рекомендуется делать осмысленно. Не раз в день, не каждые 3.14 минуты, а по задаче. В качестве примера, локализация плагина WordPress — отличная вещь, умещающаяся в одной правке. А вот локализацию большего их числа лучше разбить на несколько. Идея проверить что-либо «на живую» тоже вполне втиснется в рамки одной правки. Другое дело, если «что-либо» это что-то кардинальное, да и к тому же конфликтующее с текущими наработками, тогда дело за ветками, о чем как-нибудь потом;</li>
<li><a id="svnWork7">выборка данных из хранилища</a>. Широкие горизонты этой возможности открывает нам команды <span class="contextMenu">SVN Update</span> и <span class="contextMenu">TortoiseSVN→Update to revision…</span> Первая берет самую актуальную информацию об объекте для которого применена, а вторая позволяет выбрать номер правки из которой будет взята информация — машина времени в действии. Номер необходимой правки можно узнать по щелчку на кнопке Show Log. Еще к выборке можно отнести и команду <span class="contextMenu">SVN Checkout</span>, которая также позволяет выбрать номер правки для выборки, но доступна эта команда только для объектов не находящихся в поле рабочей копии. Таким образом, можно всегда создать рабочую копию любой правки, что также есть путешествие во времени;</li>
<li><a id="svnWork8">Отмена изменений</a>. Действия по изменению объектов рабочей копии можно отменить. Для этого существует команда <span class="contextMenu">TortoiseSVN→Revert…</span>, которая заменяет объект своим кэшированным вариантом, который соответствует последней правке. Обращения к серверу не будет, кэш находится в системных директориях <span class="filePath">.svn</span>;</li>
</ol>
<p>Теперь, когда более или менее подробно разобраны все обычно необходимые и достаточные шаги по оперированию хранилищем и рабочей копией вы можете начать развивать собственную практику общения с SVN. Осталось немного, некоторые подводные камни и нюансы.</p>
<h3 class="floatBar">Подводные камни и нюансы</h3>
<ol>
<li id="nuancePaths"><span class="captionLi">Пути</span>. Устоявшимся стандартом организации путей в хранилище является создание трех «директорий»: <span class="filePath">trunk</span>, <span class="filePath">tags</span> и <span class="filePath">branches</span>, причем текущая разработка обычно находится в <span class="filePath">trunk</span>, а остальные используются по мере надобности. Именно поэтому пути в примерах несколько странные на первый взгляд. Зачем и почему принята такая структура можно узнать из соответствующих глав книги <a href="http://svnbook.red-bean.com/nightly/ru/svn.reposadmin.projects.html#svn.reposadmin.projects.chooselayout">SVN Book</a>;</li>
<li><span class="captionLi">удаление и прочие файловые операции</span>. Если вы решили удалить или переименовать какой-то объект рабочей копии, то делайте это посредством соответствующих команд контекстного меню — изменение часть файловой системы и хранилища при последующем <span class="command">commit</span> — разные вещи;</li>
<li><span class="captionLi">рекурсивные свойства</span>. Если вы добавляете в рабочую копию новую директорию, а где-то для ее предков установлено свойство с пометкой «apply property recursively», то его надо переустановить, чтобы оно было выставлено и для новой директории;</li>
<li><span class="captionLi">что если ошибка</span>? На наше счастье операции commit и update — атомарные. Это значит, что если на протяжении этих операций возникает ошибка, то операции просто не было. Это очень напоминает транзакции;</li>
<li><span class="captionLi">ошибка «… probably out of date …»</span>. В случае данного сообщения попытайтесь сделать <span class="command">update</span> для объекта (чаще всего это директории), обычно это помогает. Дело в то, что объект был изменен как в рабочем копии, так и в хранилище. Объект необходимо сначала обновить: <span class="command">update</span> попытается объединить локальные изменения с опубликованными. Если SVN не сможет самостоятельно совершить объединение, он предложит пользователю разрешить конфликт вручную;</li>
<li><span class="captionLi">ошибка при изменении комментария к правке: «DAV request failed; it’s possible that the repository’s pre-revprop-change hook either failed or is non-existent»</span>. Изменения свойств хранилища <a href="http://svnbook.red-bean.com/nightly/ru/svn.reposadmin.create.html#svn.reposadmin.create.hooks">по умолчанию отключены</a>. Для активации возможности изменять логи правок создайте в поддиректории hooks хранилища файл с именем <span class="filePath">pre-revprop-change.bat</span> и следующим кодом:
<pre name="code" class="html">@ECHO Off
IF "%4" == "svn:log" GOTO :SVN_LOG
EXIT 1
:SVN_LOG
EXIT 0</pre>
</li>
<li> 		<span class="captionLi">переименование объектов, сводящееся к изменению регистра символов в имени</span>. В этом случае ошибка растет из регистронезависимости имен файлов ОС Windows. Что случается при любом переименовании файла? Клиент SVN помещает в системные поддиректории <span class="filePath">.svn</span> переименованный файл, но также сохраняет там и старый — конфликт! Существует два пути решения такой проблемы:
<ul>
<li>непосредственно в хранилище (рекомендуемый)
<ul>
<li>закрепить правку;</li>
<li>переименовать <span class="filePath">нужный_файл.файл</span>, используя браузер хранилища, в <span class="filePath">Нужный_Файл.файл</span>;</li>
<li>обновить рабочую копию.</li>
</ul>
</li>
<li>через временный файл
<ul>
<li>переименовать <span class="filePath">нужный_файл.файл</span> в <span class="filePath">нужный_файл.файл_</span>;</li>
<li>закрепить правку;</li>
<li>переименовать <span class="filePath">нужный_файл.файл</span> в <span class="filePath">Нужный_Файл.файл</span>;</li>
<li>закрепить правку.</li>
</ul>
</li>
</ul>
</li>
<li><span class="captionLi">перемещение через переименование</span>. В случае, когда в рабочей копии необходимо перенести объект необязательно его удалять и добавлять заново. Воспользуйтесь функцией переименования и укажите относительный путь конечной директории;</li>
<li id="nuanceIgnoreDir"><span class="captionLi">Игнорирование родителя</span>. Если вы занесли в игнор-лист некую директорию, то все ее дочерние элементы будут игнорироваться автоматически, что удобно при разнородном содержимом директории.</li>
</ol>
<h3 class="floatBar">Заключение</h3>
<p>Если вы дошли до этих строк, значит, вам это было нужно, выпейте чаю. Также возможно, что у вас просто быстрый скроллинг, но это не умаляет предыдущую мысль.</p>
]]></content:encoded>
			<wfw:commentRss>http://web-dev.info/2008/02/vvedenie-v-subversion/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>
