- Подписка на печатную версию:
- Подписка на электронную версию:
- Подшивки старых номеров журнала (печатные версии)
LXF70:Subversion2
Материал из Linuxformat.
Subversion |
---|
|
Содержание |
Subversion. Используем клиент
Часть 2: У вас уже есть репозитарий Subversion – теперь попробуем работу с Subversion в качестве клиента. Грэм Моррисон расскажет, что надо делать.
Надеемся, после введения в работу с Subversion, вы вполне можете избавить себя от старых CVS-серверов, которые, должно быть, пылятся в какой-нибудь темной комнате. Мы показали, что перейти на новое поколение программного обеспечения для контроля версий достаточно легко (а почему бы и нет, когда уже не существует свободно распространяемой версии BitKeeper). Тем не менее, настройка и администрирование сервера Subversion потребуют определенных навыков, которые должны пригодится каждому менеджеру проектов. В этом номере мы предоставим наиболее распространенное решение для большинства разработчиков – использование Subversion в качестве клиента.
Итак, клиент – это та часть, которая получает доступ к серверу и разбирается со всеми сложными деталями, например, решает, какую версию кода выбрать, и как лучше будет исправить проблемы с конфликтами версий. Это некий интерфейс между локальной копией проекта, копиями, которые также находятся у других разработчиков, и главной версией на сервере Subversion.
Использование клиента Subversion – это также и заманчивый способ скачать последние исправления в каком-нибудь программном продукте, например, обновления безопасности и новые возможности, которые только-только появились в основной ветке. Вам придется быть внимательным, так как все, что доступно в репозитарии Subversion, постоянно находится «в движении». Каждый день можно наблюдать некоторые изменения, порой достаточно значительные. Это даже похоже на чтение книги, которую еще не закончил писать ее автор.
В этом обзоре мы сконцентрируемся на использовании клиента на этапе кодирования проекта в цикле разработке ПО, где Subversion, несомненно, примененяется наиболее часто. Руководство будет содержать те же примеры, что и в предыдущем случае. На страницах обзора вы сможете узнать о том, как загружать, изменять, добавлять файлы, а также анализировать проделанную работу, что, будет вполне достаточно для того, чтобы сделать свой личный вклад в ваш любимый проект.
Часть 1. Загрузка проекта с сервера Subversion
Первое, что надо сделать, если вы работаете над проектом, который находится под управлением сервера Subversion, - загрузить вашу собственную рабочую копию исходных текстов. Эту тему мы уже обсуждали в прошлый раз, и все, что вам потребуется вспомнить - это то, что мы использовали команду svn co:
$ svn co file:///usr/share/subres. A subres/helloworld.cpp A subres/Makefile Checkedout revision 1
Путь к хранилищу исходных текстов обычно начинается с 'svn://', что говорит о внешнем соединении с репозитарием, расположенным где-то в недрах сети Интернет. Но вы также можете указать локальный репозитарий (используя 'file://'), который мы вместе создали в прошлый раз. Работа на локальном уровне значительно упрощает процесс экспериментирования, особенно в плане обновления данных. В случае работы с удаленными репозитариями получить права на запись сложней, по вполне понятным причинам. Так что ради того, чтобы поэкспериментировать, стоит создать и настроить собственное локальное хранилище исходных текстов абстрактного проекта.
Если у вас, как вы думаете, осталась работающая копия репозитария Subversion с прошлого раза, вы можете запросто проверить это при помощи команды svn info:
$ cd subres; svn info Path: . URL: file:///usr/share/subres Repository UU ID: 6319a556-cbf4-0310-b561-de3fb53aee82 Revision: 1 Node Kind: directory Schedule: normal Last Changed Author: graham Last Changed Rev: 1 Last Changed Date: 2005-04-15 16:33:44 +0100 (Fri, 15 Apr 2005)
Если вас интересует, как Subversion справляется с различиями между вашей работающей копией и той, которая содержится в репозитарии, вы будете приятно удивлены, узнав, что ответ кроется в папке .svn – административной директории. Здесь содержится вся необходимая Subversion информация для управления различиями 2-х версий дерева исходных текстов, например, расширения файлов и даты их модификации. Практически каждое ваше действие касательно Subversion отражается в административной директории, а ее редактирование вручную приведет только к лишним проблемам.
Добираемся до репозитория (врезка)
Путь к репозитарию зависит от протокола, который указывается в начале адреса:
file:// | используется для прямого доступа к файлам, хранящимся в вашей файловый системе |
http:// | протокол WebDAV, сконфигурированный на сервере Apache |
https:// | то же самое, что и в предыдущем случае, но с добавлением SSL-шифрования |
svn:// | родной протокол Subversion, поддерживаемый демоном svnserve |
svn+ssh:// | протокол Subversion, дополненный SSH для обеспечения безопасности |
Часть 2. Изменяем файлы
После того, как вы загрузили собственную рабочую копию проекта, вы можете использовать команду svn status для проверки каких-либо изменений в репозитарии. Любой из модифицированных файлов будет представлен с буквой «M», стоящей в первой колонке. Мы отредактировали простой пример helloworld.cpp, который скачали с нашего репозитария, и теперь, команда svn status должна отразить новый статус файла:
$ svn status M helloworld.cpp
В приведенном выше примере, файл helloworld.cpp был модифицирован в локальной копии. Вы можете проверить изменения между вашей локальной копией и копией в репозитарии, набрав команду svn diff. Эта команда работает в точности так же, как и всем известная команда diff, отображая также пути к двум деревьям исходных текстов.
$ svn diff Index: helloworld.cpp ========================================== --- helloworld.cpp (revision 1) +++ helloworld.cpp (working copy) @@ -5,6 +5,7 @@ int main(int argc, char *argv[]) { cout << "Hello World!" << endl; + cout << «Это дополнение» << endl; return(0); }
Строка «Это дополнение» была помечена символом «+» как измененная версия. По мере изменения файла, мы будем копировать новую версию в основной репозитарий, чтобы другие разработчики тоже могли пользоваться нашими нововведениями. Так же, как и в CVS, это делается командой svn commit, сопровождаемой комментарием для описания вносимых вами изменений. Хорошим тоном считается вносить как можно больше мелких изменений, используя вышеупомянутые комментарии для описания их сути. Таким образом, в дальнейшем будет проще отследить изменения, которые привели к неправильной работе программы, если что-то пойдет не так (а когда-нибудь это неизбежно произойдет).
$ svn commit Sending helloworld.cpp Transmitting file data . Committed revision 2.
Любому разработчику, который работает с этим же репозитарием и хотел бы получить файл с учетом ваших изменений, потребуется обновить свою рабочую копию, используя команду svn update. После этого у него будет точно такая же копия дерева исходных текстов, что и у вас.
$ svn update U helloworld.cpp Updated to revision 2.
Подсказка (врезка)
Графическое сравнение модификаций Нетрудно заметить пару отличий между двумя файлами, но ведь изменения могут быть и более сложными, и их может быть намного больше. В этом случае вы можете облегчить себе жизнь, используя графический просмотрщик отличий. Программа KDiff3 может показывать отличия нескольких файлов за один раз и даже поддерживает слияние. У KDE есть собственный просмотрщик под названием Kompare, который автоматически загружается при попытке открыть файл-патч. Для ясности, программа также показывает оригинальный файл с левой стороны, и подсвечивает, в каком именно месте он был модифицирован. С другой стороны показывается новая версия того же самого файла.
Реальный пример: обновляем Kopete при помощи Subversion (врезка)
Kopete – клиент для мгновенного обмена сообщениями, предлагаемый по умолчанию в KDE. Проблема в том, что его часто приходится обновлять. Несколько протоколов обмена сообщениями, используемых Kopete для связи с сервером и другими клиентами, разрабатываются путем инженерного анализа. Это единственный способ предоставить совместимость с такими протоколами, как AOL или MSN Messenger, которые порой таинственно и без огласки изменяются. Разработчики Kopete анализируют поток трафика между клиентом и сервером, впоследствии выпуская очередные обновления, которые сразу становятся доступными в репозитарии Subversion, а не в виде отдельных пакетов, так как на их организацию и сборку требуется определенное время.
Первое, что надо сделать для получения обновления к Kopete – подключиться к анонимному серверу KDE Subversion, который доступен для всех, кто осмелится ввести следующие команды:
$ svn co -N svn://anonsvn.kde.org/home/kde/trunk/ KDE/ kdenetwork
Вы получите много страниц кода, которые сопровождаются следующими строками:
Checked out revision 416028.
Программа Kopete является частью kdenetwork, а значит, она может быть найдена в соответствующей директории. Флаг –N в команде выше используется для скачивания отдельного каталога, а не всей ветки KDE со всеми ее поддиректориями. В результате загружаются файлы, относящиеся только к директории kdenetwork. Следующим шагом будет получение исходных текстов самой Kopete:
$ cd kdenetwork $ svn update kopete A kopete ... Updated to revision 416064.
Команда svn update загружает любые изменения между локальной копией и той, что хранится в репозитарии. Так как у нас сейчас нет локальной версии, результатом этой команды будет загрузка всей директории kopete. Каждый файл или директория отражаются в стандартном потоке вывода по мере их загрузки, обозначенные буквой 'A' в начале строки ('U' при обновлении файла и 'D' при удалении). Конечное сообщение всегда содержит номер ревизии, которую вы только что загрузили.
В репозитариях программного обеспечения обычно уже содержатся готовые сценарии, необходимые для компиляции и установки проекта, так что следующим шагом будет загрузка необходимых скриптов с директории kde-common. После этого мы можем вызвать команды для компиляции локальной копии программы Kopete:
$ svn co svn://anonsvn.kde.org/home/kde/trunk/KDE/kde-common/admin $ make -f Makefile.cvs $ ./configure --prefix=/usr $ make $ su -c "make install"
Часть 3. Вносим изменения
Если два разработчика работают над одним и тем же файлом-источником (так обычно и бывает), и второй пытается добавить свои изменения, в то время как первый уже это сделал, Subversion выдаст сообщение о конфликте версий.
$ svn commit Sending helloworld.cpp svn: Commit failed (details follow): svn: Out of date: 'helloworld.cpp' in transaction '4' svn: Your commit message was left in a temporary file: svn: '/home/graham/build/svn2/subres/svn-commit.tmp'
На этом примере мы видим ошибку, так как файл, который мы пытались обновить на сервере, уже был обновлен кем-то еще. Как вы видите, Subversion сделал копию комментария, описывающего изменение, так что вам, по крайней мере, не придется печатать ваш комментарий снова. Используя команду svn diff, Subversion покажет в каком именно месте происходит конфликт версии:
$ svn diff Index: helloworld.cpp ========================================== --- helloworld.cpp (revision 2) +++ helloworld.cpp (working copy) @@ -5,7 +5,7 @@ int main(int argc, char *argv[]) { cout << "Hello World!" << endl; - cout << "Это дополнение." << endl; + cout << "Еще одно дополнение" << endl; return(0); }
Конфликт расположен во второй строке cout, которая была изменена первым разработчиком независимо от второго. Для разрешения проблемы следует обновить локальную копию второго разработчика командой svn update. Чтобы сделать жизнь проще, вы можете просмотреть комментарии к каждому изменению, используя команду svn log, а также копии файлов с расширениями, в которых отражена версия исправления, например r1, r2, и так далее:
$ ls helloworld.cpp helloworld.cpp.r2 Makefile helloworld.cpp.mine helloworld.cpp.r3 svn-commit.tmp
Файл helloworld.cpp существует в различных версиях: версия репозитария и версии с исправлениями, например helloworld.cpp.r2 – предыдущая версия перед обновлением, а helloworld.cpp.r3 – версия, которая в настоящее время хранится в репозитарии. Subversion не позволит вам добавить файл в репозитарий, пока не устранится конфликт версий.
Вы также можете выбрать следующий вариант: скопировать один из временных файлов поверх helloworld.cpp, что позволит сделать локальную версию эквивалентной пре- или пост- обновленной версии (в нашем случае это файлы helloworld.cpp.r2 и helloworld.cpp.r3). Вы можете использовать команду svn revert для того, чтобы вернуть локальную копию к предыдущей версии, либо же вручную разрешить этот конфликт.
Итак, на нашем примере содержимое файла helloworld.cpp выглядит следующим образом:
#include <iostream> using namespace std; int main(int argc, char *argv[]) { cout << "Hello World!" << endl; <<<<<<< .mine cout << "Второе дополнение." << endl; ========================================== cout << "Первое дополнение." << endl; >>>>>>> .r3 return(0); }
Символы '<','>' и '=' - маркеры, обозначающие конфликт. Текст между символами '<' и '=' представляет собой локальное изменение, которое и послужило причиной для конфликта, потому он помечен как 'mine' (мое). В секции после символов '=' показан номер версии, которая сейчас доступна в репозитарии (согласно метке, это третья ревизия). Нам потребуется отредактировать код, чтобы постараться совместить оба изменения – вероятно, изменив текст на что-то вроде "Оба дополнения":
cout << "Hello World!" << endl; cout << "Оба дополнения." << endl; return(0);
Следующий шаг - дать Subversion знать, что мы разрешили конфликт, используя команду svn resolved вместе с самим файлом. Это также должно удалить два временных файла, что приведет вашу рабочую копию в состояние, достаточное для фиксации.
$ svn resolved helloworld.cpp Resolved conflicted state of 'helloworld.cpp' $ svn commit Sending helloworld.cpp Transmitting file data . Committed revision 4. $ svn update At revision 4.
Часть 4. Контроль над изменениями в проекте
Существует много методов получения из репозитария информации о статусе проекта. Одна из наиболее употребимых команд при возникновении конфликта – svn log, которая выводит на экран список комментариев к последним изменениям. Например, журнал для файла helloworld.cpp выглядит так:
$ svn log --------------------------------------------------------- r4 | graham | 2005-05-23 14:49:53 +0100 (Mon, 23 May 2005) | 2 lines Конфликт решен путем совмещения двух изменений. --------------------------------------------------------- r3 | rebecca | 2005-05-23 12:39:56 +0100 (Mon, 23 May 2005) | 2 lines Изменился текст во второй строке вывода. ----------------------------------------------------------- r2 | graham | 2005-05-23 12:19:36 +0100 (Mon, 23 May 2005) | 2 lines Добавление второй строки вывода.
Использование комментариев для каждого изменения позволит вам быстро и точно опознать, что могло пойти не так. Вы можете вычислить, на ком лежит ответственность за неправильную работу программы, или к кому вам следует обратиться для решения возникшей проблемы. Каждая запись в журнале начинается с номера изменения, затем следует имя разработчика, время внесения изменений и комментарий к ним.
Еще одна команда, которая будет вам полезна при разрешении конфликтов – svn cat. Подобно двойнику из командной строки – команде 'cat', которая выводит содержимое файла, svn cat отображает содержимое файла, который на данный момент используется на сервере Subversion, чтобы вы могли проверить все отличия между этим файлом и вашей локальной копией. Самое интересное, что вы также можете явно указать нужную версию и узнать, как изменился код программы.
$ svn cat --revision 2 helloworld.cpp #include <iostream> using namespace std; int main(int argc, char *argv[]) { cout << "Hello World!" << endl; cout << "Это добавление." << endl; return(0); }
Выше мы попросили сервер Subversion показать вторую ревизию файла helloworld.cpp (состояние перед конфликтом). Используйте опцию --revision вместе с командой svn list' для того, чтобы вывести на экран файлы, содержащиеся в репозитарии для каждой ревизии. Однако, лучше всего использовать эту опцию вместе с командой svn diff – это позволит вам сравнить две ревизии. Мы могли бы, например, увидеть, что именно изменилось в четвертой модификации файла helloworld.cpp по сравнению с первой.
$ svn diff --revision 1:4 helloworld.cpp Index: helloworld.cpp ======================== --- helloworld.cpp (revision 1) +++ helloworld.cpp (revision 4) @@ -5,6 +5,7 @@ int main(int argc, char *argv[]) { cout << "Hello World!" << endl; + cout << "Оба модифицированных дополнения." << endl; return(0); }
Итак, различие между первой и четвертой ревизиями файла helloworld.cpp – это строка «Оба дополнения», добавленная в предыдущем этапе данного руководства. Так как вывод команды svn diff такой же, как и у команды diff, первая могла бы быть использована для того, чтобы генерировать вывод, совместимый с приложениями, наподобие Kompare из KDE – для графического сравнения различий между двумя модификациями файлов:
$ svn diff --revision 1:4 helloworld.cpp | kompare -o -
Теперь вы должны чувствовать себя вполне уверено в работе над проектом, находящимся под управлением Subversion. Проект KDE, например, недавно перешел с CVS на Subversion. Теперь можно смело загружать исходные тексты KDE и смотреть что к чему - это поможет вам без труда войти в цикл его развития.
Работа с патчами (врезка)
Патч (patch) - это список изменений между двумя версиями одного проекта, который бывает полезен по двум причинам: во-первых, он позволяет работать над проектом, когда у вас нет прав на его запись; во-вторых, с помощью патча можно дать протестировать проект с вашими изменениями без их внесения в основную ветвь разработки.
По сути, патч не представляет из себя что-то действительно сложное – это всего лишь обычный вывод команды diff, которая сравнивает два различных файла. Интересной представляется программа под названием patch, изначально написана Ларри Уоллом (Larry «Perl» Wall), которая применяет изменения из файла-патча к другому файлу. Вы можете с легкостью создать файл-патч, используя Subversion, направив выходной поток от команды svn diff в файл:
$ svn diff > имя_файла-патча
Теперь вы можете послать результат работы этой команды в виде файла-патча какому-нибудь разработчику, которому требуются ваши изменения, либо просто тому, кто хочет их протестировать. Разработчик в дальнейшем может применить ваши изменения к его локальной версии, используя команду patch, находясь в том же каталоге, где был создан патч:
$ patch –p0 < имя_файла-патча