III(二十一)SVN

svn,subversion版本管理工具:

安装优化软件环境,如httpd,lvs等(运维工程师);

程序代码(不断更新)(开发工程师,开发+运维);

配置变更(不断变更)(运维工程师)

SVN是近年来崛起的非常优秀的版本管理工具,与CVS管理工具类似,SVN是新开发的版本控制系统,修正了CVS所未解决的问题;

SVN是一个跨平台的开源的版本控制系统,是一个非常通用的软件系统,它常被用来管理程序源码,但它可管理任何类型的文件,如文本、视频、图片等等,管理着随时间变化的各种数据,这些数据放置在一个叫中央资料库repository中,这个档案库很像一个普通的file server(FTP server),但不同的是SVN会备份并记录每个文件每一次的修改更新变动,这样我们就可把任意一个时间点的档案恢复到想要的之前的版本,也可直接浏览指定文件的更新历史记录;

http://subversion.tigris.org/

http://subversion.apache.org/

版本管理软件有:VSS(microsoft)、CVS、SVN、git

SVN是集中式的数据管理,存在一个中央版本库,所有开发人员本地开发所使用的代码都是来自于这个版本库,提交代码也都必须提交到这个中央版本库,其工作流程:

在中央版本库上创建或从主干上复制一个分支;

从中央库check out下这个分支的代码;

增加自己的代码文件,修改现存的代码或删除代码文件;

commit代码,假设有人在刚刚的分支上提交了代码,你就会被提示代码过期,你得先update你的代码后再commit,若update时有冲突要解决好冲突再commit

注:当由于网络原因无法连接到中央版本库的环境下,则无法commit代码,无法查看代码的历史版本及版本的变化过程;由于代码集中管理,因此需要对中央版本库的存储做备份,在这点上分布式版本控制系统要好些,对SVN的备份要备份所有代码数据还有所有更改的版本记录

git分布式版本控制,linux开发,git和linux的FS结合紧密,在win上要使用cygwin才能完美工作,git没有中央版本库的概念,但为了开发小组的代码共享,通常还是会搭建一个远程的git仓库,git和svn不同的是,使用git开发者在本地也包含了一个完整的git仓库,本地的仓库和远程的仓库在身份上是等价的,没有主从之分,若使用git像svn那样集中管理的话,步骤如下:

在本地创建一个git仓库,并将其add到远程git库中;

在本地修改代码、添加或删除文件,再commit提交到本地的git仓库中,具体位置是git/objects/下;

将本地git库的分支push到远程git库的分支,若远程git库中已有人push过则不允许你push,这时你要先pull,在处理好冲突后,commit到本地再push到远程git库

注:每个开发人员的本地都有一个git库,可随时commit到本地的git库,可随时查看历史版本,当某一个功能点开发完了之后将commit后的内容push到远程git库,如果远程git库的版本在你上次clone或pull之后发生了变化,那这时要先pull并处理冲突,再次commit之后再push到远程git库

运维人员掌握版本管理:

安装、部署、维护、排障;

简单使用,很多公司都由开发管理,包括建立仓库、添加删除帐号;

对于版本控制系统,运维人员相当于开发商,开发人员是业主,运维搭建的系统为开发人员服务的

SVN服务端访问方式(3种):

svn://svn.mydomain.com/sadoc(独立服务器访问);

http://svn.mydomain.com/sadoc(借助httpd服务,用CSVN这是个单独的整合了httpd和svn的软件;或者分别单独安装httpd和svn);

file:///application/svdata/sadoc(本地直接访问)

SVN客户端的访问方式:

svn://(通过tcp/ip自定义协议访问svnserver);

http://(通过WEBDAV协议访问支持subversion的httpd server);

svn+ssh://(通过认证并加密的tcp/ip自定义协议访问svnserver);

https://(ssl加密的http);

file://(直接通过本地磁盘或网络磁盘)

SVN档案库数据格式(2种,BDB和FSFS):

BDB(Berkeley DB,事务安全型表类型,一种经过充分测试的后台数据库实现,不能在网络共享的文件系统上使用,是subversion1.2版本之前的默认版本库格式,BDB格式方式在服务器中断时有可能锁住数据,还是使用FSFS更安全些);

FSFS(专用于subversion版本库的文件系统后端,可使用网络文件系统,如NFS、SMBFS,是1.2版本之后的默认版本库格式)

注:SVN是基于关系数据的BDB或一系列二进制文件的FSFS,这解决了一些问题,如并行读写共享文件和运行时的事务特性,由此数据存储变得不透明,像分布式文件系统那样要通过API接口才能访问,不能像FTP、samba、NFS一样看不到实体文件(不能直接查看文件);MySQL在5.5之前默认storage engine是MyISAM,而5.5之后默认是InnoDB

SVN系统逻辑架构图:

注:集中式代码管理的核心是SVN server,所有开发者在开始新一天的工作之前必须从server获取代码,然后进行开发,最后解决冲突、提交,所有的版本信息都放在SVN server上,若脱离了SVN server,开发者就无法进行提交代码工作

[[email protected] ~]# uname -a

Linux localhost.localdomain2.6.32-431.el6.x86_64 #1 SMP Sun Nov 10 22:19:54 EST 2013 x86_64 x86_64 x86_64GNU/Linux

[[email protected] ~]# uname -rm

2.6.32-431.el6.x86_64 x86_64

[[email protected] ~]# cat /etc/redhat-release

Red Hat Enterprise Linux Server release 6.5(Santiago)

[[email protected] ~]# rpm -qa subversion   #(若对功能无特殊要求,首选使用yum方式安装rpm二进制软件包,这样最便捷)

subversion-1.6.11-9.el6_4.x86_64

[[email protected] ~]# sed -i ‘s/keepcache=0/keepcache=1/g‘ /etc/yum.conf  #(若用的是网络yum源,yum方式安装rpm包后本地不清除rpm二进制包,方便以后使用)

[[email protected] ~]# grep ‘keepcache‘ /etc/yum.conf

keepcache=1

[[email protected] ~]# rpm -ql subversion

/etc/bash_completion.d

/etc/bash_completion.d/subversion

/etc/rc.d/init.d/svnserve

/etc/subversion

/usr/bin/svn

/usr/bin/svnadmin

/usr/bin/svndumpfilter

/usr/bin/svnlook

/usr/bin/svnserve

/usr/bin/svnsync

/usr/bin/svnversion

[[email protected] ~]# mkdir -pv /application/{svndata/,svnpasswd/}   #(创建SVN server数据存储根目录、用户密码权限目录使密码集中存放)

mkdir: created directory `/application‘

mkdir: created directory`/application/svndata/‘

mkdir: created directory`/application/svnpasswd/‘

[[email protected] ~]# tree /application

/application

├── svndata

└── svnpasswd

2 directories, 0 files

[[email protected] ~]# svnserve --help

usage: svnserve [-d | -i | -t | -X][options]

Valid options:

-d [--daemon]            : daemon mode

-i[--inetd]             : inetd mode

-t[--tunnel]            : tunnel mode

-X[--listen-once]       : listen-once mode(useful for debugging)

-r [--root] ARG          : root of directory to serve

-R[--read-only]         : force read only,overriding repository config file

--config-file ARG        : readconfiguration from file ARG

--listen-port ARG        : listen port

[mode: daemon,listen-once]

--listen-host ARG        : listenhostname or IP address

[mode: daemon, listen-once]

-T[--threads]           : use threadsinstead of fork [mode: daemon]

--foreground             : run inforeground (useful for debugging)

[mode: daemon]

--log-file ARG           :svnserve log file

--pid-file ARG           : write server process ID to file ARG

[mode: daemon,listen-once]

--tunnel-user ARG        : tunnelusername (default is current uid‘s name)

[mode: tunnel]

-h[--help]              : display this help

--version                : showprogram version information

[[email protected] ~]# svnadmin help   #(与mysqladmin命令类似)

general usage: svnadmin SUBCOMMANDREPOS_PATH  [ARGS & OPTIONS ...]

Type ‘svnadmin help <subcommand>‘ forhelp on a specific subcommand.

Type ‘svnadmin --version‘ to see theprogram version and FS modules.

Available subcommands:

crashtest

create

deltify

dump

help (?, h)

hotcopy

list-dblogs

list-unused-dblogs

load

lslocks

lstxns

pack

recover

rmlocks

rmtxns

setlog

setrevprop

setuuid

upgrade

verify

[[email protected] ~]# svnadmin help create   #(创建版本库,相当于站点目录)

create: usage:svnadmin create REPOS_PATH

Create a new, empty repository at REPOS_PATH.

Valid options:

--bdb-txn-nosync         : disablefsync at transaction commit [Berkeley DB]

--bdb-log-keep           : disableautomatic log file removal [Berkeley DB]

--config-dir ARG         : readuser configuration files from directory ARG

--fs-type ARG            : type ofrepository: ‘fsfs‘ (default) or ‘bdb‘

--pre-1.4-compatible     : useformat compatible with Subversion versions

earlier than 1.4

--pre-1.5-compatible     : useformat compatible with Subversion versions

earlier than 1.5

--pre-1.6-compatible     : useformat compatible with Subversion versions

earlier than 1.6

[[email protected] ~]# svnserve -d -r /application/svndata   #(或使用#service svnserve start)

注:若在开启进程时使用了选项--pid-file /application/svndata/svn.pid,使用脚本关闭进程时用kill -9 `cat /application/svndata/svn.pid`

[[email protected] ~]# ps aux | grep svnserve

root     14564  0.0  0.4 165132  952 ?        Ss   18:39  0:00 svnserve -d -r /application/svndata

root     14568  0.0  0.3 103252  828 pts/0    S+   18:39  0:00 grep svnserve

[[email protected] ~]# netstat -tnulp | grep :3690   #(服务端默认端口3690)

tcp       0      0 0.0.0.0:3690                0.0.0.0:*                   LISTEN      14564/svnserve

[[email protected] ~]# lsof -i :3690

COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME

svnserve 14564 root    3u IPv4 230894      0t0  TCP *:svn (LISTEN)

[[email protected] ~]# svnadmin create /application/svndata/sadoc   #(默认已指定为--fs-typeFSFS,若要用bdb可在创建时指定--fs-type bdb)

[[email protected] ~]# tree /application/svndata/sadoc   #(conf/,db/,hooks/等)

/application/svndata/sadoc

├── conf

│   ├── authz

│   ├── passwd

│   └── svnserve.conf

├── db

│   ├── current

│   ├── format

│   ├── fsfs.conf

│   ├── fs-type

│   ├── min-unpacked-rev

│   ├── rep-cache.db

│   ├── revprops

│   │   └── 0

│   │       └── 0

│   ├── revs

│   │   └── 0

│   │       └── 0

│   ├── transactions

│   ├── txn-current

│   ├── txn-current-lock

│   ├── txn-protorevs

│   ├── uuid

│   └── write-lock

├── format

├── hooks

│   ├── post-commit.tmpl

│   ├── post-lock.tmpl

│   ├── post-revprop-change.tmpl

│   ├── post-unlock.tmpl

│   ├── pre-commit.tmpl

│   ├── pre-lock.tmpl

│   ├── pre-revprop-change.tmpl

│   ├── pre-unlock.tmpl

│   └── start-commit.tmpl

├── locks

│   ├── db.lock

│   └── db-logs.lock

└── README.txt

[[email protected] ~]# cd /application/svndata/sadoc/conf   #(svnserve.conf包含了authz和passwd,默认每个版本库下会有自己的密码文件,为统一管理指定密码文件位置,将authz和passwd放到/application/svnpasswd/下)

[[email protected] conf]# ll

total 12

-rw-r--r--. 1 root root 1080 Jun 22 18:57authz

-rw-r--r--. 1 root root  309 Jun 22 18:57 passwd

-rw-r--r--. 1 root root 2279 Jun 22 18:57svnserve.conf

[[email protected] conf]# cp svnserve.conf svnserve.conf.ori   #(备份,两个目的:改错了恢复;对比改过什么)

[[email protected] conf]# cp authz passwd /application/svnpasswd/   #(将authz和passwd放到/application/svnpasswd/下)

[[email protected] conf]# chmod 700 /application/svnpasswd/*

[[email protected] conf]# vim svnserve.conf

[general]

anon-access = none

auth-access = write

password-db =/application/svnpasswd/passwd

authz-db =/application/svnpasswd/authz

[[email protected] conf]# diff svnserve.conf svnserve.conf.ori   #(用diff命令比较,或使用egrep查看)

12,13c12,13

< anon-access = none

< auth-access = write

---

> # anon-access = read

> # auth-access = write

20c20

< password-db =/application/svnpasswd/passwd

---

> # password-db = passwd

27c27

< authz-db =/application/svnpasswd/authz

---

> # authz-db = authz

[[email protected] conf]# egrep ‘\-access|\-db‘ svnserve.conf

anon-access = none

auth-access = write

### The password-db option controls thelocation of the password

password-db = /application/svnpasswd/passwd

### The authz-db option controls thelocation of the authorization

### authz-db, no path-based access controlis done.

authz-db = /application/svnpasswd/authz

[[email protected] conf]# cd /application/svnpasswd/

[[email protected] svnpasswd]# vim passwd   #(在users段添加用户名和密码,密码明文,注意权限700)

[users]

root = chai

snow = snow123

[[email protected] svnpasswd]# vim authz

[groups]

sagroup = root,snow

[sadoc:/]

@sagroup = r

root = rw

snow = r

[[email protected] svnpasswd]# pkill svnserve

[[email protected] svnpasswd]# lsof -i :3690

[[email protected] sadoc]# svnserve -d -r /application/svndata   #(修改svnserve.conf后要重启svnserv,修改authz或passwd则不需重启)

[[email protected] svnpasswd]# lsof -i :3690

COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME

svnserve 14802 root    3u IPv4 237048      0t0  TCP *:svn (LISTEN)

注authz文件:

一个用户组可包含1个或多个用户,各用户间用逗号分隔,用户要在passwd文件中存在;

版本库目录格式为:

[<版本库>:/项目名/目录]

@<用户组名> = <权限>

<用户名> = <权限>

权限有r、w、rw和空

win下的客户端软件TortoiseSVN:

在win下任意位置创建一目录例如svndata/,右键该目录选SVN checkout(仅第一次是checkout,之后都是SVN update):

在URL of repository填:svn://192.168.194.128/sadoc;

在Checkout directory填:本地的目录;-->OK

右键该目录,选TortoiseSVN-->常用的有:Repo-browser(直接查看SVNserver上的版本库)、Setting-->Saved data(可清空所有保存的密码记录)、ShowLog、Relocate(SVNserver改变了);

注:

目录颜色(绿色对号(正常)、蓝色问号(不同步状态));

提交过程中显示的颜色(蓝色(提交一个修改);紫色(提交一个新增项);深红(提交一个删除或替换);黑色(所有其它项));

在运行中输入%APPDATA%\Subversion\auth,可在此目录下删除指定的密码文件

Linux下客户端使用:

[[email protected] ~]# rpm -q subversion

subversion-1.6.11-9.el6_4.x86_64

[[email protected] ~]# svn --help

usage: svn<subcommand> [options] [args]

……

Available subcommands:

add

blame (praise, annotate, ann)

cat

changelist (cl)

checkout (co)

cleanup

commit (ci)

copy (cp)

delete (del, remove, rm)

diff (di)

export

help (?, h)

import

info

list (ls)

lock

log

merge

mergeinfo

mkdir

move (mv, rename, ren)

propdel (pdel, pd)

propedit (pedit, pe)

propget (pget, pg)

proplist (plist, pl)

propset (pset, ps)

resolve

resolved

revert

status (stat, st)

switch (sw)

unlock

update (up)

注:常用的subcommand:

add(添加本地文件到本地的版本库,通过commit才能到SVNserver的中央版本库);

checkout或co(从源码库取出一个工作版本的拷贝);

commit或ci(提交当前工作拷贝的更改,有可能会有冲突);

update或up(将SVNserver端文件同步到本地);

list或ls(查看)

[[email protected] ~]# svn --help add

usage: add PATH...

[[email protected] ~]# svn --help checkout

usage: checkoutURL[@REV]... [PATH]

[[email protected] ~]# svn --help commit

usage: commit [PATH...]

[[email protected] ~]# svn --help update

usage: update [PATH...]

[[email protected] ~]# svn --help list

usage: list[TARGET[@REV]...]

[[email protected] ~]# svn --help cat

cat: Output the content of specified filesor URLs.

usage: catTARGET[@REV]...

svn-client:

[[email protected] ~]# mkdir /svndata   #(client创建此目录存放checkout的数据)

[[email protected] ~]# svn checkout svn://192.168.194.128/sadoc/ /svndata --username root --password chai   #(从SVNserver库提取数据,若有中文名称的文件可能会报错,此报错是linux不支持中文编码,要做字符集调整,包括系统字符集和终端的编码,#export LC_CTYPE="en_US.UTF-8";export LC_ALL=;locale)

A   /svndata/test.txt

Checked out revision 3.

[[email protected] ~]# svn list svn://192.168.194.128/sadoc/ --username root --password chai

test.txt

[[email protected] ~]# svn list svn://192.168.194.128/sadoc/ --verbose --username root --password chai

3 root                  Jun 2222:13 ./

2 root                0 Jun 2222:12 test.txt

[[email protected] ~]# svn cat svn://192.168.194.128/sadoc/test.txt

[[email protected] ~]# cd /svndata

[[email protected] svndata]# touch {a,b,c,d}.txt

[[email protected] svndata]# svn add a.txt b.txt c.txt d.txt

A        a.txt

A        b.txt

A        c.txt

A        d.txt

[[email protected] svndata]# svn commit -m ‘svn commit data‘   #(只有输入信息才能提交成功)

Adding         a.txt

Adding        b.txt

Adding         c.txt

Adding         d.txt

Transmitting file data ....

Committed revision 4.

svn import(用于将client的一组文件添加到SVNserver上):

[[email protected] svndata]# svn help import

import: Commit an unversioned file or treeinto the repository.

usage: import [PATH] URL

Recursively commit a copy of PATH to URL.

SVNserver-side:

[[email protected] svndata]# pwd

/application/svndata

[[email protected] svndata]# svnadmin create /application/svndata/project1   #(先在服务端创建项目版本库)

[[email protected] svndata]# ll

total 8

drwxr-xr-x. 6 root root 4096 Jun 22 22:40project1

drwxr-xr-x. 6 root root 4096 Jun 22 18:57sadoc

[[email protected] ~]# vim /application/svndata/project1/conf/svnserve.conf   #(要记得修改此文件,否则client会报错svn:Authorization failed)

[general]

anon-access = none

auth-access = write

password-db = /application/svnpasswd/passwd

authz-db = /application/svnpasswd/authz

[[email protected] ~]# vim /application/svnpasswd/authz

--------------------------file start--------------------

sagroup = root,snow

[sadoc:/]

@sagroup = r

root = rw

snow = r

[project1:/]

@sagroup = r

root = rw

snow = r

[/]

@sagroup = r

root = rw

snow = r

---------------------file end------------------

[[email protected] ~]# pkill svnserve

[[email protected] ~]# svnserve -d -r /application/svndata

client-side:

[[email protected] svndata]# mkdir -pv /svn/{trunk/,branch/,tag}   #(开发人员经常用这三个目录,trunk/保存开发的主线,branch/存放分支,tag/保存标签)

mkdir: created directory `/svn‘

mkdir: created directory `/svn/trunk/‘

mkdir: created directory `/svn/branch/‘

mkdir: created directory `/svn/tag‘

注:

trunk/(主线,与正式线相对应,当天不上线的文件不允许提交);

branch/(分去,测试用,几天以上的项目必须开分支,测试需要此分支通过,主线合并到分支通过,才能合并到主线进行测试);

tags/(版本记录用);

[[email protected] ~]# svn import /svn svn://192.168.194.128/project1/ -m ‘initial import‘

Authentication realm:<svn://192.168.194.128:3690> 93e7f148-de67-418e-9ada-6d669fb6087d

Password for ‘root‘:

-----------------------------------------------------------------------

ATTENTION! Your password for authentication realm:

<svn://192.168.194.128:3690> 93e7f148-de67-418e-9ada-6d669fb6087d

can only be stored to diskunencrypted!  You are advised toconfigure

your system so that Subversion can storepasswords encrypted, if

possible. See the documentation for details.

You can avoid future appearances of thiswarning by setting the value

of the ‘store-plaintext-passwords‘ optionto either ‘yes‘ or ‘no‘ in

‘/root/.subversion/servers‘.

-----------------------------------------------------------------------

Store password unencrypted (yes/no)? yes

Adding         /svn/trunk

Adding         /svn/tag

Adding         /svn/branch

Committed revision 1.

[[email protected] ~]# svn list svn://192.168.194.128/project1 --username root --password chai

branch/

tag/

trunk/

svn copy(将主干拷贝到分支):

[[email protected] ~]# svn copy svn://192.168.194.128/project1/trunk svn://192.168.194.128/project1/branch/branch_cms -m ‘create branch by jowin‘ --username root --password chai

Committed revision 2.

[[email protected] ~]# svn list svn://192.168.194.128/project1/branch --username root --password chai

branch_cms/

SVN钩子hooks:

钩子脚本如同shell脚本,钩子脚本是被某些版本库事件触发的程序,类似inotify和sersync,例如创建新版本或修改未被版本控制的属性,每个钩子都能掌管足够的信息来了解发生了什么事件、操作对象是什么及触发事件用户的帐号,根据钩子输出和返回状态,钩子程序能够以某种方式控制该动作继续执行、停止或挂起;

在某一项目目录的hooks/下有模板文件,以.tmpl为扩展名,去掉其扩展名即可使用;确保脚本正常运行:脚本中一定要设置好环境变量或使用命令时一律用绝对路径,否则会怪样百出,因为它不会继承系统的环境变量;

常用的钩子脚本:

post-commit(在提交后成功创建版本,再执行该钩子,提交已经完成不可更改,因此脚本的返回值被忽略,提交完成时触发事务);

pre-commit(提交完成前触发使用该脚本);

start-commit(在client还没向server提交数据之前,即还没有建立subversion transaction(txn)之前执行该脚本,提交前触发事务);

pre-revprop-change(在修改revision属性之前,执行该脚本);

post-revprop-change

pre-unlock(对文件进行解锁操作之前执行该脚本);

post-unlock

pre-lock(对文件进行加锁操作之前执行该脚本)

post-lock

SVN钩子生产应用场景:

pre-commit(限制上传文件扩展名(如压缩包、视频不能上传)、限制上传文件大小、控制提交时要输入的信息);

post-commit(提交后通过邮件、MSN告知指定人,SVN更新触发checkout程序,定时rsync推送到指定服务器);

[[email protected] ~]# cd /application/svndata/project1/hooks/

[[email protected] hooks]# ll

total 36

-rw-r--r--. 1 root root 1977 Jun 22 22:40post-commit.tmpl

-rw-r--r--. 1 root root 1638 Jun 22 22:40post-lock.tmpl

-rw-r--r--. 1 root root 2289 Jun 22 22:40post-revprop-change.tmpl

-rw-r--r--. 1 root root 1567 Jun 22 22:40post-unlock.tmpl

-rw-r--r--. 1 root root 3426 Jun 22 22:40pre-commit.tmpl

-rw-r--r--. 1 root root 2410 Jun 22 22:40pre-lock.tmpl

-rw-r--r--. 1 root root 2786 Jun 22 22:40pre-revprop-change.tmpl

-rw-r--r--. 1 root root 2100 Jun 22 22:40pre-unlock.tmpl

-rw-r--r--. 1 root root 2780 Jun 22 22:40start-commit.tmpl

案例一(rsync与svn hooks的post-commit实现数据实时同步,此例是将SVNserver上的数据同步至本地/tmp下):

[[email protected] ~]# mkdir -pv /data/www   #(在SVNserver上操作)

mkdir: created directory `/data‘

mkdir: created directory `/data/www‘

[[email protected] ~]# svn checkout svn://192.168.194.128/sadoc /data/www/ --username root --password chai

A   /data/www/2.txt

A   /data/www/b.txt

A   /data/www/3.txt

A   /data/www/c.txt

A   /data/www/d.txt

A   /data/www/test.txt

A   /data/www/1.txt

A   /data/www/a.txt

Checked out revision 5.

[[email protected] ~]# ifconfig | grep -A 1eth0

eth0     Link encap:Ethernet  HWaddr00:0C:29:1F:B6:AC

inet addr:192.168.194.128 Bcast:192.168.194.255 Mask:255.255.255.0

[[email protected] ~]# cd/application/svndata/sadoc/hooks

[[email protected] hooks]# cp post-commit.tmpl post-commit

[[email protected] hooks]# vim post-commit

---------------------script start-------------------

#!/bin/sh

REPOS="$1"

REV="$2"

mailer.py commit "$REPOS""$REV" /path/to/mailer.conf

export LANG="en_US.UTF-8"

export LC_CTYPE="en_US.UTF-8"

export LC_ALL=

LOGPATH="/app/log"

[ ! -d $LOGPATH ] && mkdir -p $LOGPATH

/usr/bin/svn update /data/www --username root --password chai

if [ $? -eq 0 ] ; then

/usr/bin/rsync -az --delete /data/www /tmp

fi

----------------------script end---------------------

[[email protected] hooks]# chmod 755 !$   #(注意钩子脚本要有执行权限,一般为755,且脚本中的路径最好用绝对路径,因为它不会继承系统环境变量,使用时要在脚本中重新设定环境变量,脚本svn update执行前要先手动svn checkout下)

chmod 755 post-commit

[[email protected] hooks]# ll post-commit

-rwxr-xr-x. 1 root root 2242 Jun 23 00:32post-commit

在win的client增删(或在Linux的client操作均可):

右键svndata选commit,OK

在SVNserver端查看:

[[email protected] hooks]# ll /tmp/www

total 0

-rw-r--r--. 1 root root 0 Jul 13 02:241.txt

-rw-r--r--. 1 root root 0 Jul 13 02:242.txt

-rw-r--r--. 1 root root 0 Jul 13 02:243.txt

-rw-r--r--. 1 root root 0 Jul 13 02:24a.txt

-rw-r--r--. 1 root root 0 Jul 13 02:24b.txt

-rw-r--r--. 1 root root 0 Jul 13 02:24c.txt

-rw-r--r--. 1 root root 0 Jul 13 02:24d.txt

-rw-r--r--. 1 root root 0 Jul 13 02:33rsync_test.txt

-rw-r--r--. 1 root root 0 Jul 13 02:24test.txt

或在Linux的client操作:

[[email protected] ~]# mkdir -p /data/www

[[email protected] ~]# svn checkout svn://192.168.194.128/sadoc/ /data/www --username root --password chai

[[email protected] ~]# cd /data/www

[[email protected] www]# ll

total 0

-rw-r--r--. 1 root root 0 Jun 23 00:181.txt

-rw-r--r--. 1 root root 0 Jun 23 00:182.txt

-rw-r--r--. 1 root root 0 Jun 23 00:183.txt

-rw-r--r--. 1 root root 0 Jun 23 00:18a.txt

-rw-r--r--. 1 root root 0 Jun 23 00:18b.txt

-rw-r--r--. 1 root root 0 Jun 23 00:18c.txt

-rw-r--r--. 1 root root 0 Jun 23 00:18d.txt

-rw-r--r--. 1 root root 0 Jul 13 02:57rsync_test.txt

-rw-r--r--. 1 root root 0 Jun 23 00:18 test.txt

[[email protected] www]# touch rsync.txt

[[email protected] www]# svn add rsync.txt

A        rsync.txt

[[email protected] www]# svn commit -m ‘svncommit data‘   #(只有输入信息才能提交成功)

Adding         rsync.txt

Transmitting file data .

Committed revision 10.

[[email protected] www]# ll

total 0

-rw-r--r--. 1 root root 0 Jun 23 00:181.txt

-rw-r--r--. 1 root root 0 Jun 23 00:182.txt

-rw-r--r--. 1 root root 0 Jun 23 00:183.txt

-rw-r--r--. 1 root root 0 Jun 23 00:18a.txt

-rw-r--r--. 1 root root 0 Jun 23 00:18b.txt

-rw-r--r--. 1 root root 0 Jun 23 00:18c.txt

-rw-r--r--. 1 root root 0 Jun 23 00:18d.txt

-rw-r--r--. 1 root root 0 Jul 13 02:57rsync_test.txt

-rw-r--r--. 1 root root 0 Jul 13 03:05rsync.txt

-rw-r--r--. 1 root root 0 Jun 23 00:18test.txt

[[email protected] www]# svn list svn://192.168.194.128/sadoc/ --verbose --username root --password chai

10 root                  Jul 1302:46 ./

5 root                0 Jun 2223:00 1.txt

5 root                0 Jun 2223:00 2.txt

5 root                0 Jun 22 23:00 3.txt

4 root                0 Jun 2222:29 a.txt

4 root                0 Jun 2222:29 b.txt

4 root                0 Jun 2222:29 c.txt

4 root                0 Jun 2222:29 d.txt

10 root                0 Jul 13 03:05rsync.txt

9 root                0 Jul 13 02:57rsync_test.txt

2 root                0 Jun 2222:12 test.txt

注:SVN hook案例逻辑架构

案例二(利用svn hooks的pre-commit限制上传文件扩展名及大小):

[[email protected] hooks]# vim pre-commit

--------------script start------------------

#!/bin/sh

REPOS="$1"

TXN="$2"

MAX_SIZE=5242880

FILTER=‘\.(zip|rar|o|obj|tar|gz)$‘

SVNLOOK=/usr/bin/svnlook

LOGMSG=`$SVNLOOK log -t "$TXN""$REPOS" | grep "[a-zA-Z0-9]" | wc -c`

if [ "$LOGMSG" -lt 9 ];then

echo -e "nLog message can‘t be empty!you must input more than 8 chars as comment!" 1>&2

exit 1

fi

files=$($SVNLOOK changed -t $TXN $REPOS |cut -d" " -f 4-)

rc=0

echo "$files" | while read f;do

if echo $f | tr A-Z a-z | grep -Eq $FILTER;then

echo "File $f is not allow($FILTER) file" >& 2

exit 1;

fi

filesize=`$SVNLOOK cat -t "$TXN""$REPOS" "$f" | wc -c`

if [ "$filesize" -gt "$MAX_SIZE" ];then

echo "File $f is too large(must <= $MAX_SIZE) B" >& 2

exit 1;

fi

done

if [ $? -eq 1 ];then

exit 1

else

exit 0

fi-------------script end--------------

[[email protected] hooks]# chmod 755 pre-commit

[[email protected] hooks]# ll pre-commit

-rwxr-xr-x. 1 root root 4087 Jul 13 03:57pre-commit

在win 的client试验:

在SVN commit时没写comment注释会提示报错;

在SVN commit压缩文档时提示报错;

在SVN commit大于5M的文件时,提示报错;

小型企业上线解决方案:

小型企业一般几个开发人员,且网站核心程序大多数都是php开发,为方便,会直接通过FTP上传程序代码到线上server,随时随地上线更新,此方案的问题:

发布快、及时、随时随地可发布代码;

开发人员发布的代码不经过测试人员的测试,且用户访问页面刷新后页面即改变,也可能刷新瞬间程序在更新,导致用户可能无法正常访问,对网站用户的体验较差,如果开发写错了代码,会造成更大的影响,这是拿用户作为测试的上线方案;

网站50%以上的故障是和开发程序代码有关的,例如代码中的死循环导致server内存资源耗尽引起宕机;

中小公司网站出问题一般是运维人员的问题,导致的原因大多可能与开发人员的代码有关,好的策略是开发项目负责制思想;

建议:

开发人员需在个人电脑搭建LAMP环境用以测试开发好的网站代码,并在办公室或IDC机房的测试环境下通过,最好有专职测试人员;

程序代码上线公布时间,如三天上线一次,如果网站需经常更新可每天17:00上线,具体看网站业务性质而定,原则是影响用户体验降至最低;

代码上线前需备份,网站程序出了问题方便回退,从上线技巧上,上传代码时尽可能先传到服务器网站临时目录,传完整后再mv过去,或通过ln做软链接,如果再严格些,应把应用服务器从集群节点平滑下线,然后更新;

务必由运维人员管理上线,开发人员在意的是代码的功能性,运维在意的是代码的性能和上线后服务器的稳定,如果网站问题归运维管,就要让运维负责上线,这样更规范科学,否则开发随意更新,出问题由运维负责这不妥当;

中型企业上线解决方案:

一般是规范运维人员操作步骤,制定统一的上线操作脚本,备份文件名称、备份文件路径,使操作人性化、统一化、自动化;

web代码上线流程:

大型企业上线解决方案:

统一制度和流程控制较多,较严谨,下图是java代码上线方案,在流量代谷下线进行;

注:

打包由mvn、ants工具打包,格式为war,如idc_dep.war、idc_test.war、idc_product.war;

ITIL、BSW等运维规范;

SVN server上存放的有:程序代码、服务的配置、项目文档、设计文档、运维部署优化文档;

大型企业有配置管理员这一岗位,负责SVN管理、上线管理、申请协调(协调开发人员和运维人员),图中第5步骤由配置管理员负责;

Jenkins可将SVNserver的代码自动的发布到办公开发环境(依据脚本编译JAVA程序、重启tomcat等),常用于测试;

若IDC上测试有问题,说明IDC测试环境与本地的软硬件环境不一致;

从测试到上线至少要在办公开发环境、IDC测试环境通过后才允许最后在正式环境上线;

IDC统一分发管理server上的程序代码和各服务的配置文件是从SVN server上来的,若直接从正式服务器上改配置文件内容,统一分发管理server会自动将自己获取到的配置文件覆盖掉已更新的文件导致更改无效,在此架构下若要更改配置文件要走正式流程(要经过配置管理员等);

IDC统一分发控制管理(secboy,secureCRT,ssh+sudo+rsync,expect,puppet,cfengine,sersync,lsyncd);

越靠近用户上线频率越高,越底层上线频率越低;

注:

web server分A、B两组,将A组停服,从正式的LVS卸下,挂至测试用的LVS上,待测试OK,A组运行换B组上线,无论webserver有多少只能分两组上线,否则代码会有新有旧,用户会明显感知到;

程序代码上线具体方案:

1、本地开发人员从SVNserver中获取代码,当天上线的提交到trunk,否则长期项目要单开分支开发,然后再合并到trunk主线;

2、办公内网开发时,由开发人员或配置管理员通过部署平台Jenkins实现统一部署(即在部署平台上控制开发机器从SVN取代码、编译、打包、发布到开发机,包名idc_dep.war);

3、开发人员通知或和测试人员一直测试程序,没问题后,由配置管理员打上新的tag;

4、配置管理员根据上步的tag,checkout出上线代码,并配置好IDC测试环境的所有配置,执行编译、打包(mvn,ant),php则不需要,然后发布到IDC内的统一分发server,注意不同环境的配置文件是随代码同时发布的;

5、配置管理员或SA上线人员,把分发的程序代码内容推送到相关测试服务器(包名idc_test.war),然后通知开发和测试人员进行测试,若有问题向上回退,继续修改;

6、若IDC测试没问题,继续打好tag,此时配置管理员根据上步的tag,checkout出测试好的代码,并配置好IDC正式环境的所有配置,执行编译、打包(mvn,ant),php则不需要,然后发布到IDC内的统一分发server主机,准备指发布;

7、配置管理员或SA上线人员,把分发的内容推送到相关正式服务器(包名idc_product.war),然后通知开发人员进行测试,若有问题直接发布回滚指令;

注:

IDC正式上线的过程对于JAVA程序,可以是AB组分组上线的思路(即平滑下线一半的服务器),然后发布更新代码测试,重启,测试没问题后,挂上服务器,同时再平滑下线另一半的server,再发布更新代码测试(或直接发布后重启挂上线);

注:

php程序代码上线(测试完毕,发布代码时可以发布到正式线临时目录,再mv或ln发布到正式线目录,不需重启httpd服务,这是sina、ganji的上线方案);

注:

JAVA程序代码上线(较大公司(独立IP有100w以上)需要分组平滑上线,先从LB器上摘掉一半server,发布代码后重启server测试,没问题后挂上,再下另一半,如果前端有DNS智能解析,上线还可以分地区上线若干服务器,逐渐普及到全国的server,这个被称为灰度发布);

代码上线解决方案注意事项:

1、上线的流程里,办公测试环境-->IDC测试环境-->正式生产环境,这三个环境中的所有软件均应版本统一,否则后患无穷,如OS、webserver、jdk、php、tomcat、resin等;

2、办公测试环境由开发小组维护,定时自动更新代码,有问题反馈给某开发人员重新开发;

3、有专门的测试工程师,程序有问题直接返回给开发人员(此时的问题一般为BUG,称BUG库),无问题再进行IDC测试;

4、IDC测试由测试人员和运维人员共同参与,叫IDC test,进行程序的压力测试,有问题直接返回给开发人员,无问题再上线;

5、数台server代码分发上线方案(JAVA程序):假如业务server有六台,将其分为A、B两组,先对A组进行从LB器上平滑下线,B组正常提供服务,避免影响线上业务;下线过程一般在夜晚网络流量少时,通过脚本将A组server从RS池(LVS、nginx、haproxy、F5等均有平滑下线方案)中踢出,避免LB器将请求发给A组server;将代码分发到A组server的站点目录下,对A组server上线并重启服务,由测试人员测试成功后,挂上A组server,同时下线B组server同A组之前操作一样;

6、若是php程序,上线可简单化,直接将线上代码(最好全量)发布到所有上线server的特定目录后,一次性mv或ln到站点目录,测试成功后即可(各种测试脚本测试各个相关业务接口);

7、大多数门户公司的前端页面都已静态化或cache了,因此动态的部分平时访问的量少,网站流量低时更少,再加上平滑上下线,基本上对用户体验无影响,也有出问题这避免不了;

8、SVN上包含代码和配置:程序代码(不含资源,大公司网站资源和程序是分离的);所有服务的配置文件(开发小组测试环境使用的配置文件、办公测试环境使用的配置文件、IDC测试环境使用的配置文件、线上应用使用的配置文件);

注:在上线不同环境时,由配置管理员协调上线;尽可能全量上线的原因:务必要保证SVN的代码是最新的

注:自动化部署及代码发布管理平台(中大型公司都有,自己开发的web页面)

开发及运维人员业务变更管理平台:

优点:变更管理制度流程有利于业务稳定;保留变更业务历史,便于检查发现的问题;故障跟踪平台,有利于跟踪问题的解决进度,而不是半途而废;相关常用软件

JIRA用于缺陷跟踪、客户服务、需求收集、流程审批、任务跟踪、项目跟踪、敏捷管理等荼领域;

Mantis是一款php开源bug跟踪系统,适合中小型项目的管理及跟踪,特性:易于安装,易操作,基于web,支持任何可运行的php平台

软件设计流程(按30天):

需要分析阶段(7天)-->软件设计阶段(逻辑图、建模,7-10天)-->编码阶段(3-7天)-->软件测试(7天)-->发布市场

Linux运维工程师(一线):使用软件的阶段(架构师提供的文档),包括内部开发的软件工具,安装、搭建、简单调优;

Linux架构师(二线):把一堆软件整合在一起,满足某个项目需求;需求分析,项目架构方案设计,写架构文档,推进项目进度、培训,架构问题的顾问;

python运维开发-->C语言运维系统开发(软件开发、工具开发、创新、编写部署使用文档、培训、顾问)

时间: 2024-11-01 07:56:48

III(二十一)SVN的相关文章

我的编程之路(二十一) 规范

不知不觉一周就过去了,这周细想真的没有做成什么,因为几乎都是做了改,改了做··· 1.代码规范 以前自认为自己很注重代码规范,但是没有想到自己项目组的开发会将代码规范审查的那么严谨,这突然让我想到之前说到程序员都喜欢追求完美,都喜欢自己和自己的风格一致,否则就会觉得别扭,不过与此不同,这是团队开发,代码规范是为了统一风格,便于别人的阅读与后人的修改与维护,虽然因为这我前前后后改了三次dao层的代码,一是要用公司封装的借口,二是要把异常处理都放在这一层或者service层,三是要用公司自己写的工具

QT开发(二十一)——QT布局管理器

QT开发(二十一)--QT布局管理器 一.布局管理器简介 QT中使用绝对定位的布局方式无法自适应窗口的变化. QT中提供了对界面组件进行布局管理的类,用于对界面组件进行管理,能够自动排列窗口中的界面组件,窗口大小变化后自动更新界面组件的大小. QLayout是QT中布局管理器的抽象基类,通过对QLayout的继承,实现了功能各异且互补的布局管理器. 布局管理器不是界面组件,而是界面组件的定位策略. 任意容器类型的组件都可以指定布局管理器. 同一个布局管理器管理中的组件拥有相同的父组件,在设置布局

Android学习路线(二十一)运用Fragment构建动态UI——创建一个Fragment

你可以把fragment看成是activity的模块化部分,它拥有自己的生命周期,接受它自己的输入事件,你可以在activity运行时添加或者删除它(有点像是一个"子activity",你可以在不同的activity中重用它).本课将向你展示如何使用Support Libaray继承 Fragment 类来让你的应用能够兼容正在运行Android 1.6的设备. 提示: 如果你决定你的应用需求的最低API级别是11或者更高,那么你不需要使用Support Library,你可以直接使用

Java Web总结二十一Listener监听器

一.事件三要素 1.事件源:操作事件的对象,例如:窗体Frame 2.事件监听器:事件监听器监听事件源,例如WindowListner,它是一个接口 3.事件,例如:单击事件,通过事件,可以取得事件源 二.适配器模式 1.当一个接口有较多的方法时,而实现类只需对其中少数几个实现,此时可以使用适配器模式 2.适配器模式常用于GUI编程 三.八种Web监听器 1.Web中有三个事件源,分别是ServletContext->HttpSession->ServletRequest 2.ServletC

justinmind夜话:数据母板系列视频教程之原型设计二十一条军规

案例描述:使用数据母板实现原型设计二十一条军规 知识点: 数据母板 效果图: 本站在线效果预览:(原型文件) 原型下载地址:数据母板原型设计二十一条军规 .vp  数据母板原型设计二十一条军规.html 在线视频: 实现步骤:

ActionScript3游戏中的图像编程(连载二十一,第1章完)

1.4.3 用灰度/明度指导色彩搭配 试着只通过调整不等于0的通道,让上一排的色彩在灰度上保持一致,把三个颜色分别代入到心理学公式.得 Gray(red) = r * 0.299      Gray(green) = g * 0.587      Gray(blue) = b * 0.114 让它们灰度相等,则 r * 0.299 = g * 0.587 = b * 0.114 可见,b值一定最大,不妨让b取最大值255,求得r=97, g=50.把这两个值分别应用到红和绿两个色块上. 绿色不再

[翻译]NUnit---TestCase Attributes(二十一)

TestCaseAttribute (NUnit 2.5) TestCase特性有两个效果,包括标记一个方法使用参数并且在调用的时候提供内置数据.示例如下,本示例会使用不同数据集执行3次: [TestCase(12,3,4)] [TestCase(12,2,6)] [TestCase(12,4,3)] public void DivideTest(int n, int d, int q) { Assert.AreEqual( q, n / d ); } Note:.net特性的限制了参数类型,N

Welcome to Swift (苹果官方Swift文档初译与注解二十一)---140~147页(第三章--集合类型)

第三章 Collection Types (集合类型) 在Swift中,提供了两种集合类型用来存储一组值:数组和字典.数组有序的存储相同类型的值;字典存储无序的相同类型的值.字典可以通过唯一的标识(就是所说的键)来查询和访问. 在Swift中,数组和字典总是要清晰的标明他们存储数据的类型.这就意味着不可以将错误的类型插入到数组或字典中.同时也意味着你是明确了解你要遍历的数组或字典里面数据的类 型.在Swift中,集合要显式的声明类型来保证在开发中都会明确的知道它能处理的数据类型. 注意点: 在S

[原]openstack-kilo--issue(二十一) instance can&#39;t get ip 虚拟机不能得到ip(2)

===问题点==== 在使用vlan模式部署compute节点的时候出现了下面的错误:在controller节点的dhcp-agent.log中 2017-01-22 20:19:34.178 24140 INFO neutron.agent.dhcp.agent [req-bf703a13-52ba-4fc4-ae52-8af1c0c635fd ] Synchronizing state complete 2017-01-23 14:11:05.401 24140 INFO neutron.o

COJ 0979 WZJ的数据结构(负二十一)

WZJ的数据结构(负二十一) 难度级别:C: 运行时间限制:5000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 请你实现一个数据结构,完成这样的功能: 给你一个N个点的图,初始状态无边. 每次加入一条双向边(u,v,w),若加入后没有构成一棵生成树,输出“Not Yet”,否则输出当前最小生成树的权值. 输入 第一行两个正整数N,M.表示有N个点M个操作.接下来M行每行三个正整数u,v,w. 输出 每次加入一条双向边(u,v,w),若加入后没有构成一棵生成