Системы управления версиями для программистов и не только. Часть 5
Сегодня я завершаю рассказ об SVN. В прошлой статье я начал рассказ о средствах работы с SVN без командной строки — с помощью графического интерфейса (программы TortoiseSVN и SmartSVN). После того, как мы научились в TortoiseSVN вести проект, помещать и извлекать его из хранилища, добавлять/удалять файлы, нам осталось только разобраться с ветками, слияниями и разрешениями конфликтов.
Напомню, что под "ветками" я понимаю направление развития проекта, отличное от основного "ствола" разработки (trunk) или другой ветви. Например, экспериментальная ветка, на которой опробуются потенциально опасные нововведения, и только после завершения тестов изменения переносятся в основной "ствол" разработки. На "ветки" похожи и "теги": считается, что это моментальный снимок проекта, которому мы даем имя, но дальнейшую разработку не ведем ("тег" полагается как стабильное состояние проекта). Хотя такое деление условно, и в состав SVN не входит каких-то специальных команд создания ветви или тега (есть только одна универсальная команда копирования проекта, но не более). Но разработчики Tortoise решили не смущать массового пользователя и в интерфейсе своего продукта оперируют понятием "ветка" и "тег", а не "просто копия" (вот только с последовательностью в интерфейсе у разработчиков tortoise просто беда). Итак: у нас есть проект в актуальном состоянии (со сделанным commit'ом), мы вызываем контекстное меню проводника windows для папки с проектом (см. рис. 1), затем выбираем пункт Tortoise SVN -> Branch Tag.
В появившемся диалоговом окне (см. рис. 2) нас спросят, куда мы хотим скопировать текущую ветвь проекта, какую ревизию мы хотим скопировать (по умолчанию HEAD — это означает последнюю актуальную) и куда мы хотим ее скопировать (вспоминайте правила хорошего тона при именовании каталогов, каталоги tags и branches). Я же ввел такой адрес: test/project/branches/bra008, затем ввел текст примечания (а то забуду, чем так примечательна ветка под названием bra008). Внизу окна создания копии проекта обратите внимание на галочку Switch working copy to new branch/tag. Если она включена, то после создания копии ваш проект будет переключен на копию, и все последующие правки будут вноситься в свежесозданную ветвь разработки. В любом случае вы можете в произвольный момент времени переключиться на другую ветвь/тег проекта (меню Tortoise SVN -> Switch является аналогом описанной ранее команды switch). Итак, вы создаете ветки и теги. Интересно, предусмотрели ли разработчики TortoiseSVN механизм, позволяющий сказать, что вот эта копия файлов (tag) не должна редактироваться? И да, и нет. После того, как я создал копию ствола разработки в виде тега, затем внес правки и решил отправить их в репозиторий, TortoiseSVN решила предупредить меня, что вносить правки в "тег" (единственный признак тега — это расположение проекта по пути, содержащему в своем имени слово tags — например, /test/project/tags/tag002) не рекомендуется (см. рис. 3). Никаких более действенных средств защиты не предусмотрено — все на вашей совести. Для просмотра дерева проекта (чтобы увидеть, как из ствола разработки произрастают ветки, как из веток начинают расти другие ветки) используйте меню Tortoise SVN -> Revision Graph. Маленький совет: если выделить на изображении графа два узла (две ревизии) с помощью зажатого Ctrl, то после вызова контекстного меню вы можете увидеть изменения, которые были сделаны между этими двумя ревизиями.
Теперь попробуем поработать со слиянием. В общем случае есть две методики работы со слияниями (они более определены стилем работы с кодом, чем какими-то особенностями в SVN). Первый вариант: вы от основного ствола разработки отделили ветвь, затем в эту ветвь вносили правки (несколько подряд выполненных ревизий). Для примера предположим, что на момент отделения ветви номер ревизии был 100, а в коде файла about1.txt (только его мы редактировали) были описаны функции Foo0, Bar0. После создания ветви с именем /test/project/branches/forMerge1 под номером 101 вы внесли правки, и их номера стали 102, 103. В этих правках в текст файла были добавлены функции Foo1 и Bar1. Теперь вы хотите перенести изменения, выполненные в экспериментальной ветви (forMerge1), назад в основную ветвь. Для этого переключитесь на trunk и вызовите меню Tortoise SVN -> Merge. В появившемся диалоговом окне настраиваются параметры слияния. Обратите внимание на две графы: From и To (по умолчанию эта строка заблокирована). Нам нужно выбрать в верхнем падающем списке (From) ветку проекта, из которой мы хотим извлечь сделанные изменения (автоматически эта же ветка подставится в графу To). Теперь нужно указать номера ревизий файлов (чтобы определить границы изменений, сделанных над файлом в этой ветке). Установив значения цифр, настоятельно рекомендую просмотреть то, какие изменения были обнаружены с помощью расположенной внизу окна кнопки Diff, после чего будет открыто знакомое вам по прошлой статье окно diff (отличий между файлами). Возвращаясь к более раннему примеру, если в поле To я введу номер ревизии 103, в графу From номер ревизии 101, тогда в окне Diff будет показано, что добавились две функции: Foo1 и Bar1.
Когда номера ревизий будут для To 103, а для From — 102, то в списке отличий будет только функция Bar1. И напоследок выбор отрезка 102-101 даст функцию Foo1. Прикинув с помощью diff, что верно выбрали диапазон номеров изменений, мы завершаем операцию merge и, нажав кнопку Merge, вносим обнаруженные изменения в файл about1.txt в рабочей копии. Если в ходе слияния возникли конфликты (файл about1.txt был отредактирован), то в папке проекта рядом с файлом about1.txt появляются файлы about1.txt.merge-left.r101, about1.txt.merge-right.r103 и about1.txt.working. В них находится содержимое файла about1.txt на момент ревизий номер 103, 101 и текущая ревизия. Вы просматриваете файлы, находите причину конфликта и исправляете ее именно в файле about1.txt. Затем с помощью меню Tortoise SVN -> Resolved вы сообщаете SVN о том, что конфликт был разрешен (тут же файлы about1.txt.merge-left.r101, about1.txt.merge-right.r103, about1.txt.working должны исчезнуть). Последний шаг — отправить изменения в репозиторий (commit) — поздравляю: слияние изменений было завершено. Теперь более сложный сценарий, когда изменения определяются не между двумя различными ревизиями одной ветви, а между разными ветвями (а что, вполне-таки вероятная ситуация, когда в ветке A мы добавили в проект функцию Foo1, в ветке B — функцию Foo2, а теперь хотим получить в рабочей версии общую функциональность Foo1+Foo2). Отличий в процессе слияния не много: так же вызываете диалоговое окно настроек слияния, но нужно отключить галочку для пункта Use From URL напротив графы To. Таким образом, вы сможете для To выбрать ветвь, отличную от From. На этом считаю рассказ об Tortoise завершенным, а нам пора перейти к описанию еще одного клиента SVN — SmartSVN.
Итак, SmartSVN является кроссплатформенным (ага, он будет работать под linux) SVN-клиентом за счет того, что написан на java. Есть две версии SmartSVN: Foundation и Profession: первая из них бесплатная, вторую же нужно купить. В практике большинство задач успешно решаются в Foundation- версии, да и получить пробную лицензию на 30 дней не составляет никаких трудностей. Общее представление о функциональности SmartSVN: она почти не уступает TortoiseSVN. Основное отличие в идеологии построения интерфейса: Tortoise интегрируется в проводник windows, изменяет его контекстное меню, меняет иконки файлов. SmartSVN — автономное приложение, интерфейсом похожее на total commander или far (только без двух панелей). В основном окне SmartSVN находится перечисление файлов в составе проекта (см. рис. 5). Сразу расскажу о негативном опыте работы с SmartSVN: несмотря на то, что продукт создает в целом неплохое впечатление, использовать его в коллективной разработке не следует: не всегда корректно обнаруживаются конфликты с одновременным изменением файлов (в этом плане TortoiseSVN не имеет никаких нареканий). При первом запуске SmartSVN спросит, что вы хотите сделать: извлечь проект из репозитория, поместить некоторую папку внутрь репозитория или открыть существующий проект? Первые два действия не вызывают затруднений: вы указываете путь к репозиторию, затем к папке на вашем компьютере, куда будут скопированы (или откуда будут скопированы) файлы, и через несколько секунд у вас на руках будет "проект".
Если ваш проект на svn-сервере построен по правилам (trunk/tags/branches), то на стадии checkout'а будьте осторожны и обязательно укажите, что хотите импортировать не корень проекта, а конкретную папку из него (например, trunk). Этот момент важен, т.к., хотя SmartSVN вас предупредит, что импорт всего проекта нерекомендуем, но никак не запретит сделать это. И если вы допустите такую ошибку, то в последующем некоторые функции SmartSVN будут работать некорректно. В общем, помните про команду switch и не теряйтесь. Возвращаясь к SmartSVN и созданию в нем проекта: проект — это основная единица работы для SmartSVN, которая содержит параметры подключения к svn-серверу (путь к репозиторию, учетные данные для доступа). Свой рабочий день вы будете начинать с открытия проекта (меню Project -> Open), в результате чего в окне Directories (см. рис. 5 слева) будут показаны папки, входящие в состав проекта, а в основном окне отображаются файлы текущего каталога. Большинство операций с файлами/каталогами выполняется через контекстное меню (update, commit, revert…). Для открытия файла используйте двойной клик по нему (удобно, и никаких отличий от привычного интерфейса windows). Для каждого файла проекта используется своя иконка, указывающая статус файла в репозитории (для примера попробуйте отредактировать файл about1.txt, и вы увидите, как иконка сменит цвет на красный — знак того, что файл не сохранен в репозитории). После изменения файла двойной клик по нему уже не приводит к открытию файла — вместо этого появляется окно сравнения различий между текущим состоянием файла и его "Pristine Copy" (см. рис. 6). Полное перечисление иконок можно найти в справке, но в целом они интуитивно понятны.
Давайте рассмотрим методику работы с тегами/ветвями и историей правок. Несмотря на то, что в SVN понятие тегов и веток условно, разработчики SmartSVN решили создать инструменты работающими с этими понятиями не столь примитивно как "просто копия". Прежде всего, зайдите в меню Project -> Settings. Там на закладке Repository Layout находятся настройки структуры проекта в репозитории. Схема по умолчанию вполне тривиальна: папка tags хранит теги проекта, а папка branches — ветви (хотя вы можете изменить эти пути по своему усмотрению). Для создания тега/ветви используйте меню Tag/Branch -> Add Tag или Tag/Branch -> Add Branch. В появившемся диалоговом окне вы указываете название созданной ветви/тега (в случае ветки можно отметить галочку Switch to branch для того, чтобы переключить проект на свежесозданную копию). Для просмотра созданных тегов/ветвей используйте меню Tag/Branch -> Tag Browser. К сожалению, форма, в которой перечислены теги/ветви, не слишком удобна для просмотра, особенно если ваш репозиторий существует очень долго, и ветвей много, поэтому я рекомендую использовать представление ветвей/тегов в виде дерева (меню Query -> Revision Graph). Внешний вид окна дерева ревизий показан на рис. 7. Для того, чтобы детально увидеть правки, которые были выполнены в рамках некоторой ревизии, используйте меню Query -> Log. В меню Report найдется и еще несколько функций для просмотра истории правок проекта. Например, меню Query -> Change Report покажет вам список всех правок, которые были выполнены с момента последнего сохранения проекта. Для переключения между тегами/ветвями используйте меню Modify -> Switch. Наверняка пригодится и функция создания архива проекта, в ходе чего не просто будет скопирован каталог с локальной копией проекта в архив, но и удалены при этом служебные SVN-каталоги (меню Tools -> Export Backup). Несмотря на то, что SVN использует методику обеспечения коллективной работы по схеме Copy-Modify-Merge, не забывайте и про возможность работы с репозиторием по схеме Lock-Modify-Unlock (для того, чтобы блокировать или разблокировать файлы в проекте, используйте меню Lock).
На этом все. Я надеюсь, что смог выполнить свою основную задачу — рассказать о системах управления версиями документов, показать, что они совсем не страшные. Даже если вы не программист, а обычный менеджер, дизайнер, даже если вы не работаете над одними и теми же документами в команде. В любом случае вы сможете оценить преимущества стиля работы, когда есть "надежное место", хранящее все выполненные вами изменения, которое дает вам возможность создать копии файлов, переключаться между ними. Наверняка пригодится и работа с ветвями и тегами.
black-zorro@tut.by, black-zorro.com
Напомню, что под "ветками" я понимаю направление развития проекта, отличное от основного "ствола" разработки (trunk) или другой ветви. Например, экспериментальная ветка, на которой опробуются потенциально опасные нововведения, и только после завершения тестов изменения переносятся в основной "ствол" разработки. На "ветки" похожи и "теги": считается, что это моментальный снимок проекта, которому мы даем имя, но дальнейшую разработку не ведем ("тег" полагается как стабильное состояние проекта). Хотя такое деление условно, и в состав SVN не входит каких-то специальных команд создания ветви или тега (есть только одна универсальная команда копирования проекта, но не более). Но разработчики Tortoise решили не смущать массового пользователя и в интерфейсе своего продукта оперируют понятием "ветка" и "тег", а не "просто копия" (вот только с последовательностью в интерфейсе у разработчиков tortoise просто беда). Итак: у нас есть проект в актуальном состоянии (со сделанным commit'ом), мы вызываем контекстное меню проводника windows для папки с проектом (см. рис. 1), затем выбираем пункт Tortoise SVN -> Branch Tag.
В появившемся диалоговом окне (см. рис. 2) нас спросят, куда мы хотим скопировать текущую ветвь проекта, какую ревизию мы хотим скопировать (по умолчанию HEAD — это означает последнюю актуальную) и куда мы хотим ее скопировать (вспоминайте правила хорошего тона при именовании каталогов, каталоги tags и branches). Я же ввел такой адрес: test/project/branches/bra008, затем ввел текст примечания (а то забуду, чем так примечательна ветка под названием bra008). Внизу окна создания копии проекта обратите внимание на галочку Switch working copy to new branch/tag. Если она включена, то после создания копии ваш проект будет переключен на копию, и все последующие правки будут вноситься в свежесозданную ветвь разработки. В любом случае вы можете в произвольный момент времени переключиться на другую ветвь/тег проекта (меню Tortoise SVN -> Switch является аналогом описанной ранее команды switch). Итак, вы создаете ветки и теги. Интересно, предусмотрели ли разработчики TortoiseSVN механизм, позволяющий сказать, что вот эта копия файлов (tag) не должна редактироваться? И да, и нет. После того, как я создал копию ствола разработки в виде тега, затем внес правки и решил отправить их в репозиторий, TortoiseSVN решила предупредить меня, что вносить правки в "тег" (единственный признак тега — это расположение проекта по пути, содержащему в своем имени слово tags — например, /test/project/tags/tag002) не рекомендуется (см. рис. 3). Никаких более действенных средств защиты не предусмотрено — все на вашей совести. Для просмотра дерева проекта (чтобы увидеть, как из ствола разработки произрастают ветки, как из веток начинают расти другие ветки) используйте меню Tortoise SVN -> Revision Graph. Маленький совет: если выделить на изображении графа два узла (две ревизии) с помощью зажатого Ctrl, то после вызова контекстного меню вы можете увидеть изменения, которые были сделаны между этими двумя ревизиями.
Теперь попробуем поработать со слиянием. В общем случае есть две методики работы со слияниями (они более определены стилем работы с кодом, чем какими-то особенностями в SVN). Первый вариант: вы от основного ствола разработки отделили ветвь, затем в эту ветвь вносили правки (несколько подряд выполненных ревизий). Для примера предположим, что на момент отделения ветви номер ревизии был 100, а в коде файла about1.txt (только его мы редактировали) были описаны функции Foo0, Bar0. После создания ветви с именем /test/project/branches/forMerge1 под номером 101 вы внесли правки, и их номера стали 102, 103. В этих правках в текст файла были добавлены функции Foo1 и Bar1. Теперь вы хотите перенести изменения, выполненные в экспериментальной ветви (forMerge1), назад в основную ветвь. Для этого переключитесь на trunk и вызовите меню Tortoise SVN -> Merge. В появившемся диалоговом окне настраиваются параметры слияния. Обратите внимание на две графы: From и To (по умолчанию эта строка заблокирована). Нам нужно выбрать в верхнем падающем списке (From) ветку проекта, из которой мы хотим извлечь сделанные изменения (автоматически эта же ветка подставится в графу To). Теперь нужно указать номера ревизий файлов (чтобы определить границы изменений, сделанных над файлом в этой ветке). Установив значения цифр, настоятельно рекомендую просмотреть то, какие изменения были обнаружены с помощью расположенной внизу окна кнопки Diff, после чего будет открыто знакомое вам по прошлой статье окно diff (отличий между файлами). Возвращаясь к более раннему примеру, если в поле To я введу номер ревизии 103, в графу From номер ревизии 101, тогда в окне Diff будет показано, что добавились две функции: Foo1 и Bar1.
Когда номера ревизий будут для To 103, а для From — 102, то в списке отличий будет только функция Bar1. И напоследок выбор отрезка 102-101 даст функцию Foo1. Прикинув с помощью diff, что верно выбрали диапазон номеров изменений, мы завершаем операцию merge и, нажав кнопку Merge, вносим обнаруженные изменения в файл about1.txt в рабочей копии. Если в ходе слияния возникли конфликты (файл about1.txt был отредактирован), то в папке проекта рядом с файлом about1.txt появляются файлы about1.txt.merge-left.r101, about1.txt.merge-right.r103 и about1.txt.working. В них находится содержимое файла about1.txt на момент ревизий номер 103, 101 и текущая ревизия. Вы просматриваете файлы, находите причину конфликта и исправляете ее именно в файле about1.txt. Затем с помощью меню Tortoise SVN -> Resolved вы сообщаете SVN о том, что конфликт был разрешен (тут же файлы about1.txt.merge-left.r101, about1.txt.merge-right.r103, about1.txt.working должны исчезнуть). Последний шаг — отправить изменения в репозиторий (commit) — поздравляю: слияние изменений было завершено. Теперь более сложный сценарий, когда изменения определяются не между двумя различными ревизиями одной ветви, а между разными ветвями (а что, вполне-таки вероятная ситуация, когда в ветке A мы добавили в проект функцию Foo1, в ветке B — функцию Foo2, а теперь хотим получить в рабочей версии общую функциональность Foo1+Foo2). Отличий в процессе слияния не много: так же вызываете диалоговое окно настроек слияния, но нужно отключить галочку для пункта Use From URL напротив графы To. Таким образом, вы сможете для To выбрать ветвь, отличную от From. На этом считаю рассказ об Tortoise завершенным, а нам пора перейти к описанию еще одного клиента SVN — SmartSVN.
Итак, SmartSVN является кроссплатформенным (ага, он будет работать под linux) SVN-клиентом за счет того, что написан на java. Есть две версии SmartSVN: Foundation и Profession: первая из них бесплатная, вторую же нужно купить. В практике большинство задач успешно решаются в Foundation- версии, да и получить пробную лицензию на 30 дней не составляет никаких трудностей. Общее представление о функциональности SmartSVN: она почти не уступает TortoiseSVN. Основное отличие в идеологии построения интерфейса: Tortoise интегрируется в проводник windows, изменяет его контекстное меню, меняет иконки файлов. SmartSVN — автономное приложение, интерфейсом похожее на total commander или far (только без двух панелей). В основном окне SmartSVN находится перечисление файлов в составе проекта (см. рис. 5). Сразу расскажу о негативном опыте работы с SmartSVN: несмотря на то, что продукт создает в целом неплохое впечатление, использовать его в коллективной разработке не следует: не всегда корректно обнаруживаются конфликты с одновременным изменением файлов (в этом плане TortoiseSVN не имеет никаких нареканий). При первом запуске SmartSVN спросит, что вы хотите сделать: извлечь проект из репозитория, поместить некоторую папку внутрь репозитория или открыть существующий проект? Первые два действия не вызывают затруднений: вы указываете путь к репозиторию, затем к папке на вашем компьютере, куда будут скопированы (или откуда будут скопированы) файлы, и через несколько секунд у вас на руках будет "проект".
Если ваш проект на svn-сервере построен по правилам (trunk/tags/branches), то на стадии checkout'а будьте осторожны и обязательно укажите, что хотите импортировать не корень проекта, а конкретную папку из него (например, trunk). Этот момент важен, т.к., хотя SmartSVN вас предупредит, что импорт всего проекта нерекомендуем, но никак не запретит сделать это. И если вы допустите такую ошибку, то в последующем некоторые функции SmartSVN будут работать некорректно. В общем, помните про команду switch и не теряйтесь. Возвращаясь к SmartSVN и созданию в нем проекта: проект — это основная единица работы для SmartSVN, которая содержит параметры подключения к svn-серверу (путь к репозиторию, учетные данные для доступа). Свой рабочий день вы будете начинать с открытия проекта (меню Project -> Open), в результате чего в окне Directories (см. рис. 5 слева) будут показаны папки, входящие в состав проекта, а в основном окне отображаются файлы текущего каталога. Большинство операций с файлами/каталогами выполняется через контекстное меню (update, commit, revert…). Для открытия файла используйте двойной клик по нему (удобно, и никаких отличий от привычного интерфейса windows). Для каждого файла проекта используется своя иконка, указывающая статус файла в репозитории (для примера попробуйте отредактировать файл about1.txt, и вы увидите, как иконка сменит цвет на красный — знак того, что файл не сохранен в репозитории). После изменения файла двойной клик по нему уже не приводит к открытию файла — вместо этого появляется окно сравнения различий между текущим состоянием файла и его "Pristine Copy" (см. рис. 6). Полное перечисление иконок можно найти в справке, но в целом они интуитивно понятны.
Давайте рассмотрим методику работы с тегами/ветвями и историей правок. Несмотря на то, что в SVN понятие тегов и веток условно, разработчики SmartSVN решили создать инструменты работающими с этими понятиями не столь примитивно как "просто копия". Прежде всего, зайдите в меню Project -> Settings. Там на закладке Repository Layout находятся настройки структуры проекта в репозитории. Схема по умолчанию вполне тривиальна: папка tags хранит теги проекта, а папка branches — ветви (хотя вы можете изменить эти пути по своему усмотрению). Для создания тега/ветви используйте меню Tag/Branch -> Add Tag или Tag/Branch -> Add Branch. В появившемся диалоговом окне вы указываете название созданной ветви/тега (в случае ветки можно отметить галочку Switch to branch для того, чтобы переключить проект на свежесозданную копию). Для просмотра созданных тегов/ветвей используйте меню Tag/Branch -> Tag Browser. К сожалению, форма, в которой перечислены теги/ветви, не слишком удобна для просмотра, особенно если ваш репозиторий существует очень долго, и ветвей много, поэтому я рекомендую использовать представление ветвей/тегов в виде дерева (меню Query -> Revision Graph). Внешний вид окна дерева ревизий показан на рис. 7. Для того, чтобы детально увидеть правки, которые были выполнены в рамках некоторой ревизии, используйте меню Query -> Log. В меню Report найдется и еще несколько функций для просмотра истории правок проекта. Например, меню Query -> Change Report покажет вам список всех правок, которые были выполнены с момента последнего сохранения проекта. Для переключения между тегами/ветвями используйте меню Modify -> Switch. Наверняка пригодится и функция создания архива проекта, в ходе чего не просто будет скопирован каталог с локальной копией проекта в архив, но и удалены при этом служебные SVN-каталоги (меню Tools -> Export Backup). Несмотря на то, что SVN использует методику обеспечения коллективной работы по схеме Copy-Modify-Merge, не забывайте и про возможность работы с репозиторием по схеме Lock-Modify-Unlock (для того, чтобы блокировать или разблокировать файлы в проекте, используйте меню Lock).
На этом все. Я надеюсь, что смог выполнить свою основную задачу — рассказать о системах управления версиями документов, показать, что они совсем не страшные. Даже если вы не программист, а обычный менеджер, дизайнер, даже если вы не работаете над одними и теми же документами в команде. В любом случае вы сможете оценить преимущества стиля работы, когда есть "надежное место", хранящее все выполненные вами изменения, которое дает вам возможность создать копии файлов, переключаться между ними. Наверняка пригодится и работа с ветвями и тегами.
black-zorro@tut.by, black-zorro.com
Компьютерная газета. Статья была опубликована в номере 16 за 2008 год в рубрике программирование