前言:SVN(Subversion)是近年来崛起的版本管理工具,是CVS的接班人。目前,绝大多数开源软件都使用svn作为代码版本管理软件。
一、SVN的体系结构:
B:虚拟机:VMware® Workstation 9.0.0 build-812388;
C:subversion-1.6.1.tar.gz、subversion-deps-1.6.1.tar.gz;
D:主机名:samba。
[root@samba ~]# yum install -y subversion
最后显示则表示安装成功:
Complete!
B、版本验证命令:
[root@samba ~]# svnserve --version
显示:
svnserve, version 1.6.11 (r934486)
compiled Apr 11 2013, 17:28:04
Copyright (C) 2000-2009 CollabNet.
Subversion is open source software, see http://subversion.tigris.org/
This product includes software developed by CollabNet (http://www.Collab.Net/).
The following repository back-end (FS) modules are available:
* fs_base : Module for working with a Berkeley DB repository.
* fs_fs : Module for working with a plain file (FSFS) repository.
Cyrus SASL authentication is available.
C、创建SVN目录以及版本库:
[root@samba ~]# mkdir /usr/local/svn
[root@samba ~]# chmod u+x /usr/local/svn
[root@samba ~]# svnadmin create /usr/local/svn/lmzsvn
D、配置服务、用户权限等:
进入conf目录:
D1、配置svn服务选项:
[root@samba conf]# vi svnserve.conf
将下面四行行首的"#"去掉,并修改成如下结果:
anon-access = none
auth-access = write
password-db = passwd
authz-db = authz
保存svnserve.conf文件;
D2、配置用户名与密码,按照user = passwd模式设置相关的用户信息:
[root@samba conf]# vi passwd
添加如下代码:
lmz = davepwd
保存passwd文件;
D3、配置用户的访问权限,按照分组的方式将用户分成不同的访问组,并对每个访问组赋予相关的访问和操作权限:
[root@samba conf]# vi authz
添加如下代码:
[groups]
admin = lmz
[davesvn:/]
@admin = rw
保存authz文件;
E、采用后台启动SVN的方式,启动SVN并关闭系统防火墙:
[root@samba conf]# svnserve -d -r /usr/local/svn
关闭防火墙命令:
[root@samba conf]# service iptables stop
F、安装SVN的客户端TortoiseSVN,即可访问:
G、接下来可以利用TOMCAT与SVN联合开发,不在此赘述。
[root@samba ~]# yum install gcc
[root@samba ~]# yum install openssl openssl-devel
[root@samba ~]# yum install expat
B、进入SVN软件包目录,并对SVN软件包进行解压(本人的软件包在/root/soft,可通过pwd命令查看):
[root@samba soft]#tar-zxvf subversion-1.6.1.tar.gz
[root@samba soft]#tar-zxvf subversion-deps-1.6.1.tar.gz
切记:这两个软件包一定要放在相同的目录下解压,因为解压之后你会发现,所有解压文件是放在一个文件中的,其中包括一些依赖关系。
C、进入SVN软件解压目录,进行编译并指定SVN软件的安装目录:
[root@sambasoft]# cdsubversion-1.6.1
[root@sambasubversion-1.6.1]#./configure --prefix=/usr/local/svn/
[root@sambasubversion-1.6.1]#make && make install
[root@sambasubversion-1.6.1]#mkdir -p /opt/svn/
[root@sambasubversion-1.6.1]#mkdir -p /opt/svn/svntest/
[root@sambasubversion-1.6.1]# cd /usr/local/svn/bin
[root@samba bin]#svnadmin create /opt/svn/svntest/
测试版本库创建成功后,进入/opt/svn/svntest目录下,可以看到如下结构:
该目录下包括svn的配置目录、数据目录、说明文件等。
[root@sambabin]#svnserve -d -r /opt/svn
关闭防火墙:
[root@sambabin]#service iptables stop
本机测试(co:是指checkout的缩写):
[root@sambabin]#svn co svn://127.0.0.1/svntest
结果如图所示:
途中需要你输入用户名与密码。
[root@sambasoft]#svn co svn://127.0.0.1/svntest/svn
结果如下:
从图中我们可以知道,svn服务器的下载文件明细,以及下载结果情况。
我们从远程客户端windows端的svn客户端测试,结果如图所示:#!/bin/sh
##Subversion的安装目录及执行文件
SVN_HOME=/usr/local/svn/bin
SVN_ADMIN=$SVN_HOME/svnadmin
SVN_LOOK=$SVN_HOME/svnlook
##配置库根目录
SVN_REPOROOT=/opt/svn
##增量备份文件存放路径
date=
(
d
a
t
e
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
s
t
r
i
n
g
"
>
′
+
R
A
R
S
T
O
R
E
=
/
u
s
r
/
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
b
u
i
l
t
i
n
"
>
l
o
c
a
l
<
/
s
p
a
n
>
/
s
v
n
/
s
v
n
b
a
c
k
u
p
/
f
u
l
l
/
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
v
a
r
i
a
b
l
e
"
>
(date <span class="hljs-string">'+%Y-%m-%d'</span>) RAR_STORE=/usr/<span class="hljs-built_in">local</span>/svn/svn_backup/full/<span class="hljs-variable">
(date<spanclass="hljs−string">′+RARSTORE=/usr/<spanclass="hljs−builtin">local</span>/svn/svnbackup/full/<spanclass="hljs−variable">date
if [ ! -d "
R
A
R
S
T
O
R
E
<
/
s
p
a
n
>
"
<
/
s
p
a
n
>
]
;
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
k
e
y
w
o
r
d
"
>
t
h
e
n
<
/
s
p
a
n
>
m
k
d
i
r
−
p
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
v
a
r
i
a
b
l
e
"
>
RAR_STORE</span>"</span> ];<span class="hljs-keyword">then</span> mkdir -p <span class="hljs-variable">
RARSTORE</span>"</span>];<spanclass="hljs−keyword">then</span>mkdir−p<spanclass="hljs−variable">RAR_STORE
fi
##读取项目库列表
cd $SVN_REPOROOT
for name in $(ls)
do
##开始做全量备份
S
V
N
A
D
M
I
N
<
/
s
p
a
n
>
h
o
t
c
o
p
y
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
v
a
r
i
a
b
l
e
"
>
SVN_ADMIN</span> hotcopy <span class="hljs-variable">
SVNADMIN</span>hotcopy<spanclass="hljs−variable">SVN_REPOROOT/
n
a
m
e
<
/
s
p
a
n
>
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
v
a
r
i
a
b
l
e
"
>
name</span> <span class="hljs-variable">
name</span><spanclass="hljs−variable">RAR_STORE/$name
done
#!/bin/sh
#Subversion的安装目录及执行文件
SVN_HOME=/usr/local/svn/bin
SVN_ADMIN=$SVN_HOME/svnadmin
SVN_LOOK=$SVN_HOME/svnlook
##配置库根目录
SVN_REPOROOT=/opt/svn
##增量备份文件存放路径
date=
(
d
a
t
e
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
s
t
r
i
n
g
"
>
′
+
R
A
R
S
T
O
R
E
=
/
u
s
r
/
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
b
u
i
l
t
i
n
"
>
l
o
c
a
l
<
/
s
p
a
n
>
/
s
v
n
/
s
v
n
b
a
c
k
u
p
/
i
n
c
r
e
m
e
n
t
/
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
v
a
r
i
a
b
l
e
"
>
(date <span class="hljs-string">'+%Y-%m-%d'</span>) RAR_STORE=/usr/<span class="hljs-built_in">local</span>/svn/svn_backup/increment/<span class="hljs-variable">
(date<spanclass="hljs−string">′+RARSTORE=/usr/<spanclass="hljs−builtin">local</span>/svn/svnbackup/increment/<spanclass="hljs−variable">date
if [ ! -d "
R
A
R
S
T
O
R
E
<
/
s
p
a
n
>
"
<
/
s
p
a
n
>
]
;
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
k
e
y
w
o
r
d
"
>
t
h
e
n
<
/
s
p
a
n
>
m
k
d
i
r
−
p
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
v
a
r
i
a
b
l
e
"
>
RAR_STORE</span>"</span> ];<span class="hljs-keyword">then</span> mkdir -p <span class="hljs-variable">
RARSTORE</span>"</span>];<spanclass="hljs−keyword">then</span>mkdir−p<spanclass="hljs−variable">RAR_STORE
fi
##日志存放目录
Log_PATH=/usr/local/svn/svn_backup/log
if [ ! -d "
L
o
g
P
A
T
H
<
/
s
p
a
n
>
"
<
/
s
p
a
n
>
]
;
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
k
e
y
w
o
r
d
"
>
t
h
e
n
<
/
s
p
a
n
>
m
k
d
i
r
−
p
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
v
a
r
i
a
b
l
e
"
>
Log_PATH</span>"</span> ];<span class="hljs-keyword">then</span> mkdir -p <span class="hljs-variable">
LogPATH</span>"</span>];<spanclass="hljs−keyword">then</span>mkdir−p<spanclass="hljs−variable">Log_PATH
fi
##读取项目库列表
cd $SVN_REPOROOT
for name in
(
l
s
)
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
k
e
y
w
o
r
d
"
>
d
o
<
/
s
p
a
n
>
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
k
e
y
w
o
r
d
"
>
i
f
<
/
s
p
a
n
>
[
!
−
d
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
s
t
r
i
n
g
"
>
"
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
v
a
r
i
a
b
l
e
"
>
(ls) <span class="hljs-keyword">do</span> <span class="hljs-keyword">if</span> [ ! -d <span class="hljs-string">"<span class="hljs-variable">
(ls)<spanclass="hljs−keyword">do</span><spanclass="hljs−keyword">if</span>[!−d<spanclass="hljs−string">"<spanclass="hljs−variable">RAR_STORE/
n
a
m
e
<
/
s
p
a
n
>
"
<
/
s
p
a
n
>
]
;
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
k
e
y
w
o
r
d
"
>
t
h
e
n
<
/
s
p
a
n
>
m
k
d
i
r
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
v
a
r
i
a
b
l
e
"
>
name</span>"</span> ];<span class="hljs-keyword">then</span> mkdir <span class="hljs-variable">
name</span>"</span>];<spanclass="hljs−keyword">then</span>mkdir<spanclass="hljs−variable">RAR_STORE/$name
fi
cd
R
A
R
S
T
O
R
E
<
/
s
p
a
n
>
/
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
v
a
r
i
a
b
l
e
"
>
RAR_STORE</span>/<span class="hljs-variable">
RARSTORE</span>/<spanclass="hljs−variable">name
if [ ! -d “
L
o
g
P
A
T
H
<
/
s
p
a
n
>
/
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
v
a
r
i
a
b
l
e
"
>
Log_PATH</span>/<span class="hljs-variable">
LogPATH</span>/<spanclass="hljs−variable">name” ];then
mkdir
L
o
g
P
A
T
H
<
/
s
p
a
n
>
/
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
v
a
r
i
a
b
l
e
"
>
Log_PATH</span>/<span class="hljs-variable">
LogPATH</span>/<spanclass="hljs−variable">name
fi
echo ******Starting backup from KaTeX parse error: Expected 'EOF', got '&' at position 19: …e</span>****** &̲gt;> <span c…Log_PATH/
n
a
m
e
<
/
s
p
a
n
>
/
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
v
a
r
i
a
b
l
e
"
>
name</span>/<span class="hljs-variable">
name</span>/<spanclass="hljs−variable">name.log
echo ******svn repository KaTeX parse error: Expected 'EOF', got '&' at position 39: …o backup****** &̲gt;> <span c…Log_PATH/
n
a
m
e
<
/
s
p
a
n
>
/
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
v
a
r
i
a
b
l
e
"
>
name</span>/<span class="hljs-variable">
name</span>/<spanclass="hljs−variable">name.log
S
V
N
L
O
O
K
<
/
s
p
a
n
>
y
o
u
n
g
e
s
t
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
v
a
r
i
a
b
l
e
"
>
SVN_LOOK</span> youngest <span class="hljs-variable">
SVNLOOK</span>youngest<spanclass="hljs−variable">SVN_REPOROOT/KaTeX parse error: Expected 'EOF', got '&' at position 13: name</span> &̲gt; <span class…Log_PATH/A.TMP
UPPER=head -1 <span class="hljs-variable">$Log_PATH</span>/A.TMP
##取出上次备份后的版本号,并做+1处理
NUM_LOWER=head -1 <span class="hljs-variable">$Log_PATH</span>/<span class="hljs-variable">$name</span>/last_revision.txt
let LOWER="$NUM_LOWER+1"
##开始做增量备份并记录
U
P
P
E
R
,
为
下
次
备
份
做
准
备
<
/
s
p
a
n
>
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
v
a
r
i
a
b
l
e
"
>
UPPER,为下次备份做准备</span> <span class="hljs-variable">
UPPER,为下次备份做准备</span><spanclass="hljs−variable">SVN_ADMIN dump
S
V
N
R
E
P
O
R
O
O
T
<
/
s
p
a
n
>
/
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
v
a
r
i
a
b
l
e
"
>
SVN_REPOROOT</span>/<span class="hljs-variable">
SVNREPOROOT</span>/<spanclass="hljs−variable">name -r
L
O
W
E
R
<
/
s
p
a
n
>
:
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
v
a
r
i
a
b
l
e
"
>
LOWER</span>:<span class="hljs-variable">
LOWER</span>:<spanclass="hljs−variable">UPPER --incremental >
R
A
R
S
T
O
R
E
<
/
s
p
a
n
>
/
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
v
a
r
i
a
b
l
e
"
>
RAR_STORE</span>/<span class="hljs-variable">
RARSTORE</span>/<spanclass="hljs−variable">name/
L
O
W
E
R
<
/
s
p
a
n
>
−
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
v
a
r
i
a
b
l
e
"
>
LOWER</span>-<span class="hljs-variable">
LOWER</span>−<spanclass="hljs−variable">UPPER.dump
rm -f
L
o
g
P
A
T
H
<
/
s
p
a
n
>
/
A
.
T
M
P
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
b
u
i
l
t
i
n
"
>
e
c
h
o
<
/
s
p
a
n
>
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
v
a
r
i
a
b
l
e
"
>
Log_PATH</span>/A.TMP <span class="hljs-built_in">echo</span> <span class="hljs-variable">
LogPATH</span>/A.TMP<spanclass="hljs−builtin">echo</span><spanclass="hljs−variable">UPPER >
L
o
g
P
A
T
H
<
/
s
p
a
n
>
/
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
v
a
r
i
a
b
l
e
"
>
Log_PATH</span>/<span class="hljs-variable">
LogPATH</span>/<spanclass="hljs−variable">name/last_revision.txt
echo This time we bakcup from
L
O
W
E
R
<
/
s
p
a
n
>
t
o
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
v
a
r
i
a
b
l
e
"
>
LOWER</span> to <span class="hljs-variable">
LOWER</span>to<spanclass="hljs−variable">UPPER >>
L
o
g
P
A
T
H
<
/
s
p
a
n
>
/
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
v
a
r
i
a
b
l
e
"
>
Log_PATH</span>/<span class="hljs-variable">
LogPATH</span>/<spanclass="hljs−variable">name/KaTeX parse error: Expected 'EOF', got '&' at position 118: …up ended****** &̲gt;> <span c…Log_PATH/
n
a
m
e
<
/
s
p
a
n
>
/
<
s
p
a
n
c
l
a
s
s
=
"
h
l
j
s
−
v
a
r
i
a
b
l
e
"
>
name</span>/<span class="hljs-variable">
name</span>/<spanclass="hljs−variable">name.log
done
一种不需要数据库的存储系统。FSFS版本库在单一文件中存储修订版本树,所以版本库中所有的修订版本都在一个子文件夹中有限的几个文件里。事务在单独的子目录中被创建,创建完成后,一个单独的事务文件被创建并移动到修订版本目录,这保证提交是原子性的。因为一个修订版本文件是持久不可改变的,版本库也可以做到热备份,就象Berkeley DB版本库一样。
修订版本文件格式代表了一个修订版本的目录结构,文件内容,和其它修订版本树中相关信息。不像Berkeley DB数据库,这种存储格式可跨平台并且与CPU架构无关。因为没有日志或用到共享内存的文件,数据库能被网络文件系统安全的访问和在只读环境下检查。缺少数据库花消同时也意味着版本库的总体体积可以稍小一点。
FSFS也有一种不同的性能特性。当提交大量文件时,FSFS使用O(N)算法来追加条目,而Berkeley DB则用(N^2)算法来重写整个目录。另一方面,FSFS通过写入与上一个版本比较的变化来记录新版本,这也意味着获取最新修订版本时会比Berkeley DB慢一点,提交时FSFS也会有一个更长的延迟,在某些极端情况下会导致客护端在等待回应时超时。
最重要的区别是当出现错误时FSFS不会楔住的能力。如果使用Berkeley DB的进程发生许可错误或突然崩溃,数据库会一直无法使用,直到管理员恢复。假如在应用FSFS版本库时发生同样的情况,版本库不会受到任何干扰,最坏情况下也就是会留下一些事务数据。
唯一真正对FSFS不利的是相对于Berkeley DB的不成熟,缺乏足够的使用和压力测试,许多关于速度和可扩展性的判断都是建立在良好的猜测之上。在理论上,它承诺会降低管理员新手的门槛并且更加不容易发生问题。在实践中,只有时间可以证明。
总之,这两个中并没有一个是更正式的,访问版本库的程序与采用哪一种实现方式无关。通过上文和下表(从总体上比较了Berkeley DB和FSFS版本库),读者可以自行选择自己需要的存储方式。