МУ ОффС и УРП
.pdfВетвление (branching) SVN — это именно то, что стоит за этим словом: создание ветвей. Ничем больше это понятие не обладает.
Что такое ветка?
Основная идея ветки — направление разработки, которое существует независимо от другого направления, однако имеет с ним общую историю, если заглянуть немного в прошлое. Ветка берет начало как копия чего-либо и двигается от этого момента, создавая свою собственную историю.
Создание ветки
Команда svn copy может оперировать с двумя URL напрямую. $ svn copy http://svn.example.com/repos/calc/trunk \
http://svn.example.com/repos/calc/branches/my-calc-branch \ -m "Creating a private branch of /calc/trunk."
Committed revision 341.
Легкие копии
Каждая правка является «легкой копией» предыдущей правки с несколькими элементами, измененными в ней.
Работа с веткой
После создания ветки проекта можно создать новую рабочую копию для начала ее использования:
$ svn checkout http://svn.example.com/repos/calc/branches/my-calc-
branch
Amy-calc-branch/Makefile
Amy-calc-branch/integer.c
Amy-calc-branch/button.c Checked out revision 341.
В этой рабочей копии нет ничего особенного; она является
просто отражением другой директории хранилища.
Subversion прослеживает историю ветки во времени полностью, в том числе пересекая точку создания копии.
Ключевые идеи, стоящие за ветками:
−ветки в Subversion существуют в хранилище как обычные директории файловой системы. Просто они содержат дополнительную информацию о своей истории;
−Subversion не имеет такого понятия, как ветка, — есть только копии. При копировании директории результирующая директория становится «веткой» только потому что вы рассматриваете ее таким образом.
Копирование изменений между ветками
9
Разработчики могут делиться изменениями по ходу работы. Вы можете решать вплоть до отдельного изменения, стоит ли им делиться; Subversion предоставляет возможность выборочного «копирования» изменений между ветками. А когда ваша ветка будет полностью закончена, полный набор изменений ветки может быть скопирован обратно в основную ветку.
Копирование отдельных изменений
Основа копирования - svn merge. Эта команда - родственник команды svn diff. Обе команды способны сравнивать любые два объекта в хранилище и показывать изменения. Например, вы можете попросить svn diff показать все изменения, сделанные другим пользователем в правке 344.
Команда svn merge ведет себя практически полностью идентично. Но вместо вывода различий на терминал применяет их к рабочей копии в виде локальных изменений:
$ svn merge -r 343:344 http://svn.example.com/repos/calc/trunk U integer.c
$ svn status M integer.c
Вывод команды svn merge показывает, что к вашей копии integer.c был применен патч.
По другому сценарию integer.c может оказаться в состоянии конфликта. Вам необходимо будет с помощью стандартной процедуры решить конфликт либо отказаться от объединения, отменив локальные изменения командой svn revert.
После просмотра результата объединения изменений можно их зафиксировать (svn commit). После этого изменения будут внесены в вашу ветку хранилища. В терминах контроля это называют
портированием изменений.
При фиксации локальных изменений убедитесь, что в сообщении упоминается о портировании отдельных изменений из одной ветки в другую. Например:
$ svn commit -m "integer.c: ported r344 (spelling fixes) from trunk." Sending integer.c
Transmitting file data . Committed revision 360.
Ключевые понятия, стоящие за слиянием
Вы увидели примеры использования svn merge, продолжим рассмотрение. Если вы не понимаете, как, собственно, работает слияние, то в этом вы не одиноки. Многие пользователи (особенно те, для которых управление версиями в новинку) поначалу путаются в правильности записи этой команды и в том, как и когда эту функцию
10
следует использовать. Очень просто понять механизм того, как именно ведет себя svn merge.
Команда принимает три аргумента:
−начальное дерево хранилища (как правило, называемое левой частью при сравнении);
−конечное дерево хранилища (как правило, называемое правой частью при сравнении);
−рабочую копию для применения отличий в виде локальных изменений (как правило, называемую целью слияния).
Когда эти три аргумента указаны, сравниваются два дерева и результирующие различия применяются к целевой рабочей копии в виде локальных изменений. После того как команда выполнена, результат не будет отличаться от того, как если бы вы вручную редактировали файлы или многократно выполняли команды svn add или svn delete самостоятельно. Если результат устраивает, его можно зафиксировать. Если результат не устраивает, просто отмените (svn revert) все сделанные изменения.
Правила записи svn merge позволяют указывать три необходимых аргумента довольно гибко. Вот несколько примеров:
$ svn merge http://svn.example.com/repos/branch1@150 \ http://svn.example.com/repos/branch2@212 \ my-working-copy
$ svn merge -r 100:200 http://svn.example.com/repos/trunk my- working-copy
$ svn merge -r 100:200 http://svn.example.com/repos/trunk
В первом примере записи все три аргумента явно указаны, указываются деревья в форме URL@REV и указывается целевая рабочая копия. Второй пример записи может использоваться для краткости, в ситуациях, когда сравниваются две разных правки по одному и тому же URL. Последний пример демонстрирует возможность не указывать целевую рабочую копию, при этом по умолчанию используется текущая директория.
Конфликты при объединении
Так же как и команда svn update, svn merge внедряет изменения в рабочую копию. А следовательно, тоже может создавать конфликты. Однако конфликты, создаваемые svn merge, иногда отличаются и эти отличия рассмотрены в данном разделе.
Вначале будем считать, что рабочая копия не имеет локальных изменений. При обновлении (svn update) до конкретной правки изменения, отправляемые сервером, будут всегда «без проблем»
11
внедряться в рабочую копию. Сервер создает дельту, сравнивая два дерева: виртуальный снимок рабочей копии и дерево файлов, которое вас интересует. С учетом того, что левая часть сравнения полностью эквивалентна тому, что вы уже имеете, дельта гарантированно правильно конвертирует рабочую копию в правую часть сравнения.
Однако svn merge не может этого гарантировать и может вести себя более хаотично: пользователь может запросить сервер сравнить любые два дерева файлов, даже такие, которые не имеют отношения к рабочей копии. Из этого следует большое количество потенциальных человеческих ошибок. Пользователи иногда будут сравнивать два ошибочных дерева, создавая дельту, которая не сможет правильно внедриться. Svn merge будет пытаться внедрить по возможности больше различий, но иногда это будет невозможно.
Учитывать или игнорировать происхождение
При общении разработчиков, использующих Subversion, очень часто можно услышать упоминание термина происхождение. Это слово используется для описания отношений между двумя объектами хранилища: если между ними есть связь, тогда говорят, что один объект является предком другого.
Например, предположим, что фиксируется правка 100, в которой содержатся изменения файла foo.c. В этом случае файл foo.c@99 является предком файла foo.c@100. С другой стороны, можно допустить, что в правке 101 вы фиксируете удаление foo.c, а затем в правке 102 добавляете новый файл с таким же именем. В таком случае файлы foo.c@99 и foo.c@102 могут выглядеть так, как будто они имеют друг к другу отношение (у них одинаковый путь), однако на самом деле являются полностью независимыми объектами хранилища. Они не имеют ни общей истории, ни общих «предков».
Важные отличия между svn diff и svn merge: первая команда игнорирует происхождение, в то время как вторая его учитывает. Например, если попросить svn diff сравнить правки 99 и 102 файла foo.c можно увидеть построчное сравнение; команда diff слепо сравнивает два пути. А вот если вы попросите svn merge сравнить те же объекты, то Subversion предупредит вас о том, что они не связаны друг с другом, и сначала попытается удалить старый файл, а затем добавить новый; вывод команды покажет удаление с последующим добавлением:
D foo.c A foo.c
В большинстве случаев при объединении сравниваются деревья, имеющие родственную связь, и по умолчанию svn merge рассчитывает на это. Однако иногда вам будет нужно, чтобы команда merge
12
сравнила два не связанных дерева файлов. Например, у вас может быть два импортированных дерева, содержащих исходный код релизов программных проектов от сторонних поставщиков. Если попросить svn merge сравнить два этих дерева, вы увидите, что первое дерево будет полностью удалено, а затем будет полностью добавлено второе.
В подобных ситуациях вам нужно, чтобы команда svn merge выполняла сравнение, основанное только на пути, без учета любых отношений между файлами и директориями. Добавьте опцию --ignore- ancestry при записи команды объединения, после чего эта команда будет вести себя так же, как svn diff. (И наоборот, опция --notice- ancestry будет заставлять svn diff вести себя как команда merge.)
Полное объединение двух веток
Предположим, прошло несколько дней, и как в главную линию разработки, так и в вашу личную ветку было внесено множество изменений. Допустим, что работу над своей веткой вы завершили; добавление функциональности или исправление ошибок закончены, и теперь вы хотите объединить все изменения из своей ветки с главной линией разработки.
Как же в этом случае нужно использовать svn merge? Помните о том, что эта команда сравнивает два дерева и применяет различия к рабочей копии. Поэтому для того, чтобы было, к чему применять изменения, необходимо иметь рабочую копию главной линии разработки. Будем считать, что у вас под рукой имеется такая (полностью обновленная) копия либо вы только что создали новую рабочую копию /calc/trunk.
С учетом того, что svn merge работает так же, как svn diff, сравнение последние версии главной линии разработки и вашей ветки покажет изменения, сделанные не только в вашей ветке. Такое сравнение покажет слишком много изменений: будет показано не только то, что добавлялось в вашей ветке, но и то, что удалялось в главной линии разработки и не удалялось в вашей ветке.
Для выделения только тех изменений, которые были сделаны в вашей ветке, нужно сравнивать начальное и конечное состояния ветки. Воспользовавшись svn log для ветки, можно узнать, что она была создана в правке 341. А для определения конечного состояния ветки можно просто использовать правку HEAD. Это значит, что вам нужно сравнить правки 341 и HEAD директории с веткой и применить различия к рабочей копии главной линии разработки.
Отмена изменений
Еще одним типичным применением для svn merge является откат изменений, которые уже были зафиксированы. Предположим, вы спокойно работаете в рабочей копии /calc/trunk и выясняете, что изме-
13
нения, сделанные в правке 303, которые изменили integer.c, полностью ошибочны. Вы можете воспользоваться командой svn merge для «отмены» изменений в своей рабочей копии, после чего зафиксировать локальные изменения в хранилище. Все, что нужно сделать, это указать обратные отличия:
$ svn merge -r 303:302 http://svn.example.com/repos/calc/trunk U integer.c
$ svn status M integer.c $ svn diff
…
# verify that the change is removed
…
$ svn commit -m "Undoing change committed in r303." Sending integer.c
Transmitting file data . Committed revision 350.
Восстановление удаленных элементов
Отличным свойством системы контроля версий является то, что информация никогда не теряется. При удалении файла или директории, элемент исчезает из правки HEAD, но продолжает существовать в более ранних правках. Одним из наиболее частых вопросов, задаваемых новыми пользователями, является такой: «Как мне вернуть назад свой файл или директорию?»
Первым шагом является определение того, какой именно элемент вы пытаетесь восстановить. Удачным является представление каждого объекта в хранилище существующим в двухмерной системе координат. Первой координатой является отдельное дерево правок, второй координатой является путь в этом дереве. Таким образом, каждая версия файла или директории может быть представлена конкретной парой координат.
$ cd parent-dir
$ svn log --verbose
…
-------------------------------------------------------
r808 | joe | 2003-12-26 14:29:40 -0600 (Fri, 26 Dec 2003) | 3 lines Changed paths:
D /calc/trunk/real.c M /calc/trunk/integer.c
Added fast fourier transform functions to integer.c.
14
Removed real.c because code now in double.c.
…
В примере предполагается, что вы ищете удаленный файл real.c. Просмотрев логи родительской директории, вы определите, что этот файл был удален в правке 808. Следовательно, последняя существовавшая версия файла была в правке, предшествующей этой. Вывод: необходимо из правки 807 восстановить путь /calc/trunk/real.c.
Поиск был сложной задачей. Теперь, когда известно, что нужно восстановить, есть две возможности.
Одним из вариантов является использование svn merge для применения правки 808 «в обратном направлении». Это приведет к эффекту повторного добавления файла real.c в виде локальных изменений. Файл будет запланирован для добавления и после фиксации будет опять присутствовать в HEAD.
При втором, более целевом методе svn merge вообще не используется, а вместо него применяется команда svn copy. Просто скопируйте определенные «парой координат» правку и путь из хранилища в рабочую копию:
$ svn copy --revision 807 \ http://svn.example.com/repos/calc/trunk/real.c ./real.c
$ svn status A + real.c
$ svn commit -m "Resurrected real.c from revision 807, /calc/trunk/real.c."
Adding real.c Transmitting file data . Committed revision 1390.
Знак плюс в статусе показывает, что элемент не просто запланирован для добавления, а запланирован для добавления «с историей». Subversion запоминает, откуда он был скопирован. В будущем запуск svn log для этого файла будет пересекать восстановление файла и всю историю, предшествующую правке 807. Другими словами, новый файл real.c на самом деле не является новым; он является прямым наследником оригинального, удаленного файла.
Хотя наш пример показывает, как восстанавливать файл, обратите внимание на то, что этот подход работает также и для восстановления удаленных директорий.
3. Практическая часть
1.Создайте рабочую директорию trunk c тремя текстовыми файлами file1.txt, file2.txt, file3.txt
2.Создайте 3 ветки, в которых будете работать вы, Петров и
Сидоров.
15
3.Пусть вы сделаете изменения в файле file1.txt, Петров сделает изменения в file2.txt, а Сидоров сделает изменения в файлах file1.txt и file2.txt. Все должны зафиксировать изменения.
4.Посмотрите на историю изменений для вашей копии файла file1.txt. После этого посмотрите на историю изменений этого же файла для Сидорова. Сравните истории.
5.Скопируйте изменения, сделанные Сидоровым в файле file1.txt, в свою ветку. Зафиксируйте изменения.
6.Скопируйте изменения, сделанные Сидоровым в файле file2.txt, в ветку Петрова. Посмотрите, изменился ли файл. Отмените изменения.
7.Отмените изменения, сделанные в вашей ветке.
8.Выполните полное объединение своей ветки с trunk.
4. Требования к отчету
В отчете необходимо представить:
−исходные текстовые файлы (не менее 30 строк текста);
−схему организации работы с ветками;
−цель создания ветки;
−файлы, которые войдут в новую ветку;
−условия копирования изменений в процессе работы с
веткой;
−условия отмены изменений;
−условие полного слияния версий.
Все выполненные команды:
−тексты команд;
−реакция системы на выполненную команду (терминальный вывод);
−номер ревизии;
−важные с точки зрения версионирования фрагменты файлов, находящихся под контролем;
−граф ревизий проекта.
5.Контрольные вопросы
1.Как создать ветку в Subversion?
2.Что такое «Легкие копии»?
3.В чем разница между командами svn diff и svn merge?
4.Какие ветки называются функциональными?
5.Расскажите о ключевых идеях веток.
16
Лабораторная работа № 3
Основы создания документации в формате DocBook
1. Цель работы
Получение основных навыков создания документации в формате DocBook, изучение основных компонентов DocBook и приемов работы.
Продолжительность работы: 4 часа.
2. Теоретическая часть
XML формат DocBook является одним из основных стандартов для разработки технической документации. Несмотря на наличие большого количества текстовых редакторов, таких как Open Office Writer, Microsoft Word, позволяющих создавать сложные текстовые документы с возможностью форматирования и интегрирования медиа ресурсов, практика создания документации, написания статей и книг выявляет их главный недостаток – большие затраты времени на форматирование документов. Использование специальных шаблонов с блокировкой ручного изменения форматов шрифтов и стилей не решает проблему. Копирование и перенос фрагментов текста между документами часто приводят к переносу элементов форматирования между документами и смешению стилей. Использование режима специальной вставки без форматирования в редакторах Open Office Writer или Microsoft Word частично решает данную проблему, но при создании больших документов на форматирование впустую затрачивается слишком много времени. Для упрощения и удешевления процесса допечатной подготовки некоторые издательства требуют оформление рукописей в формате DocBook.
Второй проблемой является бинарный формат хранения файлов, который плохо подходит для совместной работы нескольких человек над документом. Если документ хранится в удаленном хранилище (например, CVS или SVN репозитарии), то приходится заново закачивать полную копию всего документа, если он был изменен, что увеличивает затраты на сетевой трафик. Одновременное изменение несколькими пользователями и слияние таких измененных документов в один весьма проблематичны.
XML формат DocBook решает обе вышеописанные проблемы. В настоящее время существуют довольно удобные альтернативные редакторы, позволяющие работать с форматом DocBook, среди которых есть и бесплатные версии.
Основные преимущества формата DocBook:
17
¾унифицированное форматирование, которое задается с помощью унифицированного предопределенного набора тегов, на основе которых в последующем производится трансформирование документа в произвольный формат посредством преобразования на основе таблиц стилей. Таблицы стилей (stylesheet) представляют собой написанные на специальных языках (XSL — Extended Specification Language или DSSSL — Document Style Semantics and Specification Language) файлы скриптов, которые описывают формат вывода различных элементов документа (используемые шрифты, форматирование, нумерацию страниц и т.д.). Сами документы DocBook не содержат форматированного содержимого (текста, разметки страниц и т. д.). Использование фиксированного набора тегов гарантирует, что конечный документ будет корректно сформирован независимо от количества авторов;
¾работа с системами контроля версий, которая заключается в том, что можно легко контролировать всю историю изменения любых частей документов, так как они хранятся в обычных текстовых XML файлах. Жесткая спецификация на XML формат упрощает процесс слияния документов при совместной работе нескольких авторов;
¾модульность, позволяющая легко разделить документ на независимые части для упрощения работы над большими документами. При работе удобно разбивать документ на главы, причем широко практикуется создание документов одновременно на нескольких языках;
¾многовариантное представление документов,
позволяющее трансформировать один и тот же XML документ в формате DocBook во множество различных форматов (например, PDF, RTF, HTML и Eclipse Help). Стандартная поставка DocBook включает примеры скриптов и таблиц стилей для трансформации в PDF, HTML
иEclipse Help форматы.
DocBook требует планирования структуры создаваемого текста. Хотя формально DocBook в состоянии обеспечивать разметку некоторых элементов бесструктурного текста, наиболее эффективно применение DocBook именно для текстов с предварительно продуманной структурой (структура может изменяться в процессе работы над документом).
Обычный текст (как в редакторе «Блокнот» или TextPad), текст, подготавливаемый в текстовых процессорах типа Microsoft Word, текст, подготавливаемый в виде HTML-страниц, в общем случае либо бесструктурный, либо (в случае Word/HTML) содержит смесь струк-
18
