Стержневые и оперативные правки

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

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

Простейшим примером может служить ситуация, когда каталог или файл сначала удаляют из версионного контроля, а затем создают новый элемент с тем же именем и добавляют его под версионный контроль. Безусловно, то, что вы удалили и то, что вы впоследствии добавили — это разные вещи. Просто так получилось, что они имеют одинаковый путь, например /trunk/object. Что должен выдать Subversion, когда вы запросите у него историю /trunk/object? Имеете ли вы ввиду то, что находится по этому пути в текущий момент, или тот старый объект, который вы удалили? Спрашиваете ли вы об операциях, совершенных со всеми объектами, которые когда-либо располагались по этому пути? Очевидно, Subversion требуется подсказка о том, что же вы действительно хотите получить.

Благодаря перемещениям история версионированного объекта может получиться гораздо более извилистой, чем в только что рассмотренном примере. Допустим, что у вас есть каталог с именем concept, содержащий недавно начатый проект разработки программы, с которым вы усиленно экспериментируете. В один прекрасный момент этот проект дорастет до того, что вы признаете идею действительно стоящей и ценой неимоверных усилий все-таки решите дать проекту имя. [22] Допустим, вы назвали вашу программу Frabnaggilywort. При этом не помешало бы переименовать каталог, чтобы он отражал новое имя проекта, поэтому concept переименовывается в frabnaggilywort. Жизнь идет дальше, выпускается версия Frabnaggilywort 1.0, она доступна для скачиванися и ежедневно используется кучей людей, жаждущих улучшить свою жизнь.

Это действительно хорошая история — но она на этом не заканчивается. У такого предприимчивого человека как вы в голове уже родилась новая идея. Поэтому вы создаете новый каталог с именем concept, и цикл начинается снова. На самом деле, этот цикл с годами повторяется многократно, каждый раз начинаясь со старого каталога concept, который впоследствии иногда переименовывается (когда идея оказывается хороша), а иногда удаляется (когда идея оказывается неудачной). Чтобы совсем запутаться, предположим, что вы сначала переименовали concept во что-то еще, а впоследствии по какой-то причине переименовали его обратно в concept.

При возникновении подобных ситуаций пытаться объяснить Subversion, как работать с этими многократно используемыми путями — все равно что сказать автомобилисту в западных пригородах Чикаго, чтобы он ехал на восток вниз по Roosevelt Road, а затем повернул налево на Main Street. Меньше чем за двадцать минут можно пересечь «Main Street» в Уитоне, Глен Эллине и Ломбарде. И это будут три разных улицы. Нашему автомобилисту, как и Subversion, нужно больше подробностей, чтобы поступить правильно.

Начиная с версии 1.1, Subversion позволяет вам точно указать, какую именно Main Street вы имеете ввиду. Для этого используется так называемая стержневая правка (peg revision) — то есть правка, указываемая Subversion исключительно для того, чтобы однозначно идентифицировать отдельную линию в истории. Поскольку в любой конкретный момент времени (или, говоря точнее, в любой конкретной правке) определенному пути может соответствовать не более одного версионированного объекта, комбинации пути и стержневой правки достаточно для однозначной ссылки на определенную линию в истории. Для указания стержневых правок в клиенте Subversion с интерфейсом командной строки используется at-синтаксис, который получил такое название, потому что включает добавление «символа at» (@) и номера стержневой правки после пути, который связан с данной правкой.

Ну а как же параметр --revision (-r), о котором мы так много говорили в этой книге? Эта правка (или множество правок) называется оперативной правкой (или диапазоном оперативных правок). Идентифицировав конкретную линию в истории с помощью пути и стержневой правки, Subversion выполняет требуемые операции, используя оперативную правку (или правки). Возвращаясь к нашей аналогии с улицами Чикаго, если нам объясняют, как проехать к дому 606 N. по Main Street в Уитоне, [23] мы можем рассматривать «Main Street» как путь и «Уитон» как стержневую правку. Эти два элемента информации однозначно идентифицируют путь, по которому нам следует ехать (на север или на юг Main Street), и позволяет нам избежать поездок верх и вниз по неправильным Main Street в поиске точки назначения. Далее мы рассматриваем «606 N.» как своего рода оперативную правку, и мы точно знаем, куда нам ехать.

Допустим, что хранилище создано давным давно, и в правке 1 была добавлен наш первый каталог concept, а также файл IDEA внутри этого каталога, содержащий описание концепции. После нескольких правок, в которых добавлялся и изменялся реальный программный код, в правке 20 мы переименовали этот каталог в frabnaggilywort. В правке 27 у нас появилась новая идея, для которой мы создали новый каталог concept и новый файл IDEA с описание наших мыслей. Спустя пять лет и двадцать тысяч правок они будут уже частью одной древней истории.

Теперь, спустя годы, мы интересуемся, как же выглядел файл IDEA в правке 1. Но Subversion нужно знать, спрашиваем ли мы о том, как выглядел в правке 1 текущий файл, или интересуемся содержанием того файла, который когда-то, в правке 1 имел путь concepts/IDEA? Эти вопросы, конечно же, будут иметь разные ответы, и благодаря стержневым правкам мы можем задать оба из них. Чтобы найти, как выглядел в той старой правке текущий файл IDEA, мы выполним такую команду:

$ svn cat -r 1 concept/IDEA 
svn: Unable to find repository location for 'concept/IDEA' in revision 1

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

$ svn cat -r 1 concept/IDEA@BASE
svn: Unable to find repository location for 'concept/IDEA' in revision 1

Ее выполнение приведет к тому же ожидаемому результату. Стержневой правкой по умолчанию считается BASE (правка, представленная в текущий момент в вашей рабочей копии) при указании путей рабочей копии, и HEAD при указании URL-адресов.

Проницательный читатель, вероятно, поинтересуется, как же быть с at-синтаксисом в случае, если пути рабочей копии или URL сами по себе содержат символ at. Откуда svn узнает, является ли news@11 именем каталога в моей файловой структуре, или же синтаксисом для «правки 11 каталога news»? К счастью, хотя svn предполагает последнее, существует тривиальный обходной прием. Нужно всего лишь добавить символ at в конец пути, записав его как news@11@. svn обращает внимание только на последний символ at в аргументе и не считaет ошибкой, если вы опустите указание стержневой правки после символа at. Этот обходной прием применим даже к путям, которые оканчиваются символом at — укажите filename@@, чтобы сослаться на файл с именем filename@.

Давайте зададимся теперь вторым вопросом — какого было в правке 1 содержание файла, располагавшегося по адресу concepts/IDEA? Получить ответ нам поможет явное указание стержневой правки.

$ svn cat concept/IDEA@1
The idea behind this project is to come up with a piece of software
that can frab a naggily wort.  Frabbing naggily worts is tricky
business, and doing it incorrectly can have serious ramifications, so
we need to employ over-the-top input validation and data verification
mechanisms.

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

Судя по выведенному тексту файла, это именно то, что мы ожидали получить. В тексте даже упоминается frabbing naggily worts, так что почти наверняка этот файл описывает программу, называющуюся теперь Frabnaggilywort. Мы можем в этом удостовериться, явно указав и стержневую, и оперативную правки. Нам известно, что в правке HEAD проект Frabnaggilywort располагается в каталоге frabnaggilywort. Поэтому мы укажем, что хотим увидеть, как выглядела в правке 1 та линия истории, которая идентифицируется в HEAD как путь frabnaggilywort/IDEA.

$ svn cat -r 1 frabnaggilywort/IDEA@HEAD
The idea behind this project is to come up with a piece of software
that can frab a naggily wort.  Frabbing naggily worts is tricky
business, and doing it incorrectly can have serious ramifications, so
we need to employ over-the-top input validation and data verification
mechanisms.

И стержневая, и оперативная правки не обязательно должны быть столь тривиальными. Предположим, что frabnaggilywort удален из HEAD, но при этом нам известно, что он существовал в правке 20, и мы хотим увидеть различия для файла IDEA между правками 4 и 10. Мы можем указать стержневую правку 20 вместе с URL, по которому располагался файл IDEA проекта Frabnaggilywort в правке 20, а затем использовать 4 и 10 как указатели диапазона оперативных правок.

$ svn diff -r 4:10 http://svn.red-bean.com/projects/frabnaggilywort/IDEA@20
Index: frabnaggilywort/IDEA
===================================================================
--- frabnaggilywort/IDEA	(revision 4)
+++ frabnaggilywort/IDEA	(revision 10)
@@ -1,5 +1,5 @@
-The idea behind this project is to come up with a piece of software
-that can frab a naggily wort.  Frabbing naggily worts is tricky
-business, and doing it incorrectly can have serious ramifications, so
-we need to employ over-the-top input validation and data verification
-mechanisms.
+The idea behind this project is to come up with a piece of
+client-server software that can remotely frab a naggily wort.
+Frabbing naggily worts is tricky business, and doing it incorrectly
+can have serious ramifications, so we need to employ over-the-top
+input validation and data verification mechanisms.

К счастью, большинство людей не сталкивается со столь сложными ситуациями. Но если такое все-таки случится, помните, что стержневые правки — это дополнительная подсказка, которая нужна Subversion для устранения неоднозначности.



[22] «You're not supposed to name it. Once you name it, you start getting attached to it.» — Mike Wazowski

[23] 606 N. Main Street, Wheaton, Illinois, is the home of the Wheaton History Center. Get it—«History Center»? It seemed appropriate….