Subversion

Article on other languages:

del.icio.us del.icio.us
Digg Digg
Furl Furl
Reddit Reddit
Rojo Rojo
Add to OnlyWire
Subversion
Логотип Subversion
Тип система управления версиями
Разработчик CollabNet, Inc.
ОС GNU/Linux, Microsoft Windows, Mac OS X, FreeBSD
Текущая версия 1.4.6 — 20 декабря 2007
Лицензия Аналог Apache/BSD
Сайт subversion.tigris.org

Subversion[1]  — свободная централизованная система управления версиями.

Subversion разработана специально для замены устаревшей системы CVS[2][3], самой распространённой открытой системы управления версиям. Subversion обладает всеми основными функциями CVS (хотя некоторые из них выполняет другими способами) и свободна от ряда её недостатков.

Subversion часто называют «SVN», по названию клиентской программы, входящей в её дистрибутив.

Содержание

История

Разработка Subversion была начата в 2000 году как попытка создать свободную систему управления версиями, в основном похожую[4] на CVS, но свободную от ее ошибок и неудобств. 31 августа 2001 года, спустя четырнадцать месяцев с начала работы, команда разработчиков перешла с CVS на Subversion для управления версиями собственного исходного кода — Subversion стала «самодостаточной».[5]

Общие сведения

Возможности

  • Реализовано большинство возможностей CVS.
  • Отслеживается история файлов, директорий и метаданных файлов, в том числе при переименовании и копировании.
  • Публикации изменений атомарны.
  • Возможность организации доступа к хранилищу Subversion через Apache по протоколу WebDAV/DeltaV.
  • Возможность установки автономного сервера Subversion с доступом по собственному протоколу.
  • «Дешёвые» операции создания ветвей и меток (требуется небольшое фиксированное количество временных и дисковых ресурсов).
  • Многоуровневая архитектура библиотек, изначально рассчитанная на клиент-серверную модель.
  • Клиент-серверный протокол пересылает по сети только разницу между объектами, когда это возможно.
  • Затраты ресурсов пропорциональны размеру изменений, а не размеру данных, которые затронуты изменениями.
  • Два возможных внутренних формата репозитория: база данных или простой файл.
  • Версионированные символьные ссылки (только в рабочих копиях под UNIX-системами).
  • Одинаково эффективная работа и с текстовыми, и с двоичными файлами.
  • Вывод клиента командной строки одинаково удобен и для чтения, и для разбора программами.
  • Частичная локализация сообщений (используются настройки локали).
  • Библиотеки для языков PHP, Python, Perl, Java.
  • Возможность зеркалирования репозитория.

Модель работы

Subversion — централизованная система (в отличие от распределенных систем, таких, как Git или Mercurial), то есть данные хранятся в едином хранилище. Хранилище может располагаться на локальном диске или на сетевом сервере.

Работа в Subversion мало отличается от работы в других централизованных системах управления версиями. Клиенты копируют файлы из хранилища, создавая локальные рабочие копии, затем модифицируют их и публикуют изменения в хранилище. Несколько клиентов могут одновременно обращаться к хранилищу. Для совместной работы над файлами в Subversion преимущественно используется модель Копирование-Изменение-Слияние. Кроме того, для файлов, не допускающих слияние (различные бинарные форматы файлов), можно использовать модель Блокирование-Изменение-Разблокирование.

При сохранении новых версий используется дельта-компрессия: система находит отличия новой версии от предыдущей и записывает только их, избегая ненужного дублирования данных.

При использовании доступа с помощью WebDAV также поддерживается прозрачное управление версиями — если любой клиент WebDAV открывает для записи и затем сохраняет файл, хранящийся на сетевом ресурсе, то автоматически создаётся новая версия.

Доступ к репозиторию

Начиная с версии 1.4 Subversion предоставляет следующие способы доступа к репозиториям:

  • Локальная или сетевая файловая система[6] — используется напрямую клиентской программой Subversion.
  • WebDAV/DeltaV (поверх http или https) с использованием модуля mod_dav_svn для Apache 2.
  • Собственный протокол «svn» (порт по умолчанию 3690), используя простой текст или через SSH.

Все эти способы могут быть использованы для работы с репозиторями обоих типов (FSFS и Berkeley DB). Для доступа к одному и тому же репозиторию могут одновременно использоваться разные способы.

Основные концепции

Файловая система

Рисунок 1. Двумерное представление файловой системы в Subversion
Рисунок 1. Двумерное представление файловой системы в Subversion

С точки зрения пользователя хранилище Subversion представляет собой «двумерную» файловую систему. Объекты в хранилище (файлы и каталоги) идентифицируются двумя «координатами»: именем и номером ревизии. Для однозначной адресации объекта необходимо указание обоих параметров. При необходимости указания на конкретную ревизию объекта используется запись вида: имя@ревизия, например, /main.c@29 — файл /main.c в ревизии 29. Такое указание ревизии, используемое для уточнения имени, называется стержневая ревизия (англ. peg revision).

На рисунке показано графическое представление файловой системы: вертикальная ось соответствует множеству имен, горизонтальная — множеству ревизий. Другими словами, хранилище представляет собой массив мгновенных снимков (ревизий) дерева файлов и каталогов. Каждый такой снимок — обычная (одномерная) файловая система.

Имена файлов

Имя объекта файловой системы в Subversion образуется по тем же правилам, что и в UNIX-подобных операционных системах: существует только один корневой каталог, элементы пути разделяются косой чертой «/». Объектами файловой системы являются файлы и каталоги (а также символические ссылки, которые эмулируются из обычных файлов путем установки атрибута svn:special).

Номера ревизий

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

В Subversion ревизия характеризует состояние не отдельного файла, а всего хранилища в целом. Поэтому при изменении даже одного файла создается новая ревизия всех имеющихся в хранилище файлов и каталогов. Например, ревизия 32 (обведено пунктиром на рисунке) — это состояние трех файлов и двух каталогов, существовавших в хранилище на тот момент.

Номер ревизии является аналогом времени в том смысле, что меньшие номера ревизий соответствуют более ранним состояниям хранилища, а бо́льшие — поздним:

  • Минимальный номер ревизии 0 (ноль) соответствует изначальному состоянию хранилища, когда еще не было опубликовано ни одной правки. В нулевой ревизии хранилище содержит только корневой каталог и ничего более.
  • Максимальный номер ревизии соответствует самому последнему состоянию хранилища, то есть состоянию после публикации последней правки. Вместо указания номера последней ревизии можно использовать ключевое слово HEAD (головная ревизия); это удобно, поскольку номер головной ревизии увеличивается при каждой публикациии изменений.

Ревизию можно рассматривать как некую временну́ю отметку в истории хранилища. Более того, с каждым номером ревизии связано абсолютное значение времени, когда эта ревизия была сделана (свойство svn:date). Однако указание номера ревизии удобнее, чем указание времени, так как нет путаницы с часовыми поясами, запись номера короче и номер ревизии не может быть изменен.

Операции над файловой системой

Над объектами файловой системы в хранилище Subversion могут быть произведены перечисленные ниже операции[7] (смотри также рисунок). В скобках указано краткое именование операции в обозначениях команды svn status.

  • Добавление (A). Добавление объекта в файловую систему. Добавленный объект не имеет истории ревизий. Пример на рисунке:
  • файл /main.c был добавлен в ревизии 27.
  • Модификация (M). Модификация объекта, например, изменение содержимого файла или изменение свойств файла или каталога. Пример на рисунке:
  • файл /main.c был модифицирован в ревизии 28.
  • Удаление (D). Удаление файла с головной и последующих ревизий. При этом файл остается в предыдущих ревизиях. Пример на рисунке:
  • файл /main.c был удален в ревизии 30.
  • Добавление с историей (A+). Представляет собой копирование объекта внутри файловой системы хранилища (хотя может быть произведено и через рабочую копию), то есть объект имя_источника@ревизия_источника копируется в имя_копии@HEAD. Скопированный объект наследует от источника историю ревизий до момента копирования (наследование истории показано на рисунке пунктирными связями). Примеры на рисунке:
  • в ревизии 29 каталог /tags/R1 был скопирован с каталога /trunk@27.
  • в ревизии 31 файл /main.c был скопирован с /main.c@29, то есть с более ранней ревизии самого себя. Таким образом, произведено восстановление ранее удаленного (в ревизии 30) файла с сохранением истории ревизий.
  • Замена (R+). Имеет место в случае, когда в одной ревизии произведено и удаление объекта (D), и добавление с историей (A+) объекта с тем же самым именем. Хотя имя при операции замены остается неизменным, Subversion рассматривает объект до и после замены как два различных объекта с различными историями ревизий (история старого заканчивается в точке замены, история нового наследуется от источника копирования и продолжается далее). Пример на рисунке:
  • в ревизии 30 файл /file.txt был скопирован с файла /bar.txt@29, а старый файл /file.txt удален.

Рабочая копия

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

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

Транзакции

В Subversion транзакции, то есть публикации изменений и другие операции с хранилищем, обладают по крайней мере свойствами атомарности и изоляции из набора свойств ACID. Атомарность и изоляция очень важны для систем управления версиями, так без них невозможно в любой момент времени гарантировать непротиворечивость данных в хранилище.

  • Атомарность. В Subversion публикации изменений атомарны (англ. atomic commits). Это значит, что если изменения сделаны в нескольких файлах и каталогах, то они публикуются как единая транзакция, порождая при этом одну ревизию. Система гарантирует, что либо в хранилище попадают все изменения, либо (при неудачной публикации) состояние хранилища не изменяется, ревизия не создается.
  • Изоляция. С точки зрения пользователей не существует состояния хранилища «в середине» транзакции. Если один пользователь публикует изменения множества файлов единой транзакцией, то другие пользователи не могут увидеть такого состояния хранилища, в котором часть файлов опубликована, а часть — не опубликована. Хранилище мгновенно переходит из состояния до транзакции в состояние после транзакции, поскольку новая головная ревизия появляется только когда транзакция уже завершена, а до этого видна только предыдущая ревизия. Другими словами, невозможно увидеть состояние хранилища «между» ревизиями.

Ветви и метки

Ветви

Subversion использует «файловую» модель (такую же, как и в Perforce[8]) для реализации ветвей и меток. Новая ветвь или метка создается командой svn copy, которая создает в хранилище копию источника с сохранением истории ревизий (A+). Полученная копия будет ветвью (или меткой, в зависимости от способа работы с ней). В дальнейшем изменения, сделанные на ветви, могут быть перенесены на источник, от которого была создана эта ветвь, такое распространение изменений называется слияние (англ. merge)

Операции копирования в Subversion дешёвые (англ. cheap copy), то есть требуют небольшого фиксированного количества времени и дискового пространства. Хранилище спроектировано таким образом[9], что при любом копировании происходит не дублирование данных, а создание ссылки на источник (аналогично жёсткой ссылке), однако этот механизм чисто внутренний — с точки зрения пользователя происходит именно создание копии.

Рисунок 2. Пример эволюции ветвей в Subversion
Рисунок 2. Пример эволюции ветвей в Subversion

Метки

Создание метки также производится командой svn copy, то есть технически не отличается от создания ветви. Отличие только в способе использования: предполагается, что никто не будет изменять данные в метке (публиковать в нее изменения). Например, на рисунке 1 метка создана в ревизии 29: каталог /trunk из ревизии 27 скопирован под именем /tags/R1. Теперь, если не изменять данные в каталоге /tags/R1, то он навсегда останется точной копией каталога /trunk@27, то есть будет меткой.

Концепция меток, используемая в Subversion, отличается от концепции меток в других системах управления версиями. Метки-копии в Subversion имеют свои достоинства и недостатки:

Достоинства:
  • Метка создается практически мгновенно при любом размере помечаемых данных.
  • Метка видна в структуре каталогов, можно сделать удобную древовидную организацию меток.
Недостатки:
  • Для объекта файловой системы невозможно узнать, в какие метки он вошёл.
  • Если права доступа установлены индивидуально[10] для каталогов, то метка эти права не наследует.
  • Помеченные данные могут быть изменены.

Структура каталогов хранилища

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

/branches
/tags
/trunk

Каталог /trunk содержит основную линию разработки проекта (англ. mainline), /branches содержит все ветви, /tags содержит все метки. Такая структура удобна для хранилища, содержащего только один проект. Если проектов несколько, то более удобна следующая структура:

 /project1
   /branches
   /tags
   /trunk
 /project2
   /branches
   /tags
   /trunk

то есть в корневом каталоге находятся каталоги проектов, и в каждом из них есть свои каталоги /trunk, /branches, /tags, относящиеся только к этому проекту. Описанные структуры каталогов хранилища являются лишь примерами, на практике хранилище можно организовать таким способом, который оптимально подходит в данном конкретном случае[11][12].

Другим способом хранения нескольких проектов является создание нескольких хранилищ. В разных хранилищах следует располагать проекты, которые никак не связаны между собой, поскольку между хранилищами нельзя будет выполнить операции копирования, перемещения и слияния. Несколько хранилищ можно при необходимости объединить в одно с сохранением истории ревизий (путем импорта командой svnadmin load с параметром --parent-dir).

Свойства (properties)

Одной из важных возможностей Subversion является поддержка свойств, то есть текстовых пар имя=значение, которые могут быть установлены для объектов в хранилище. Свойства используются в двух различных контекстах: для объектов файловой системы и для ревизий.

Свойства объектов файловой системы

Каждому файлу или директории в хранилище может быть присвоен набор свойств. Изменения свойств сохраняются в истории также, как и изменения в файловой системе. Пользователи могут устанавливать свойства с любыми именами; существует также предопределенный набор служебных свойств, которые используются клиентской программой Subversion (имена служебных свойств имеют префикс 'svn:').

Свойства файлов
svn:executable 
Делает файл исполняемым (для рабочих копий под операционными системами семейства UNIX).
svn:mime-type 
Хранит MIME-тип файла. Влияет на способ работы команд, показывающих разницу файлов, а также объединяющих изменения (merging).
svn:keywords 
Список ключевых слов (англ. keywords), которые будут заменены в файле соответствующими значениями. Чтобы замена произошла, ключевое слово должно присутствовать в файле в виде $keyword$. Используется для того, чтобы автоматически обновлять в файле значения, меняющиеся от версии к версии (например, номер ревизии).
svn:eol-style 
Определяет правило преобразования символов конца строки (англ. end-of-line, EOL) в текстовом файле. Используется в случаях, когда файл должен иметь конкретный тип символов EOL. Обычно используется «native» — при этом тип символов конца строки соответствует принятому в той операционной системе, в которой происходит создание рабочей копии.
svn:needs-lock 
Означает, что при извлечении из хранилища файл будет доступен только для чтения. Это свойство предназначено для использования совместно с механизмом блокировки. Запрет записи в файл является напоминанием того, что надо получить блокировку на этот файл, прежде чем его редактировать: при получении блокировки клиентская программа Subversion автоматически делает файл доступным для записи (снятие блокировки снова делает файл защищенным от модификаций). Блокировки могут быть использованы и без установки этого свойства. Однако делать это не рекомендуется, так как существует риск того, что другой пользователь может начать редактировать заблокированный файл, и это обнаружится только при публикации изменений.
svn:special 
Свойство не предназначено для установки или модификации пользователями. В настоящее время используется для хранения символьных ссылок в репозитории. Когда символьная ссылка добавляется в репозиторий, в репозитории создается файл с установленным свойством svn:special. Когда этот файл извлекается в UNIX-подобной системе, клиентская программа Subversion преобразует его обратно в ссылку.

Свойства директорий
svn:ignore 
Список шаблонов имен файлов, которые клиентская программа Subversion будет игнорировать в данной директории. Это свойство аналогично файлу .cvsignore в CVS.
svn:externals 
Позволяет автоматически извлечь в рабочую копию набор директорий, указав их URL (можно даже из другого хранилища).

Свойства ревизий

Второй тип объектов, для которых существуют свойства — это сами ревизии. В этом случае имена свойств также могут быть любыми; некоторые свойства с префиксом «svn:» имеют специальное значение. Отличие свойств ревизий от свойств объектов файловой системы в том, что для первых понятие истории версий не применимо (поскольку конкретное значение свойства приписано одной ревизии). Другими словами, свойства ревизий можно изменить, но старое значение при этом теряется.

svn:date 
Дата и время создания ревизии.
svn:author 
Имя пользователя, который опубликовал изменения, вошедшие в эту ревизию.
svn:log 
Описание изменений (задается пользователем при публикации изменений).

Subversion и CVS

Сравнение

Ниже приведено сравнение параметров систем Subversion и CVS, так как Subversion позиционируется именно как конкурент CVS. Приведено сравнение только по тем параметрам, по которым эти системы отличаются.

Параметр Subversion CVS
Возможности
Каталоги Отслеживает версии не только файлов, но и каталогов. Версии каталогов не отслеживаются, то есть структура каталогов одна и та же (та, которая существует в хранилище на данный момент) для всех ревизий и всех веток. При извлечении старых состояний получаем правильные (старые) ревизии файлов, но в неправильной (существующей на момент извлечения) структуре каталогов.
Транзакции Атомарность многофайловых публикаций. Атомарность только на уровне однофайловых публикаций. Фактически публикация изменений в нескольких файлах разбивается на последовательность публикаций изменений отдельных файлов. Если такая публикация прервана, то часть файлов остается опубликованной, часть - не опубликованной.
Наборы изменений Наборы изменений (англ. changeset) поддерживаются. Наборы изменений не поддерживаются.
Модификации имен файлов Поддерживает копирование, перемещение и переименование файлов и каталогов с сохранением истории изменений. При копировании, перемещении и переименовании файлов файл с новым именем не имеет никакой истории, то есть связь со старым именем и его историей версий полностью теряется. То же самое для файлов внутри каталога при модификации его имени[13].
Свойства (properties) С каждым файлом и каталогом может быть связан произвольный набор свойств, состоящих из названия и значения. Свойства тоже находятся под управлением версиями. Свойства не поддерживаются
Блокировки Поддерживается необязательная блокировка файлов (начиная с версии 1.2). Блокировки не поддерживаются, но есть похожий механизм, называемый слежение
Ветки Ветки (branch, см. словарь) реализованы в пространстве путей. Это значит, что для создания ветки производится копирование каталога (копия и будет веткой). Создание таких каталогов — быстрая и не ресурсоёмкая операция, потому что данные не дублируются, вместо этого публикуется новая версия, отличающаяся от предыдущей лишь расположением файлов. Ветки реализованы в «третьем измерении». Это значит, что файл на ветке адресуется тремя параметрами: путём в файловой системе, ревизией (или другим способом указания ревизии, например, временем), именем ветки.
Метки Нет меток (tag, см. словарь), как таковых. Вместо них используется иерархия каталогов — для метки создаётся отдельный каталог (как и для ветки). Метка — это ветка, в которой по договоренности больше не делают изменений. Метки поддерживаются
Эффективность
Клиент-серверный обмен При любых обновлениях версий между клиентом и сервером передаются только различия между файлами, что может существенно уменьшить сетевой трафик. С сервера к клиенту передаются различия, с клиента на сервер объект передается полностью
Двоичные файлы Одинаково эффективно работает как с текстовыми, так и с двоичными файлами. Работа с двоичными файлами менее эффективна: каждая новая версия сохраняется в хранилище полностью.
Создание ветвей и меток Требуется небольшое фиксированное количество времени и дискового пространства. Затраты времени велики (зависят от количества задействованных файлов). Имена ветвей и меток хранятся избыточно (во всех задействованных файлах).
Накладные расходы в рабочей копии В служебных каталогах рабочей копии хранится чистая копия (англ. pristine copy) - файлы рабочей копии в неизмененном виде, как они были извлечены из хранилища. Это позволяет быстро и без обращения к хранилищу выполнять операции просмотра и отката локальных изменений. Однако размер рабочей копии на диске примерно в два раза больше (рабочие файлы + чистая копия), чем размер самих данных[14]. Чистая копия не хранится, размер рабочей копии примерно равен размеру данных. В результате операции просмотра и отката локальных изменений требуют доступа к хранилищу и выполняются медленно.
Расход памяти на стороне сервера Меньше[15] Больше.

Миграция с CVS на Subversion

Преобразование репозитория

Существует программа cvs2svn, предназначенная для преобразования репозитория CVS в готовый репозиторий Subversion (либо в репозиторий git) или в текстовый дамп, который можно затем импортировать в репозиторий при помощи утилиты svnadmin. При этом cvs2svn сохраняет всю информацию, содержащуюся в репозитории CVS: ветви, метки, описания изменений, имена авторов, даты публикации изменений. Кроме того, изменения в различных файлах, опубликованные совместно, преобразуются в одну ревизию.

Отличия в использовании

Переименование

Пользователи, перешедшие с CVS на Subversion, часто выполняют переименование файлов и каталогов неправильным способом. В CVS не существует иного способа изменения имени, кроме как удалить объект со старым именем и добавить объект с новым именем. Аналогичные (неправильные!) действия в Subversion выполняются парой команд (или аналогичными действиями через графический клиент):

svn delete <старое имя>
svn add <новое имя>

Данный способ переименования неправильный потому, что новый объект, добавленный командой svn add, не имеет истории (поскольку он добавлен как новый), то есть полностью теряется связь со старым именем и его историей ревизий. Правильный способ переименования объектов в Subversion:

svn move <старое имя> <новое имя>

При этом объект со старым именем также удаляется, но объект с новым именем копируется со старого с сохранением истории. При просмотре истории ревизий переименованного объекта будет виден факт копирования, а также вся история ревизий до копирования.

Все сказанное в равной степени относится и к копированию: следует использовать именно копирование (svn copy), а не добавление нового экземпляра объекта (svn add).

Внутренняя структура

Слои

Управление

USVN[1] Дружелюбный веб интерфейс для SVN на базе PHP5. Позволяет управлять и конфигурировать репозитарии Subversion.

Позволяет пользователю создавать и управлять проектами без использования командной строки SVN клиента. USVN предоставляет простой, быстрый и мощный механизм управления правами доступа к репозитарию. USVN это проект с открытыми исходными кодами распространяемый по лицензии CeCill (это GPL совместимая лицензия).

Распространённость

По состоянию на 2006 год Subversion уступает по распространённости CVS, однако её можно назвать наиболее популярной альтернативой этой традиционной системе. Многие сообщества разработчиков открытого программного обеспечения перешли на использование Subversion. В их числе такие известные проекты как Apache Software Foundation, KDE, GNOME, GCC, MediaWiki, Python, Samba, Mono и многие другие.

Примечания

  1. Sub- (под-) + version (версия). В то же время, англ. subversion — свержение.
  2. Официальный сайт Subversion
  3. The Risks of Distributed Version Control Бен Коллинз-Сассман
  4. CVS была взята за отправную точку потому, что в то время не существовало лучших программ этого класса со свободной лицензией
  5. "История Subversion", раздел в Управление версиями в Subversion, версия 1.4
  6. Berkeley DB использует блокировки файлов, поэтому она не должна использоваться на (сетевых) файловых системах, которые не поддерживают блокировки
  7. Здесь перечислены операции именно с точки зрения файловой системы хранилища. В рабочей копии действия над объектами несколько иные. Однако изменения в рабочей копии, будучи опубликованными, вызовут в хранилище описанные здесь действия. Например, команда svn move в рабочей копии произведет операции D, A+ в хранилище.
  8. Inter-File Branching in Perforce
  9. Bubble-Up Method
  10. Path-Based Authorization
  11. Структура проектов на C++ с использованием Subversion и Mxx_ru
  12. Хранение сложных проектов в репозитории и установка tag’ов на несколько проектов сразу
  13. Каталог можно переместить прямо в хранилище средствами файловой системы, при этом файлы в нем не потеряют историю. Однако эта модификация подействует на все ревизии и ветви файлов в этом каталоге (поскольку каталоги не имеют версионной информации в CVS)
  14. Такой подход обусловлен тем, что дисковые ресурсы дешевле и доступнее, чем ресурсы сети передачи данных
  15. http://subversion.tigris.org/faq.html#server-requirements

Ссылки

Публичные хранилища SVN

Источник — «http://ru.wikipedia.org/wiki/Subversion»

This article is from Wikipedia. All text is available under the terms of the GNU Free Documentation License.


Giant Panda

Mercedes Car
James Bond Guide
This site monitored by SitePinger.net