Following up on the good work of Jean-Francois Roy, here's my slightly extended version of his script (Update: sorry, the link is dead) to backup all Subversion repositories to a remote host.

How to use:

  1. Download backup-all-svn.sh
  2. chmod u+x path/to/backup-all-svn.sh
  3. ./backup-all-svn.sh -h target_host (can also set target port and user name)

Some features:

  • Works with plain /bin/sh, so it should work on any Linux / BSD distribution.
  • Works with repository names with spaces and non-ASCII characters.

backup-all-svn.sh

#!/bin/sh
#
# $Id: backup-all-svn.sh 387 2008-06-07 20:36:08Z vengmark $
#
# NAME
#    backup-all-svn.sh - Backup all Subversion repositories
#
# SYNOPSIS
#    backup-all-svn.sh [options]
#
# OPTIONS
#    -v     Verbose output
#    -h     Target host name (mandatory)
#    -p     Target host port
#    -u     Target host user name
#
# EXAMPLE
#    ./backup-all-svn.sh -v -h example.com -p 1234 -u johndoe
#
# DESCRIPTION
#    Backups all your subversion repositories to a remote machine.
#
#    The current user must have access to the subversion repositories.
#    To work around this, you should `sudo adduser &ltusername> &ltdiv>`
#    and `sudo chmod -R g+w /path/to/repos`.
#
#    To avoid having to type your password several times, you can setup SSH
#    keys - See e.g. https://help.ubuntu.com/community/SSHHowto
#
# BUGS
#    Email bugs to victor dot engmark at gmail dot com. Please include the
#    output of running this script in verbose mode (-v).
#
# COPYRIGHT AND LICENSE
#    Copyright (C) 2005 Jean-Francois Roy
#    Copyright (C) 2008 Victor Engmark
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see &lthttp://www.gnu.org/licenses/>.
#
################################################################################

# Init
ifs_original="$IFS" # Reset when done

PATH="/usr/bin:/bin"
cmdname=`basename $0`
directory=`dirname $0`

# Remote host
target_dir=".svn-backup/`date +%G-%m-%d`"
target_port=22
target_user=`whoami`

# Subversion
svn_root="/var/lib/svn"
svn_install_root="/usr/bin"

# Error messages from /usr/include/sysexits.h, recommended by
# http://www.faqs.org/docs/abs/HTML/exitcodes.html
EX_OK=0
EX_USAGE=64
EX_CANT_CREATE=73

# Custom errors
EX_NO_SUCH_DIR=91
EX_NO_SUCH_EXEC=92

usage_error()
{
    echo "Usage: ${cmdname} [-v] -h host [-p port] [-u user]" #Code 3
    exit $EX_USAGE
}

# Process parameters
until [ $# -eq 0 ]
do
    case $1 in
        -v)
            verbose=1
            shift
            ;;
        -h)
            if [ -z "$2" ]
            then
                usage_error
            fi
            target_host=$2
            shift 2
            ;;
        -p)
            if [ -z "$2" ]
            then
                usage_error
            fi
            target_port=$2
            shift 2
            ;;
        -u)
            if [ -z "$2" ]
            then
                usage_error
            fi
            target_user=$2
            shift 2
            ;;
        *)
            #Unknown parameter
            usage_error
            ;;
    esac
done

if [ -z ${target_host} ]
then
    usage_error
fi

# Use for mandatory directory checks
# $1 is the directory path
# $2 is the (optional) error message
check_directory()
{
    if [ ! -d $1 ]
    then
        echo "No such directory: '${1}'" >&2
        echo $2 >&2
        exit $EX_NO_SUCH_DIR
    fi
}

check_directory $svn_root "Please change \$svn_root to point to the directory where your Subversion repositories are."

check_directory $svn_install_root "Please change \$svn_install_root to point to the directory where Subversion is installed."

# Make sure an executable is available
# $1 is the path to the executable
# $2 is the (optional) error message
check_executable()
{
    if [ ! -x $1 ]
    then
        echo "No such executable: '${1}'" >&2
        echo $2 >&2
        exit $EX_NO_SUCH_EXEC
    fi
}

svn_install_missing="Please change \$svn_install_root to point to the directory where Subversion is installed."
check_executable ${svn_install_root}/svnlook $svn_software_missing
check_executable ${svn_install_root}/svnadmin $svn_software_missing

# Create the temporary folder
temp_dir=`mktemp -t -d ${cmdname}.XXXXXXXXXX` || exit $?

verbose_echo()
{
    if [ $verbose ]
    then
        echo "$*"
    fi
}

# Announce that we're running
verbose_echo "Running $cmdname at `date`."

# Create target directory
ssh -p ${target_port} ${target_user}@${target_host} "mkdir -p \"${target_dir}\"" || exit $?

# Loop over repositories
cd "${svn_root}"
IFS="
" # Make sure paths with spaces don't make any trouble when looping
for repository in *
do
    # Get the last revision
    revision=`${svn_install_root}/svnlook youngest "${repository}"`
    verbose_echo "Backing up repository \"${repository}\" revision ${revision}."

    # Make sure the repo is OK
    verbose_echo "Recovering the repository."
    ${svn_install_root}/svnadmin recover --wait "${repository}" > /dev/null

    # Did the recover operation fail?
    if [ $? -ne 0 ]
    then
        echo "Backup failed because recovery failed." >&2
        break
    fi

    # Hotcopy
    verbose_echo "Hot-copying the repository."
    ${svn_install_root}/svnadmin hotcopy --clean-logs "${repository}" "$temp_dir/${repository}"

    # Did the hotcopy fail?
    if [ $? -ne 0 ]
    then
        echo "Backup failed because hotcopy failed." >&2
        rm -Rf "$temp_dir"
        break
    fi

    # Compress the hotcopy
    verbose_echo "Compressing the repository in a tar.bz2 archive."
    archive="${repository}-r${revision}.tar.bz2"
    tar -cjpf "$temp_dir/${archive}" -C "$temp_dir" "${repository}"

    # Send it over
    verbose_echo "Copying repository archive to remote host."
    scp -P ${target_port} "$temp_dir/${archive}" "${target_user}@${target_host}:\"${target_dir}/${archive}\""

done

verbose_echo "Cleaning up."
rm -Rf $temp_dir
IFS="$ifs_original"

# End
verbose_echo "${cmdname} completed at `date`."

exit $EX_OK