20080116

Как сделать копию удалённого репозитория Subversion

Резервная копия репозитория Subversion, находящегося на локальной машине, делается обычно так:
$ svnadmin dump /путь/к/репозиторию > мой-дамп

Всё просто, достаточно иметь прямой доступ к каталогу с репозиторием.

Увы, для удалённых репозиториев, управляемых кем-то другим (например, на code.google.com), такой фокус не проходит. А как-то беспокойно на душе, когда нет своей копии... Зато проходят фокусы с созданием локального «зеркала» (копии) удалённого репозитория, с которым потом можно делать всё, что угодно.

Фокусов здесь можно сделать целых два.

Фокус первый

Содержимое удалённого SVN-репозитория можно легко перенести в локальный SVK-репозиторий. SVK — это система управления версиями, использующая хранилище SVN. То есть, фактически, всего лишь надстройка над Subversion.

Итак, чтобы фокус получился, для начала удаляем локальный SVK-репозиторий (если в нём ничего ценного нет, конечно):
$ rm -rf ~/.svk


Далее:
$ svk ls URL-удалённого-SVN-репозитория

(утвердительно отвечаем на все вопросы, svk создаёт локальный репозиторий с копией изменений из удалённого SVN-репозитория)

Теперь осталось сделать резервную копию:
$ svnadmin dump -r2:HEAD ~/.svk/local > мой-дамп

(создаём dump всех изменений, игнорируя первые две ревизии SVK-репозитория, к нашим делам отношения не имеющие)

Узнал я про такой фокус здесь.

Фокус второй

SVK пользоваться легко, но, к сожалению, SVK не сохраняет номера ревизий SVN. Поэтому для точного зеркалирования репозитория он не годится.

Тут на помощь может прийти другой инструмент: svnsync, появившийся в Subversion начиная с версии 1.4. svnsync предназначаен для одностороннего зеркалирования репозиториев SVN (то есть для создания репозиториев-клонов, предназначенных только для чтения).

Для начала создадим новый репозиторий, куда будем всё копировать. Это описано в документации Subversion:
$ svnadmin create /путь/к/новому/локальному/репозиторию

Не используйте в качестве зеркала уже существующие репозитории! svnsync может полностью перезаписать их содержимое.

После этого обозначим переменными MASTERSVN и COPYSVN адреса исходного репозитория и нового локального:
$ MASTERSVN=URL-удалённого-SVN-репозитория
$ COPYSVN=file:///путь/к/новому/локальному/репозиторию


После этого делаем пустой «хук» в локальном репозитории-зеркале:
$ cd /путь/к/новому/локальному/репозиторию
$ echo "#!/bin/sh" > hooks/pre-revprop-change
$ chmod 755 hooks/pre-revprop-change


Далее инициализируем репозиторий-зеркало:
$ svnsync init ${COPYSVN} ${MASTERSVN}

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

Чтобы начать передачу данных (синхронизовать репозиторий-зеркало с удалённым), следует выполнить такую команду:
$ svnsync --non-interactive sync ${COPYSVN}


В некоторых случаях (например, если предыдущая синхронизация оборвалась аварийно), svnsync может жаловаться на то, что не может заблокировать репозиторий-зеркало. В этих случаях помогает такая команда:
$ svn propdel svn:sync-lock --revprop -r 0  ${COPYSVN}


Поскольку я обычно синхронизую репозитории автоматически, по crontab, то в скрипте для синхронизации репозиториев пишу так:
if [ $(svn proplist --revprop -r 0 ${COPYSVN} | \
grep sync-lock | wc -l) -ne 0 ] ; then
sleep 15
svn propdel svn:sync-lock --revprop -r 0 ${COPYSVN}
fi


Этому фокусу я научился по статьям using svnsync и svnsync: mirror your svn repository. Пока доволен.

P.S. Недавно в блогах на runix.org проскакивало, в блоге Strannick-а, как копировать гиперссылки, используя два буфера обмена. Правой кнопкой мыши по ссылке и копировать адрес ссылки (в буфер GNOME), а потом выделение текста ссылки мышью (помещается в буфер X Window). Чтобы вставить: Shift-Ins (Ctrl-V) для адреса, щелчок средней мыши для текста ссылки. Мне понравилось! Если потренироваться — довольно удобно.