Системы контроля версий

Существует несколько десятков таких широкоиспользуемых систем: SCCS (1972,
Source Code Control System, Posix), RCS (1982, Revision Control System: OpenBSD,
...), CVS (1990, Concurrent Version Control: Emacs, ...), Subversion (2000,
FreeBSD, Apache, GCC, Virtualbox, ...), Bazaar (2005, Ubuntu, Mysql, Squid, ...),
GIT (2005, Linux, ...), Mercurial (2005, Clisp, Python, Vim, ...), TFS (2005,
Microsoft Team Foundation Server), ... Они позволяют не терять последовательности 
изменений в файлах. Это, например, позволяет вернуться к предшествующему этапу
разработки, следить за историей проекта и т.п. 

Система subversion (svn) ориентирована на совместную сетевую разработку. Она
позволяет многим пользователям одновременно работать над одним проектом.
Кроме того, svn позволяет организовывать ветвления, т.е. развивать дерево
разработки -- вести независимые, но согласованные изменения в параллельных
проектах-ветках. При необходимости ограничить доступ можно использовать 
пароли.

Основа работы с svn -- это хранилище данных, репозиторий. Он может
находиться как на компьютере пользователя, так и на удаленном сервере.
Создание репозитория -- это первый этап работы с svn. Затем в хранилище
данных нужно загрузить файлы проекта, изменения которых следует отслеживать.
Файлы загружаются вместе со структурой каталогов -- изменения этой структуры 
svn также отслеживает. После чего из репозитория выписывается рабочая копия
проекта, с которой можно работать обычным образом. Рабочая копия в каждом
своём каталоге содержит подкаталог .svn с данными, управляемыми автоматически
(с версии 1.7 такой каталог только один). Пользователь может командой status 
(st) получить информацию о файлах, которые были изменены с момента последней 
выписки. У команды st есть полезная опция -q --- показывать только версионные
файлы. Команда commit (ci) обновляет репозиторий новыми версиями файлов из 
рабочей копии, а команда update (up) обновляет рабочую версию данными из 
хранилища. При каждом занесении новых данных в репозиторий происходит создание 
новой версии всех файлов проекта. Версии нумеруются последовательно, начиная с 
1. Все файлы в каждой версии проекта в хранилище имеют одну версию, а в рабочей 
копии могут быть файлы разных версий. Команда list (ls) позволяет просмотреть 
содержимое репозитория. Другие команды:

add -- отметить файлы и каталоги как версионные -- они будут занесены в
репозиторий при следующем его обновлении

cat -- показать содержимое файлов указанной версии

checkout (co) -- выписать рабочую копию

cleanup -- привести в порядок рабочую копию: закончить незавершенные
операции

copy (cp) -- копировать что-либо в рабочей копии или репозитории

delete (del, remove, rm) -- сделать заданные файлы и каталоги неверсионными
и удалить их из рабочей копии, использование опции --keep-local предотвратит 
последнее удаление

diff (di) -- сравнить разные версии

export -- выписать копию проекта без поддержки контроля версий

import -- отправить файлы в репозиторий -- без изменений рабочей копии

info -- информация по файлам, репозиторию и т.п.

log -- показать записи в журнале по заданным файлам или версиям. При каждом
изменении хранилища нужно добавлять сопроводительную запись в журнал либо
строкой с опцией -m, либо содержимым файла по опции -F. Если такая запись
будет отсутствовать, то будет предложено её создать

mkdir -- создать версионный каталог

move (mv, rename, ren) -- переместить/переименовать

revert -- вернуться к исходной версии -- отбросить результаты редактирования
в рабочей копии.

Команды update и checkout позволяют получать рабочие копии любых версий, 
организуя ``путешествие во времени''.

При совместной разработке возможно возникновение конфликтных ситуаций.
Например, если два пользователя одновременно редактировали один файл и затем
отправили его в хранилище. Простейший способ борьбы с конфликтами -- это
блокировка. Она устанавливается командой lock и снимается командой unlock.
Блокировка хороша для бинарных данных, но часто это не лучший способ. Она может 
вызвать проблемы администрирования, когда один пользователь надолго блокирует 
файл. Может вызвать излишнюю пошаговость, когда разным пользователям, 
редактирующим разные части файла придётся ждать друг друга. Кроме того, она 
может вызвать ложное чувство безопасности, хотя она не может гарантировать 
целостности проекта при несогласованных изменениях в разных файлах. Поэтому svn
предлагает модель копирование-изменение-слияние, когда пользователи
независимо работают со своими рабочими версиями, а при обновлении
репозитория производятся слияния. В сложных ситуациях при слиянии необходимо
участие пользователей. Команда resolved сбрасывает флажки конфликтности в 
рабочей копии после устранения конфликтов пользователем. Слияния обычно проходят 
автоматически, но ими можно управлять явно командами merge и mergeinfo.

Все команды вводятся как параметры в вызове svn, например, svn status.
Репозиторий создаётся командой svnadmin create ПУТЬ. 

Правки идентифицируются номерами, но можно использовать вместо них даты или 
ссылки на специальные случаи, например, последнюю правку хранилища (HEAD) или 
последнюю локальную согласованную с репозиторием (BASE). Опция -r позволяет 
указывать нужную версию или диапазон версий.

svn checkout -r {"2006-02-17 15:30"} 
  #выписать рабочую копию, ближайшую к заданному времени 
svn diff -r BASE:14 foo.c 
  #сравнить базовую версию foo.c и версию foo.c в правке 14
svn log --revision BASE:HEAD 
  #показать журнал фиксаций со времени последнего обновления
svn log -r {2010-11-20}:{2010-11-29}

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

propget (pg) -- получить свойства

propedit (pe) -- редактировать свойства, выбранным редактором текстов

propdel (pd) -- удалить свойства

proplist (pl) -- показать свойства

propset (ps) -- установить свойства.

svn propset copyright '(c) 2010 MATI' calc/* 
  #установить свойство на содержимое каталога calc
svn propset license -F /path/to/LICENSE calc/button.c 
  #значение свойства из указанного файла
svn proplist -v calc/button.c 
  #показать все свойства указанного файла со значениями
svn propset svn:log '* button.c: Fix a compiler warning.' -r11 --revprop
  #установить свойство правки

Для указания на неверсионный элементы можно указать их глобально при помощи 
шаблонов в конфигурационном файле svn в строке global-ignores или локально 
свойством каталогов svn:ignore. Локальные свойства не переопределяют 
глобальные. Неверсионные элементы состоят в основном из генерируемых из 
исходников файлов. 

Отметки версионного контроля можно вставить в файлы-исходники проекта при 
помощи механизма подстановка ключевых слов. Например, слово $Id$ заменяется на 
дату и версию последнего изменения, автора изменения и полный адрес в 
хранилище последнего изменения. Механизм подстановки работает только с 
файлами с установленным свойством svn:keywords. Значение этого свойства --- 
это список слов для замены (Id и др.).

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

Помимо файлов и каталогов можно версионировать символические соединения.

Ветки создаются командой copy для каталогов --- при этом ничего не копируется,
а создаётся лишь ссылка на оригинал. Поэтому можно создавать много веток - это
не потребует больших ресурсов. Аналогично веткам создаются метки или снимки
(tags), которые отличаются от веток только назначением. Обычно метки - это
готовые к публикации версии, т.е. версии, которые далее не меняют. Метки
позволяют использовать имена вместо номеров версий.

Команда help (?, h) позволяет получать справочную информацию по всем 
командам svn.

С репозиторием можно взаимодействовать, используя протоколы:
1) локальный - file;
2) svn;
3) svn+ssh;
4) http.

В пакет Subversion помимо основной утилиты входят программы svnadmin (для
создания репозитория и других административных задач), svnserv (сервер по
протоколу svn), svnsync (синхронизация с локальным репозиторием - это
средство позволяет поддерживать некоторые свойства распределенных систем),
svnlook (информация по репозиторию).

Существует несколько программ, графических интерфейсов, в частности, через 
веб, для svn.

Subversion как и многие другие подобные системы имеет клиент-серверную
архитектуру. Есть ещё так называемые распределённые (distributed) системы:
Bazaar, GIT, Mercurial, ... Есть системы совмещающие оба подхода, например,
TFS. В распределённых системах из-за отсутствия центрального репозитория
образуется множество репозиториев отдельных пользователей, которые можно
попарно синхронизовывать. Многие операции проходят в таких системах быстрее, 
так как связь с сервером не нужна. Недостатки распределенных систем:
отсутствие механизмов блокировки, больший объем репозитория для больших
проектов, намного большая сложность, отсутствие простой идентификации версий,
большая чувствительность к поломке рабочего компьютера.

Для некоторых систем, например, GIT и SVN, есть возможность их использовать
в одном проекте.

Пример выполнения некоторых задач с svn.

svnadmin create /home/student/project1    #создание репозитория
cd projects
svn co file:///home/students/project1     #выписка рабочей копии
cd project1
#работа с файлами проекта
svn st                                    #статус файлов в рабочей копии
svn add file.c file.h makefile wrongfile  #отметка файлов как версионных
svn del wrongfile                         #снятие файла с версионного контроля
svn up                                    #обновление рабочей копии
svn ci -m "the first commit"              #занесение изменений в рабочей копии в репозиторий
svn up
svn ps svn:ignore 'file.o a.out' .        #не показывать файлы в каталоге по команде st
svn up
svn ci -m "the 2nd commit"
svn up
D=/home/student/project1mirror
svnadmin create $D                        #создание "зеркала" репозитория в заданном каталоге
echo '#!/bin/sh' >$D/hooks/post-revprop-change        #три операции полезные при создании любого репозитория
echo '#!/bin/sh' >$D/hooks/pre-revprop-change
chmod 755 $D/hooks/*-revprop-change
svnsync init file://$D file:///home/student/project1  #окончание создания "зеркала"
svnsync sync file://$D                    #синхронизация репозиториев
#работа с файлами проекта
svn diff file.c                           #просмотр изменений в указанном файле, сравнивается текущая
                                          #версия и последния согласованная версия (BASE) из репозитория
                                          #команда выполняется без обращения к репозиторию
svn revert file.c                         #отбросить все изменения файла в рабочей копии, вернуться
                                          #к версии BASE
svn up -r 1 file.c                        #вернуться к версии 1 файла
svn up file.c                             #взять из репозитория новейшую версию (HEAD) файла
svn up
svn ci -m "the 3d commit"
svn up
svnsync sync file://$D
svn ls file://$D                          #просмотр каталога репозитория
svn log                                   #журнал изменений, список операций занесения в репозиторий