Pull to refresh

Работа с ветками SVN

Reading time 6 min
Views 185K
Прежде чем приступать вообще к использованию веток, и даже если вы и не думаете их использовать, необходимо прочесть Этот Священный Талмуд.

После того как вы прочли статью о ветках в svnbook, вы уже понимаете для чего нужны ветки, как с ними работать и в каких случаях их необходимо использовать. В принципе, после этого, то, что написано под катом вам уже скорее всего не нужно. Но если вам было лень читать, то может текст ниже вас заинтересует, и вы все таки прочтете статью документации. А может, просто поможет вам лучше понять то, что только что прочли в svnbook-е.

Для чего все это?

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

Но иногда задача длинная, а закоммититься где нибудь посредине мы не можем, по причине что недоделанная задача, закомиченная в основной код, может мешать другим разработчикам в их работе. Но не коммитится несколько дней тоже неправильно. Во-вторых, может понадобиться выгрузка кода на продакшен. Если мы коммитим в основную ветку недоделанную задачу, она попадет на продакшен, что не кошерно. Для этого существуют ветки. Они позволяют нам комитится в любое удобное для нас время, при этом не мешая всем остальным. Так же ветки позволяют работать над несколькими задачами параллельно, не перемешивая их.

Что такое ветка?

Это всего лишь копия директории svn. Точнее так называемая «легкая копия», содержащая только изменения. Одинаковые файлы не копируются. Ветка имеет общую историю до момента её создания с основной веткой. В общем случае веток может быть сколько угодно, и каждая из них может ветвиться. Но в стандартом проекте принято иметь три постоянных ветки:

* trunk — основная линия разработки. Здесь будет актуальный на данный момент код, здесь будут выполняться мелкие задачи и правки багов.
* branches — ветка для разработчиков. гсуто ветвится другими ветками. Именно в ней вы будете создавать свои ветки.
* tags — ветка тэгов. Тут создаются всякие метки, отмечающие значимые вехи развития проектов, проще говоря его стабильные и не очень версии. Нужна она для того, что бы всегда можно было вернуться до какой нибудь версии, например что бы посмотреть «почему эта хрень раньше работала а потом перестала, сцуко»

Программисты отвечают за то, что бы

* Создать ветку тогда когда это нужно для стабильного существования проекта. В общем случае если вы чувствуете что задача будет длиться больше пары дней (а иногда и дня), и все это время вы не сможете безболезненно коммититься хотя бы пару раз в день, вам нужна ветка.
* Поддерживать свою ветку в актуальном состоянии — то есть необходимо избавиться от панического страха перед командой merge как можно раньше, и мержить не реже чем комитишь. Иначе конфликтов при сливании ветки с транком не избежать.
* Удалить ветку после завершения задачи. Ветки разработчиков — временные ветки, поэтому они должны удаляться, когда задача завершена. В крайнем случае, они могут пожить еще несколько дней, для уверенности, что в задаче нет больших ошибок. Дальше ветка никому нужна не будет, её можно удалять. Все равно, через некоторое время, она так далеко отойдет от основной линии разработки, что уже никакой мердж не сможет ей вернуть актуальность.

Как работать с ветками

Создать новую ветку очень просто. Как следует из талмуда, делается это командой copy. Допустим, мы разрабатываем некий проект — BUMP (Большой Афигенный Мега Проект). Для нашего случая, нужно выполнить такую команду:

svn copy svn://svnserver/var/bump/trunk svn://svnserver/var/bump/branches/my-branch -m="Creating a private branch of /bump/trunk"

Для того, что бы переключиться в новую ветку:

svn switch svn://svnserver/var/bump/branches/my-branch

Для того что бы проверить в какой ветке находитесь сейчас

svn info

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

Копирование изменений между ветками

Для того что бы держать свою ветку в актуальном состоянии, вам необходимо периодически копировать изменения из основной ветки. Это необходимо для того, что бы избежать конфликтов при слиянии веток или при переключении в основную ветку. Поэтому мержится нужно почаще, хотя бы раз-два за день. Можно взять за правило: мержиться перед каждым коммитом. Команада merge, наверное, самая сложная из команд svn. И все дело в том, что svn не помнит о ваших предыдущих мержах (до версии 1.5). А раз не помнит, значит вы рискуете скопировать себе изменения, которые уже у вас есть, после предыдущего мержа. Но этот недостаток легко обойти. После каждого копирования изменений себе в рабочую копию, вам необходимо закомитить их в свою ветку. В комментарии укажите диапазон ревизий, включенных в ваш текущий мерж. То есть например так: «merged from trunk r1234:1256». Этот комментарий будет служить вам памяткой, и вы в любой момент сможете посмотреть когда вы последний раз мержились и какая ревизия является последней. Такие комментарии включать обязательно, иначе, будут большие проблемы и непонятки. И еще. Для того что бы быть уверенным что все смержится удачно, можно сначала, перед реальным копированием, сделать проверочное. Для этого используется параметр --dry-run который только показывает вывод, не внося изменений в рабочую копию.

Итак, посомтреть изменения из транка можно такой командой:

svn merge -r4106:HEAD svn://svnserver/var/bump/trunk ./ --dry-run

Получаем, например, такой вывод:

--- Merging r4107 into '.':
U db/queries.txt
U ejb/src/main/java/ru/bump/action/folder/MoveFolderActionLocal.java
U ejb/src/main/java/ru/bump/action/user/UserRegistrationAction.java


Это означает что в ревизии r4107 изменилось 3 файла. Отлично, все правильно, копируем изменения

svn merge -r4106:HEAD svn://svnserver/var/bump/trunk ./

И комитимся:

svn ci -m "merged from trunk r4106:4108"

Число 4108 это номер текущей ревизии. Получить его просто. Достаточно выполнить команду svn up.

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

svn log --stop-on-copy

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

#:~/www/bump$ svn log | grep merged
merged from trunk r4106:4108


Таким образом, что бы смержить еще раз из транка нужно выполнить команду

svn merge -r4109:HEAD svn://svnserver/var/bump/trunk ./

Завершение работы над задачей

Если работа над задачей завершена, вам нужно

* Слить свои изменения в транк
* Удалить свою ветку что бы не мешалась

Сливаем в транк той же командой merge. Для этого выясняем ревизию создания ветки, и свитчимся в транк.

svn switch svn://svnserver/var/bump/trunk

После этого копируем изменения из своей ветки

#svn up
At revision 4155

#svn merge svn://svnserver/var/bump/trunk@4155 svn://svnserver/var/bump/branches/my-branch@4155


Если все прошло нормально, нет никаких конфликтов и доделать ничего не нужно, комитим изменения в основную ветку, а свою ветку можно теперь удалить. Она совсем не отличается от транка, и в случае надобности мы всегда сможем создать еще одну ветку. Да и стоит помнить что наша ветка конечно же не удаляется физически, просто она удаляется из HEAD, но в ранних ревизиях мы всегда сможем её отыскать, и при необходимости востановить. Так что смелее:

svn delete svn://svnserver/var/bump/branches/my-btanch -m "Removing my-branch branch."

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

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

Заключение

В этой статье содержится лишь малая часть сведений о работе с ветками. Она может служить как памятка, но не как самоучитель. Поэтому настоятельно рекомендуется прочесть соответствующий раздел svnbook. В нем содержится множество сведений которые не попали в этот опус, но необходимы для понимания того как работать с ветками.
Tags:
Hubs:
+78
Comments 72
Comments Comments 72

Articles