Журнал LinuxFormat - перейти на главную

LXF70:Subversion2

Материал из Linuxformat
(Различия между версиями)
Перейти к: навигация, поиск
(часть 3)
м (шаблон)
 
(не показаны 2 промежуточные версии 2 участников)
Строка 1: Строка 1:
 +
{{Цикл/Subversion}}
 +
 
== Subversion. Используем клиент ==
 
== Subversion. Используем клиент ==
''ЧАСТЬ 2: У вас уже есть репозитарий Subversion – теперь попробуем работу с Subversion в качестве клиента. Грэм Моррисон расскажет, что надо делать.''
+
''Часть 2: У вас уже есть репозитарий Subversion – теперь попробуем работу с Subversion в качестве клиента. Грэм Моррисон расскажет, что надо делать.''
  
 
Надеемся, после введения в работу с ''Subversion'', вы вполне можете избавить себя от старых ''CVS''-серверов, которые, должно быть, пылятся в какой-нибудь темной комнате. Мы показали, что перейти на новое поколение программного обеспечения для контроля версий достаточно легко (а почему бы и нет, когда уже не существует свободно распространяемой версии ''BitKeeper''). Тем не менее, настройка и администрирование сервера ''Subversion'' потребуют определенных навыков, которые должны пригодится каждому менеджеру проектов. В этом номере мы предоставим наиболее распространенное решение для большинства разработчиков – использование ''Subversion'' в качестве клиента.
 
Надеемся, после введения в работу с ''Subversion'', вы вполне можете избавить себя от старых ''CVS''-серверов, которые, должно быть, пылятся в какой-нибудь темной комнате. Мы показали, что перейти на новое поколение программного обеспечения для контроля версий достаточно легко (а почему бы и нет, когда уже не существует свободно распространяемой версии ''BitKeeper''). Тем не менее, настройка и администрирование сервера ''Subversion'' потребуют определенных навыков, которые должны пригодится каждому менеджеру проектов. В этом номере мы предоставим наиболее распространенное решение для большинства разработчиков – использование ''Subversion'' в качестве клиента.
Строка 12: Строка 14:
 
вы сможете узнать о том, как загружать, изменять, добавлять файлы, а также анализировать проделанную работу, что, будет вполне достаточно для того, чтобы сделать свой личный вклад в ваш любимый проект.
 
вы сможете узнать о том, как загружать, изменять, добавлять файлы, а также анализировать проделанную работу, что, будет вполне достаточно для того, чтобы сделать свой личный вклад в ваш любимый проект.
  
=== Часть 1 - загрузка проекта с сервера Subversion ===
+
=== Часть 1. Загрузка проекта с сервера Subversion ===
 
'''Первое, что надо сделать, если вы работаете над проектом''', который находится под управлением сервера ''Subversion'', - загрузить вашу собственную рабочую копию исходных текстов. Эту тему мы уже обсуждали в прошлый раз, и все, что вам потребуется вспомнить - это то, что мы использовали команду '''svn co''':
 
'''Первое, что надо сделать, если вы работаете над проектом''', который находится под управлением сервера ''Subversion'', - загрузить вашу собственную рабочую копию исходных текстов. Эту тему мы уже обсуждали в прошлый раз, и все, что вам потребуется вспомнить - это то, что мы использовали команду '''svn co''':
  
Строка 22: Строка 24:
 
</code>
 
</code>
  
Путь к хранилищу исходных текстов обычно начинается с ‘svn://, что говорит о внешнем соединении с репозитарием, расположенным где-то в недрах сети Интернет. Но вы также можете указать локальный репозитарий (используя ‘file://), который мы вместе создали в прошлый раз. Работа на локальном уровне значительно упрощает процесс экспериментирования, особенно в плане обновления данных. В случае
+
Путь к хранилищу исходных текстов обычно начинается с 'svn://', что говорит о внешнем соединении с репозитарием, расположенным где-то в недрах сети Интернет. Но вы также можете указать локальный репозитарий (используя 'file://'), который мы вместе создали в прошлый раз. Работа на локальном уровне значительно упрощает процесс экспериментирования, особенно в плане обновления данных. В случае
 
работы с удаленными репозитариями получить права на запись сложней, по вполне понятным причинам. Так что ради того, чтобы поэкспериментировать, стоит создать и настроить собственное локальное хранилище исходных текстов абстрактного проекта.
 
работы с удаленными репозитариями получить права на запись сложней, по вполне понятным причинам. Так что ради того, чтобы поэкспериментировать, стоит создать и настроить собственное локальное хранилище исходных текстов абстрактного проекта.
  
Строка 62: Строка 64:
 
|}
 
|}
  
=== Часть 2 - изменяем файлы ===
+
=== Часть 2. Изменяем файлы ===
'''После того, как вы загрузили собственную рабочую копию проекта''', вы можете использовать команду '''svn status''' для проверки каких-либо изменений в репозитарии. Любой из модифицированных файлов будет представлен с буквой '''M''', стоящей в первой колонке. Мы отредактировали простой пример '''helloworld.cpp''', который скачали с нашего репозитария, и теперь, команда ''svn status'' должна отразить новый статус файла:
+
'''После того, как вы загрузили собственную рабочую копию проекта''', вы можете использовать команду '''svn status''' для проверки каких-либо изменений в репозитарии. Любой из модифицированных файлов будет представлен с буквой '''«M»''', стоящей в первой колонке. Мы отредактировали простой пример '''helloworld.cpp''', который скачали с нашего репозитария, и теперь, команда ''svn status'' должна отразить новый статус файла:
  
 
<code>
 
<code>
Строка 82: Строка 84:
 
  int main(int argc, char *argv[])
 
  int main(int argc, char *argv[])
 
  {
 
  {
  cout << “Hello World!<< endl;
+
  cout << "Hello World!" << endl;
 
  + cout << «Это дополнение» << endl;
 
  + cout << «Это дополнение» << endl;
 
  return(0);
 
  return(0);
Строка 88: Строка 90:
 
</code>
 
</code>
  
Строка «'''Это дополнение'''» была помечена символом '''+'''как измененная версия. По мере изменения файла, мы будем копировать новую версию в основной репозитарий, чтобы другие разработчики тоже могли пользоваться нашими нововведениями. Так же, как и в ''CVS'', это делается командой '''svn commit''', сопровождаемой комментарием для описания вносимых вами изменений. Хорошим тоном считается вносить как можно больше мелких изменений, используя вышеупомянутые комментарии для описания их сути. Таким образом, в дальнейшем будет проще отследить изменения, которые привели к неправильной работе программы, если что-то пойдет не так (а когда-нибудь это неизбежно произойдет).
+
Строка «'''Это дополнение'''» была помечена символом '''«+»''' как измененная версия. По мере изменения файла, мы будем копировать новую версию в основной репозитарий, чтобы другие разработчики тоже могли пользоваться нашими нововведениями. Так же, как и в ''CVS'', это делается командой '''svn commit''', сопровождаемой комментарием для описания вносимых вами изменений. Хорошим тоном считается вносить как можно больше мелких изменений, используя вышеупомянутые комментарии для описания их сути. Таким образом, в дальнейшем будет проще отследить изменения, которые привели к неправильной работе программы, если что-то пойдет не так (а когда-нибудь это неизбежно произойдет).
  
 
<code>
 
<code>
Строка 138: Строка 140:
 
</code>
 
</code>
  
Команда '''svn update''' загружает любые изменения между локальной копией и той, что хранится в репозитарии. Так как у нас сейчас нет локальной версии, результатом этой команды будет загрузка всей директории '''kopete'''. Каждый файл или директория отражаются в стандартном потоке вывода по мере их загрузки, обозначенные буквой ‘A’ в начале строки (‘U’ при обновлении файла и ‘D’ при удалении). Конечное сообщение всегда содержит номер ревизии, которую вы только что загрузили.
+
Команда '''svn update''' загружает любые изменения между локальной копией и той, что хранится в репозитарии. Так как у нас сейчас нет локальной версии, результатом этой команды будет загрузка всей директории '''kopete'''. Каждый файл или директория отражаются в стандартном потоке вывода по мере их загрузки, обозначенные буквой 'A' в начале строки ('U' при обновлении файла и 'D' при удалении). Конечное сообщение всегда содержит номер ревизии, которую вы только что загрузили.
  
 
В репозитариях программного обеспечения обычно уже содержатся готовые сценарии, необходимые для компиляции и установки проекта, так что следующим шагом будет загрузка необходимых скриптов с директории '''kde-common'''. После этого мы можем вызвать команды для
 
В репозитариях программного обеспечения обычно уже содержатся готовые сценарии, необходимые для компиляции и установки проекта, так что следующим шагом будет загрузка необходимых скриптов с директории '''kde-common'''. После этого мы можем вызвать команды для
Строка 148: Строка 150:
 
  $ ./configure --prefix=/usr
 
  $ ./configure --prefix=/usr
 
  $ make
 
  $ make
  $ su -c “make install”
+
  $ su -c "make install"
 
</code>
 
</code>
  
=== Часть 3 - вносим изменения ===
+
=== Часть 3. Вносим изменения ===
 
Если два разработчика работают над одним и тем же файлом-источником (так обычно и бывает), и второй пытается добавить свои изменения, в то время как первый уже это сделал, ''Subversion'' выдаст сообщение о конфликте версий.
 
Если два разработчика работают над одним и тем же файлом-источником (так обычно и бывает), и второй пытается добавить свои изменения, в то время как первый уже это сделал, ''Subversion'' выдаст сообщение о конфликте версий.
  
Строка 158: Строка 160:
 
  Sending helloworld.cpp
 
  Sending helloworld.cpp
 
  svn: Commit failed (details follow):
 
  svn: Commit failed (details follow):
  svn: Out of date: ‘helloworld.cpp’ in transaction ‘4’
+
  svn: Out of date: 'helloworld.cpp' in transaction '4'
 
  svn: Your commit message was left in a temporary file:
 
  svn: Your commit message was left in a temporary file:
  svn: /home/graham/build/svn2/subres/svn-commit.tmp’
+
  svn: '/home/graham/build/svn2/subres/svn-commit.tmp'
 
</code>
 
</code>
  
Строка 175: Строка 177:
 
  int main(int argc, char *argv[])
 
  int main(int argc, char *argv[])
 
  {
 
  {
  cout << “Hello World!<< endl;
+
  cout << "Hello World!" << endl;
  - cout << “Это дополнение.<< endl;
+
  - cout << "Это дополнение." << endl;
  + cout << “Еще одно дополнение” << endl;
+
  + cout << "Еще одно дополнение" << endl;
 
  return(0);
 
  return(0);
 
  }
 
  }
Строка 192: Строка 194:
 
Файл '''helloworld.cpp''' существует в различных версиях: версия репозитария и версии с исправлениями, например '''helloworld.cpp.r2''' – предыдущая версия перед обновлением, а '''helloworld.cpp.r3''' – версия, которая в настоящее время хранится в репозитарии. ''Subversion'' не позволит вам добавить файл в репозитарий, пока не устранится конфликт версий.
 
Файл '''helloworld.cpp''' существует в различных версиях: версия репозитария и версии с исправлениями, например '''helloworld.cpp.r2''' – предыдущая версия перед обновлением, а '''helloworld.cpp.r3''' – версия, которая в настоящее время хранится в репозитарии. ''Subversion'' не позволит вам добавить файл в репозитарий, пока не устранится конфликт версий.
  
Вы также можете выбрать следующий вариант: скопировать один из временных файлов поверх '''helloworld.cpp''', что позволит сделать локальную версию эквивалентной пре- или пост- обновленной версии (в нашем случае это файлы '''helloworld.cpp.r2''' и '''helloworld.cpp.r3'''). Вы можете использовать команду ''svn revert’'' для того, чтобы вернуть локальную копию к предыдущей версии, либо же вручную разрешить этот конфликт.
+
Вы также можете выбрать следующий вариант: скопировать один из временных файлов поверх '''helloworld.cpp''', что позволит сделать локальную версию эквивалентной пре- или пост- обновленной версии (в нашем случае это файлы '''helloworld.cpp.r2''' и '''helloworld.cpp.r3'''). Вы можете использовать команду '''svn revert''' для того, чтобы вернуть локальную копию к предыдущей версии, либо же вручную разрешить этот конфликт.
  
 
Итак, на нашем примере содержимое файла '''helloworld.cpp''' выглядит следующим образом:
 
Итак, на нашем примере содержимое файла '''helloworld.cpp''' выглядит следующим образом:
Строка 201: Строка 203:
 
  int main(int argc, char *argv[])
 
  int main(int argc, char *argv[])
 
  {
 
  {
  cout << “Hello World!<< endl;
+
  cout << "Hello World!" << endl;
 
  <<<<<<< .mine
 
  <<<<<<< .mine
  cout << “Второе дополнение.<< endl;
+
  cout << "Второе дополнение." << endl;
 
  ==========================================
 
  ==========================================
  cout << “Первое дополнение.<< endl;
+
  cout << "Первое дополнение." << endl;
 
  >>>>>>> .r3
 
  >>>>>>> .r3
 
  return(0);
 
  return(0);
Строка 211: Строка 213:
 
</code>
 
</code>
  
Символы <,>и =- маркеры, обозначающие конфликт. Текст между символами <и =представляет собой локальное изменение,
+
Символы '<','>' и '=' - маркеры, обозначающие конфликт. Текст между символами '<' и '=' представляет собой локальное изменение,
которое и послужило причиной для конфликта, потому он помечен как '''mine'''(мое). В секции после символов =показан номер версии, которая сейчас доступна в репозитарии (согласно метке, это третья ревизия). Нам потребуется отредактировать код, чтобы постараться совместить оба изменения – вероятно, изменив текст на что-то вроде '''Оба дополнения''':
+
которое и послужило причиной для конфликта, потому он помечен как ''''mine'''' (мое). В секции после символов '=' показан номер версии, которая сейчас доступна в репозитарии (согласно метке, это третья ревизия). Нам потребуется отредактировать код, чтобы постараться совместить оба изменения – вероятно, изменив текст на что-то вроде "'''Оба дополнения'''":
  
 
<code>
 
<code>
  cout << “Hello World!<< endl;
+
  cout << "Hello World!" << endl;
  cout << “Оба дополнения.<< endl;
+
  cout << "Оба дополнения." << endl;
 
  return(0);
 
  return(0);
 
</code>
 
</code>
Строка 224: Строка 226:
 
<code>
 
<code>
 
  $ svn resolved helloworld.cpp
 
  $ svn resolved helloworld.cpp
  Resolved conflicted state of ‘helloworld.cpp’
+
  Resolved conflicted state of 'helloworld.cpp'
 
  $ svn commit
 
  $ svn commit
 
  Sending helloworld.cpp
 
  Sending helloworld.cpp
Строка 231: Строка 233:
 
  $ svn update
 
  $ svn update
 
  At revision 4.
 
  At revision 4.
 +
</code>
 +
 +
=== Часть 4. Контроль над изменениями в проекте ===
 +
Существует много методов получения из репозитария информации о статусе проекта. Одна из наиболее употребимых команд при возникновении конфликта – '''svn log''', которая выводит на экран список комментариев к последним изменениям. Например, журнал для файла '''helloworld.cpp''' выглядит так:
 +
 +
<code>
 +
$ 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
 +
Добавление второй строки вывода.
 +
</code>
 +
 +
Использование комментариев для каждого изменения позволит вам быстро и точно опознать, что могло пойти не так. Вы можете вычислить, на ком лежит ответственность за неправильную работу программы, или к кому вам следует обратиться для решения возникшей проблемы. Каждая запись в журнале начинается с номера изменения, затем следует имя разработчика, время внесения изменений и комментарий к ним.
 +
 +
Еще одна команда, которая будет вам полезна при разрешении конфликтов – '''svn cat'''. Подобно двойнику из командной строки – команде
 +
'cat', которая выводит содержимое файла, '''svn cat''' отображает содержимое файла, который на данный момент используется на сервере
 +
''Subversion'', чтобы вы могли проверить все отличия между этим файлом и вашей локальной копией. Самое интересное, что вы также можете явно указать нужную версию и узнать, как изменился код программы.
 +
 +
<code>
 +
$ 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);
 +
}
 +
</code>
 +
 +
Выше мы попросили сервер ''Subversion'' показать вторую ревизию файла '''helloworld.cpp''' (состояние перед конфликтом). Используйте
 +
опцию '''--revision'' вместе с командой '''svn list''' для того, чтобы вывести на экран файлы, содержащиеся в репозитарии для каждой ревизии. Однако, лучше всего использовать эту опцию вместе с командой '''svn diff''' – это позволит вам сравнить две ревизии. Мы могли бы, например, увидеть, что именно изменилось в четвертой модификации файла '''helloworld.cpp''' по сравнению с первой.
 +
 +
<code>
 +
$ 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);
 +
}
 +
</code>
 +
 +
Итак, различие между первой и четвертой ревизиями файла '''helloworld.cpp''' – это строка «Оба дополнения», добавленная в предыдущем этапе данного руководства. Так как вывод команды '''svn diff''' такой же, как и у команды '''diff''', первая могла бы быть использована для того, чтобы генерировать вывод, совместимый с приложениями, наподобие Kompare из KDE – для графического сравнения различий между двумя модификациями файлов:
 +
 +
<code>
 +
$ svn diff --revision 1:4 helloworld.cpp | kompare -o -
 +
</code>
 +
 +
Теперь вы должны чувствовать себя вполне уверено в работе над проектом, находящимся под управлением ''Subversion''. Проект KDE, например, недавно перешел с ''CVS'' на ''Subversion''. Теперь можно смело загружать исходные тексты KDE и смотреть что к чему -
 +
это поможет вам без труда войти в цикл его развития.
 +
 +
==== Работа с патчами (врезка) ====
 +
Патч (patch) - это список изменений между двумя версиями одного проекта, который бывает полезен по двум причинам: во-первых, он позволяет работать над проектом, когда у вас нет прав на его запись; во-вторых, с помощью патча можно дать протестировать проект с вашими изменениями без их внесения в основную ветвь разработки.
 +
 +
По сути, патч не представляет из себя что-то действительно сложное – это всего лишь обычный вывод команды '''diff''', которая сравнивает два различных файла. Интересной представляется программа под названием '''patch''', изначально написана Ларри Уоллом (Larry «Perl» Wall), которая применяет изменения из файла-патча к другому файлу. Вы можете с легкостью создать файл-патч, используя Subversion, направив выходной поток от команды '''svn diff''' в файл:
 +
 +
<code>
 +
$ svn diff > имя_файла-патча
 +
</code>
 +
 +
Теперь вы можете послать результат работы этой команды в виде файла-патча какому-нибудь разработчику, которому требуются ваши изменения, либо просто тому, кто хочет их протестировать. Разработчик в дальнейшем может применить ваши изменения к его локальной
 +
версии, используя команду '''patch''', находясь в том же каталоге, где был создан патч:
 +
 +
<code>
 +
$ patch –p0 < имя_файла-патча
 
</code>
 
</code>

Текущая версия на 21:59, 4 февраля 2009

Содержание

[править] 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 < имя_файла-патча

Персональные инструменты
купить
подписаться
Яндекс.Метрика