Subversionリポジトリのバックアップをとるシェルスクリプト
僕は作成物をSubversionで管理している。そのリポジトリは大事なので、ちゃんとバックアップをとりたい。リポジトリをバックアップするツールとして、svn-hot-backup というものがある。Subversionに同梱されている公式ツール(?)で、運悪く誰かがコミット中でもちゃんとバックアップできる。
Ubuntuの場合、subversion-tools というパッケージの中に入っている。最新のソースコードは以下から取れる。また、実行するにはpythonが必要だ。
ただし、僕の場合はいくつかリポジトリを持っているので、簡単なシェルスクリプトを作って一度に全部バックアップできるようにした。ソースコードは長いので一番下に書いておく。
僕の環境
- OS
- Ubuntu 8.04
- Subversion
- 1.4.6 (r28521)
- subversion-tools
- 1.4.6dfsg1-2ubuntu1
- python
- 2.5.2
使い方
まず、ソースコード中の定数を変更する。
- SVN_BACKUP_CMD
- svn-hot-backupコマンドのフルパス
- REPOSITORY_DIR
- リポジトリが格納されているディレクトリ。このディレクトリ直下にバックアップをとりたいリポジトリを全て置く。
- BACKUP_DIR
- バックアップ先のディレクトリ。
その後、BACKUP_DIRを作成してから以下のコマンドを実行する(svnbakという名前でシェルスクリプトを作成した場合の例)。
# バックアップ対象となるリポジトリを全て出力する % svnbak list /var/local/mollifier/svnrepos/_vim /var/local/mollifier/svnrepos/etc /var/local/mollifier/svnrepos/mozilla # リポジトリのバックアップをgzip圧縮形式でとる # 通常はこれのみで良いだろう % svnbak gz # リポジトリのバックアップを圧縮しない形式でとる % svnbak backup
何日か使いつづけた例
% ls /home/mollifier/.backup/svn/ _vim-52.tar.gz etc-249.tar.gz mozilla-134.tar.gz mozilla-37.tar.gz _vim-53.tar.gz etc-250.tar.gz mozilla-135-1.tar.gz mozilla-38.tar.gz _vim-55.tar.gz etc-254.tar.gz mozilla-135.tar.gz mozilla-41.tar.gz _vim-56.tar.gz etc-263.tar.gz mozilla-16.tar.gz mozilla-43.tar.gz _vim-58.tar.gz etc-267.tar.gz mozilla-19.tar.gz mozilla-54.tar.gz _vim-59.tar.gz etc-271.tar.gz mozilla-22.tar.gz mozilla-7.tar.gz _vim-60.tar.gz etc-278.tar.gz mozilla-23.tar.gz mozilla-72.tar.gz _vim-61-1.tar.gz etc-279.tar.gz mozilla-24.tar.gz mozilla-99.tar.gz _vim-61.tar.gz etc-284.tar.gz mozilla-26.tar.gz etc-246.tar.gz etc-286.tar.gz mozilla-31.tar.gz etc-247.tar.gz etc-287.tar.gz mozilla-33.tar.gz etc-248.tar.gz etc-289.tar.gz mozilla-35.tar.gz
こんな風にリポジトリ名にリビジョン番号をつけてアーカイブが作られる。
注意点
- 同じリビジョンのリポジトリを何度もバックアップすると、mozilla-135.tar.gz, mozilla-135-1.tar.gz, mozilla-135-2.tar.gz という風に通し番号付きでどんどんバックアップが作られます。
- 一つのリポジトリごとに、バックアップの数が増えると古いものから削除されます(svn-hot-backup が削除する)。デフォルトでは64個を越えると古いものが削除されます。本当はmozilla-135-1.tar.gz, mozilla-135-2.tar.gz のような重複したバックアップを優先して削除してほしいわけですが、ソースコードを見る限りそうはなっていません。リビジョンの古いものが先に削除されます。
- リポジトリ名が. (ドット)で始まる場合はバックアップされません。
ソースコード
#!/bin/bash ########################################################## # subversionリポジトリのバックアップを行う # hot-backupを使用する ########################################################## ##################### #定数 ##################### declare -r SCRIPT_NAME=${0##*/} #バックアップコマンド declare -r SVN_BACKUP_CMD="/usr/bin/svn-hot-backup" #リポジトリが格納されているディレクトリ #このディレクトリの直下のディレクトリをリポジトリと扱う #最後に'/'を付加すること declare -r REPOSITORY_DIR="/var/local/${LOGNAME}/svnrepos/" #バックアップ先のディレクトリ declare -r BACKUP_DIR="${HOME}/.backup/svn/" ##################### #関数 ##################### #ヘルプを出力する print_usage() { cat << EOF Usage: $SCRIPT_NAME backup|gz|list|help Backup all subversion repositories. Backup command: $SVN_BACKUP_CMD Repository directory: $REPOSITORY_DIR Backup directory: $BACKUP_DIR backup backup all repositories gz create gzip compressed tar archives of the backups list list all repositories help, -h, --help display this help and exit EOF } #エラーを出力する print_error() { echo "$SCRIPT_NAME: $@" 1>&2 echo "Try '$SCRIPT_NAME help' for more information." 1>&2 } ##################### #メイン処理 ##################### #変数 #実行モード #backup: リポジトリをバックアップする #list: リポジトリをリスト出力する execute_mode='' #バックアップコマンドのオプション backup_opt='' #引数解析 case "$1" in backup) execute_mode='backup' ;; gz) execute_mode='backup' backup_opt='--archive-type=gz' ;; list) execute_mode='list' ;; help|-h|--help) print_usage exit 0 ;; *) #エラー print_error "unknown argument -- $1" exit 1 ;; esac #コマンド、ディレクトリのチェック if [ ! -x "$SVN_BACKUP_CMD" ]; then print_error "can't execute backup command: $SVN_BACKUP_CMD" exit 1 fi if [ ! -d "$REPOSITORY_DIR" ]; then print_error "not found repository directory: $REPOSITORY_DIR" exit 1 fi if [ ! -d "$BACKUP_DIR" ]; then print_error "not found backup directory: $BACKUP_DIR" exit 1 fi #バックアップ実行 for trydir in $REPOSITORY_DIR*; do #ディレクトリのみを対象とする if [ -d "$trydir" ]; then if [ "$execute_mode" == "backup" ]; then #バックアップモードの場合 "$SVN_BACKUP_CMD" $backup_opt "$trydir" "$BACKUP_DIR" else #リスト出力モードの場合 ls -d "$trydir" fi fi done exit $?