1. SVN从1.4开始包含了同步功能,通过使用svnsync功能可以使一个SVN库与另一地点的SVN同步内容,可以起到热备和回收资源的功能。
1. 同步异地配置库,从而尝试支持驻外实施人员的附加开发工作。
2. 将项目现场搭建的配置环境内容备份回公司。
1. Subversion服务器两台A、B,部署在不同机器上,做测试可临时安放在同一台机器上;
2. 两个SVN数据库,(源库A,镜像库B)名称可以相同也可不同,其A为主库,B为备份库,备份库必须为空(无任何项目结构);
3. 需要svn命令行操作svn,需要管理员权限
1. 建立目标库B,库名为synctest,并开启synctest库服务
2. 建立相同名称的用户,并赋予其对目标数据库的读写权限,建议使用管理员用户
3. 设置hook内容,并赋予hook文件权限
4. 初始化需要同步的两个数据库
5. 执行正式同步
6. 异常同步处理
1. 机器240上建立目标SVN库B(synctest),对应机器27上得原库A(test),因为新建立的库没有内容,所以这里使用svn://192.168.60.27:3688 test库作为原库。
mkdir /opt/svndata
svnadmin create /opt/svndata/repos_synctest
接着开启镜像库synctest的服务,对应test库,同样使用3688端口
svnserve -d --listen-port=3688 -r /opt/svndata/repos_synctest
通过客户端登陆svn://192.168.60.240:3688,发现可正常登陆(因为还未对配置文件进行配置,所以还没有用户认证,直接可以在客户端进行登陆)
2. 修改配置文件,建立专用同步用户并赋予其镜像库synctest的可读可写权限
在机器240上
#cd /opt/svndata/synctest/conf
将svnserve.conf去掉下面几行的注释并修改:
anon-access = none(无授权用户将无法访问SVN库)
auth-access = write
password-db = passwd
authz-db = authz
realm = /opt/svndata/repos_synctest
修改密码文件password
在文件最后加上专用同步用户test,并设置密码
syncuser = syncuser
修改权限控制文件authz
在文件最后加上
[/]
syncuser = rw
同步用户test拥有对镜像库synctest的可读可写权限
3. 进入目标库的存放目录,找到同步钩子脚本pre-revprop-change.tmp(关于此钩子脚本,在下文的补充中有详细介绍),复制并改名为:pre-revprop-chang,使用编辑器编辑其内容,将所有内容删除或者使用“#”注释掉,最后一行写如下命令:“exit 0”(不包含双引号),保存退出即可。
4. 初始化两个SVN库之前,需要将pre-revprop-chang文件权限升级,否则执行初始化命令时会出现如下错误:
使用chomd 775 pre-revpro-chang命令将文件权限升级
在命令行下输入命令:
svnsync init svn://192.168.60.240:3688 svn://192.168.60.27:3688 ,按照提示分别输入root命令和镜像库B专用同步用户名test和密码,开始进行初始化
完成初始化出现以下提示:
(或者 svnsync init file:///opt/svndata/某个svn库 svn://192.168.60.27:3688 )
5. 此时可以使用:svnsync sync svn://192.168.60.240:3688进行正式同步操作
报错 access denied,未知何因。用下面括号中命令可顺利进行
svnsync sync file:///opt/svndata/repos_synctest
6. 同步完成后可以使用有权限的用户在目标库中查看同步的结果完整性,同步过程不会将用户也同步过来,需要重新建立用户和权限规则。如果过程中出现异常,如传送数据连接异常断开时同步会受到影响,你可能会得到以下错误:
由于同步过程中svn会形成一个锁定属性,来保持数据库的锁定状态,如果中间意外停止,则仍然会保持锁定,下次同步会提示获得锁失败,使用下面的命令将锁定去掉可以继续同步:
svn propdel svn:sync-lock --revprop -r 0 svn://192.168.60.240:3688/opt/svndata/synctest
7. 如果原始版本库的地址改变了(比如说换了域名或者IP地址),在svn中可以使用 svn relocate 来实现,但在svnsync中,就必须用propset来实现了,具体代码如下:
svn propget svn:sync-from-url --revprop -r 0 svn://192.168.4.240:3689/opt/svndata/newrepos
#这个操作会显示原始版本库的地址(假如你忘了原始地址时就很有用)
#显示地址如右:svn://192.168.4.247:3689
关于pre-revprop-chang脚本
pre-revprop-chang脚本是修订版本属性修改的通知。
pre-revprop-change 钩子在修改版本属性修改之前,正常提交范围之外被执行。不像其它钩子,这个钩子默认是拒绝所有的属性修改,钩子必须实际存在,并且返回一个零值,这样才能修改属性。如果 pre-revprop-change 钩子不存在,不可执行,或返回非零值,就不能修改属性。
自动实时同步需要在源SVN服务器192.168.60.27上进行配置。
#cd /opt/svndata/test/hooks
该目录有两个重要的文件:pre-commit.tmpl和post-commit.tmpl
pre-commit.tmpl:该文件是SVN每次提交之前都要执行的脚本;
post-commit.tmpl:该文件是SVN每次提交之后执行的脚本。
只需要将svnsync sync --non-interactive --username test --password test
svn://192.168.60.240:3688输入到脚本最后,即可实现自动实时同步设置。
建议:最好使用post-commit脚本,而非pre-commit中,如果使用pre-commit脚本,则是每次提交前同步,显然镜像库会比源库一直会落后一个版本。
#cp post-commit.tmpl post-commit
#chmod +x post-commit
#chmod 777 post-commit
在文件的最后加上命令:
svnsync sync --non-interactive svn://192.168.4.240:3689 --source-username guli --source-password guli --sync-username syncuser --sync-password syncuser
svnsync sync --non-interactive svn://192.168.4.241:3689 --source-username guli --source-password guli --sync-username syncuser --sync-password syncuser
(实际配置时,需将源数据账户、密码及镜像账户、密码填入方能成功实时拷贝 )
即可实现。
根据以上配置以后,在源库SVN上提交相应的文件版本更新后,镜像库也会同步更新。
自动定时同步在镜像库服务器192.168.60.240上进行配置,这里我们使用cron来实现。
cron 是一个可以用来根据时间、日期、月份、星期的组合来调度对重复任务的执行的守护进程。
#vim /etc/crontab
根据文件要求格式,在文件最后一行加上命令:
*/1 * * * * root /usr/bin/svnsync sync svn://192.168.60.240:3688 --non-interactive --username test --password test
(*/1此处表明每隔一分钟执行一次以上命令)
同步日志可查看邮件:/var/spool/mail/root
关于/etc/crontab文件的格式
crontab中每列代表的含义:
· minute — 分钟,从 0 到 59 之间的任何整数
· hour — 小时,从 0 到 23 之间的任何整数
· day — 日期,从 1 到 31 之间的任何整数(如果指定了月份,必须是该月份的有效日期)
· month — 月份,从 1 到 12 之间的任何整数(或使用月份的英文简写如 jan、feb 等等)
· dayofweek — 星期,从 0 到 7 之间的任何整数,这里的 0 或 7 代表星期日(或使用星期的英文简写如 sun、mon 等等)
· command — 要执行的命令(命令可以是 ls /proc >> /tmp/proc 之类的命令,也可以是执行你自行编写的脚本的命令。)
在以上任何值中,星号(*)可以用来代表所有有效的值。譬如,月份值中的星号意味着在满足其它制约条件后每月都执行该命令。
整数间的短线(-)指定一个整数范围。譬如,1-4 意味着整数 1、2、3、4。
用逗号(,)隔开的一系列值指定一个列表。譬如,3, 4, 6, 8 标明这四个指定的整数。
正斜线(/)可以用来指定间隔频率。在范围后加上 /<integer> 意味着在范围内可以跳过 integer。譬如,0-59/2 可以用来在分钟字段定义每两分钟。间隔频率值还可以和星号一起使用。例如,*/3 的值可以用在月份字段中表示每三个月运行一次任务。