Subversion в действии

Настало время перейти от абстракций к конкретике. В этом разделе мы покажем реальные примеры использования Subversion.

URL хранилища в Subversion

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

$ svn checkout http://svn.example.com:9834/repos
…

Однако в обработке URL Subversion есть некоторые нюансы, о которых нужно помнить. Например, в соответствии с принятыми соглашениями, URL использующий метод доступа file: (этот метод доступа используется для локальных хранилищ) должен либо иметь имя сервера localhost либо вообще не содержать имени сервера:

$ svn checkout file:///path/to/repos
…
$ svn checkout file://localhost/path/to/repos
…

Кроме того, тем кто применяет схему file: на платформе Windows необходимо использовать неофициальные «стандартные» правила записи при обращении к хранилищу, которое находится на одном компьютере но на разных дисках с клиентом. Обе из приведенных ниже записей будут работать; здесь X это имя диска, на котором находится хранилище:

C:\> svn checkout file:///X:/path/to/repos
…
C:\> svn checkout "file:///X|/path/to/repos"
…

При второй форме записи, для того, чтобы вертикальная черта не расценивалась как канал, необходимо брать URL в кавычки. Так же обратите внимание на использование в URL прямого слеша, не взирая на то, что родная (не-URL) форма записи пути на Windows использует обратный слеш.

Ну и наконец, нужно сказать о том, что клиент Subversion автоматически кодирует URL при необходимости, точно так же как это делает веб-браузер. Например, если в URL будет пробел или ASCII-символы в верхнем регистре:

$ svn checkout "http://host/path with space/project/españa"

…то Subversion скроет небезопасные символы и будет вести себя, как если бы вы напечатали так:

$ svn checkout http://host/path%20with%20space/project/espa%C3%B1a

Если в URL есть пробелы, возьмите его в кавычки и тогда командная оболочка обработает это все как один аргумент программы svn.

Рабочие копии

Вы уже читали о рабочих копиях; теперь мы покажем как Subversion-клиент создает и использует их.

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

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

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

Как правило, хранилище Subversion содержит файлы (или исходный код) нескольких проектов; обычно каждый проект представляется в виде подкаталога файловой системы хранилища. При таком подходе, пользовательская рабочая копия обычно соответствует отдельному подкаталогу хранилища.

Например, предположим, что у вас есть хранилище, содержащее два программных проекта: paint и calc. Каждый проект располагается в своем собственном каталоге, как показано на Рисунок 1.6, «Файловая система хранилища».

Рисунок 1.6. Файловая система хранилища

Файловая система хранилища

Для того чтобы создать рабочую копию, вам нужно получить какую-либо из подкаталогов хранилища. (Возможно, термин получить звучит как что-то связанное с блокированием или резервированием ресурсов, но это не так; эта команда просто создает для вас личную копию проекта.) Например, если вы получите /calc, у вас будет рабочая копия, наподобие этой:

$ svn checkout http://svn.example.com/repos/calc
A    calc/Makefile
A    calc/integer.c
A    calc/button.c
Checked out revision 56.

$ ls -A calc
Makefile  integer.c  button.c  .svn/

Буквы А говорят о том, что Subversion добавил этот элемент в вашу рабочую копию. Теперь у вас есть личная копия каталога /calc хранилища, с одним небольшим добавлением — каталогом .svn, содержащим, как было указано выше, дополнительную информацию, необходимую Subversion.

Предположим, вы внесли изменения в button.c. Так как каталог .svn помнит дату изменения файла и его оригинальное содержимое, Subversion может сказать о том, что вы изменили файл. Subversion не публикует ваших изменений пока вы не прикажете это сделать. Публикация ваших изменений более известна как фиксация (или checking in) изменений в хранилище.

Для того, что бы опубликовать ваши изменения вы можете воспользоваться командой commit.

$ svn commit button.c -m "Fixed a typo in button.c."
Sending        button.c
Transmitting file data .
Committed revision 57.

Теперь ваши изменения в button.c с примечанием, описывающим эти изменения (а именно, исправление опечатки), зафиксированы в хранилище; если другой пользователь создаст рабочую копию /calc, он увидит ваши изменения в последней версии файла.

Предположим, у вас есть партнер, Салли, которая создала рабочую копию /calc одновременно с вами. Когда вы зафиксировали изменения в button.c, рабочая копия Салли осталась не измененной; Subversion модифицирует рабочие копии только по запросу пользователей.

Для приведения рабочей копии в актуальное состояние, Салли может попросить Subversion обновить её рабочую копию, используя команду Subversion update. Это внедрит ваши изменения в ее рабочую копию вместе с другими изменениями, которые были зафиксированы с момента когда она создавала рабочую копию.

$ pwd
/home/sally/calc

$ ls -A
.svn/ Makefile integer.c button.c

$ svn update
U    button.c
Updated to revision 57.

Вывод команды svn update говорит, что Subversion обновила содержимое button.c. Обратите внимание, что Салли не должна указывать, какой файл обновить; для определения файлов, которые необходимо привести в актуальное состояние, Subversion использует информацию в каталоге .svn, а также информацию из хранилища.

Правки

Операция svn commit публикует изменения любого количества файлов и каталогов за одну атомарную операцию. В своей рабочей копии вы можете менять содержимое файлов, создавать, удалять, переименовывать и копировать файлы и каталоги, а затем зафиксировать все изменения за одну атомарную транзакцию.

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

Каждый раз, когда происходит фиксация, создаётся новое состояние файловой системы, которое называется правка. Каждая правка получает уникальный номер, на единицу больший номера предыдущей правки. Начальная правка только что созданного хранилища получает номер 0 и не содержит ничего, кроме пустого корневого каталога.

Рисунок 1.7, «Хранилище» отлично иллюстрирует хранилище. Представьте массив номеров правок, начинающийся с 0, с направлением слева направо. Каждый номер правки имеет соответствующее дерево файлов, а каждое дерево представляет собой «снимок» того, как хранилище выглядело после фиксации.

Рисунок 1.7. Хранилище

Хранилище

Важно помнить то, что рабочие копии не всегда соответствуют какой-то одной правке в хранилище; они могут содержать файлы из разных правок. Например, вы получили рабочую копию из хранилища, у которого самая последняя правка — 4:

calc/Makefile:4
     integer.c:4
     button.c:4

На данный момент рабочий каталог полностью соответствует правке 4 в хранилище. Допустим, что вы внесли изменения в button.c, и зафиксировали эти изменения. При отсутствии других фиксаций ваша фиксация создаст правку под номером 5, и теперь ваша рабочая копия выглядит следующим образом:

calc/Makefile:4
     integer.c:4
     button.c:5

Предположим, что после этого Салли фиксирует изменения integer.c, создавая правку 6. Если вы воспользуетесь svn update для приведения своей рабочей копии в актуальное состояние, то она станет выглядеть так:

calc/Makefile:6
     integer.c:6
     button.c:6

Изменения, внесенные Салли в integer.c будут отражены в вашей рабочей копии, и ваши изменения в button.c также будут присутствовать. В этом примере текст Makefile в правках 4, 5 и 6 идентичен, однако, Subversion проставляет номер правки 6 для вашей рабочей копии Makefile, чтобы показать что файл не устарел. Таким образом, после того как вы выполните полное обновление вашей рабочей копии, она будет полностью соответствовать текущему состоянию хранилища.

Как рабочие копии отслеживают хранилище

В служебном каталоге .svn/ для каждого файла рабочего каталога Subversion записывает информацию о двух важнейших свойствах:

  • на какой правке основан ваш рабочий файл (это называется рабочая правка файла), и

  • временной (ударение на последний слог) метке, определяющей, когда рабочая копия последний раз обновлялась из хранилища.

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

Не изменялся и не устарел

Файл не изменялся в рабочем каталоге, в хранилище не фиксировались изменения этого файла со времени создания его рабочей правки. Команды svn commit и svn update никаких операций делать не будут.

Изменялся локально и не устарел

Файл был изменен в рабочей копии, но в хранилище не фиксировались изменения этого файла последнего обновления рабочей копии. Есть локальные изменения, которые не были зафиксированы в хранилище, поэтому svn commit выполнит фиксацию ваших изменений, а svn update не сделает ничего.

Не изменялся и устарел

В рабочем каталоге файл не изменялся, но был изменен в хранилище. Необходимо выполнить обновление файла для того, чтобы он соответствовал текущей опубликованной правке. Команда svn commit не сделает ничего, а svn update обновит вашу рабочую копию файла в соответствии с последними изменениями.

Изменялся локально и устарел

Файл был изменен как в рабочем каталоге, так и в хранилище. svn commit потерпит неудачу, выдав ошибку «out-of-date». Файл необходимо сначала обновить; svn update попытается объединить локальные изменения с опубликованными. Если Subversion не сможет самостоятельно совершить объединение, он предложит пользователю разрешить конфликт вручную.

Может показаться, что следить за актуальным состоянием рабочей копии сложно. Это не так. Для того, чтобы узнать состояние любого элемента в вашей рабочей копии существует команда svn status. За более подробной информацией об этой команде обратитесь к «svn status».

Смешивание правок в рабочих копиях

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

Обновления и фиксации отделены друг от друга

Одно из фундаментальных правил Subversion заключается в том, что «передающее» действие не приводит к «принимаемому», и наоборот. То, что вы готовы внести изменения в хранилище, не означает то, что вы готовы принять изменения от других. А если вы все еще работаете над новыми изменениями, то svn update изящно объединит изменения из хранилища с вашими собственными, вместо того, что бы заставлять вас опубликовать их.

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

Допустим, у вас есть рабочая копия, полностью соответствующая правке 10. После изменения файла foo.html, вы выполняете команду svn commit, которая создает в хранилище правку 15. После выполнения фиксации большая часть новичков ожидают, что вся рабочая копия будет иметь правку 15, однако это не так. Между правками 10 и 15 в хранилище могло быть внесено любое количество изменений. Так как команда svn update не выполнялась, а svn commit не загружает изменений, клиент ничего не знает о находящихся в хранилище изменениях. С другой стороны, если команда svn commit будет автоматически загружать последние изменения, то всей рабочей копии можно будет назначить соответствующий номер правки - 15. Однако нарушится фундаментальное правило, согласно которому «передача» и «получение» являются независимыми операциями. Следовательно, все, что может сделать клиент Subversion, это пометить один файл — foo.html — как соответствующий правке 15. Остальная рабочая копия продолжает соответствовать правке 10. Только при выполнении svn update будут загружены последние изменения и вся рабочая копия будет помечена как соответствующая правке 15.

Смешивание правок — это нормально

Фактически, каждый раз при выполнении svn commit правки рабочей копии смешиваются. Только что зафиксированные элементы отмечаются как имеющие больший номер рабочей правки, чем все остальные. После нескольких фиксаций (без выполнения обновлений между ними) правки рабочей копии будут полностью перемешаны. Даже если вы являетесь единственным пользователем хранилища, вы все равно с этим столкнетесь. Для просмотра этой смеси рабочих правок воспользуйтесь командой svn status --verbose (см. «svn status»).

Часто новые пользователи даже не подозревают о том, что их рабочая копия содержит смешанные правки. Это может сбить с толку, так как многие команды клиента чувствительны к рабочей правке элемента, с которым он работает. Например, команда svn log используется для вывода истории изменения файла или каталога (см. «svn log»). Когда пользователь вызывает эту команду применительно к объекту рабочей копии, он ожидает увидеть полную историю этого объекта. Однако если рабочая правка объекта очень старая (из-за того, что команда svn update долго не выполнялась) будет показана история для более старой версии этого объекта.

Смешивание правок — это полезно

Если у вас очень большой проект, вы можете найти полезным, время от времени принудительно «возвращать» части рабочей копии к более ранним правкам; как это делается, вы узнаете в Глава 2, Экскурсия по Subversion. Возможно вы захотите протестировать более раннюю версию модуля, находящегося в подкаталоге или точно узнать, когда в конкретном файле появилась ошибка. Это — «машина времени» — тот аспект системы управления версиями, который позволяет перемещать в истории любую часть рабочей копии вперед и назад.

Смешивание правок имеет ограничения

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

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

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