项目管理是大型程序设计中必不可少的一部分。对于经常修改程序版本的程序员而言,项目管理的价值已远远超出软件开发的领域。在项目开始中,如果当前出现了失误,项目管理可以使用户代码自动恢复到一个已知的,工作正常的版本,从而避免重大的风险和损失。此外,在已经发布的老程序版本中如果发现了bug,用户也可以轻松地检出特定的版本,以确认和修订,并生成该bug的修补程序。如果没有版本控制和项目管理,用户在开发时必须慎之又慎,缓慢推进,这样会严重影响开发效率。
项目管理的工具很多,在Linux下常用的管理工具主要包括以下几种:Redmine,DotProject,Subversion及CVS。下面主要介绍如何使用Subversion来搭建一个小型的项目。
一、 SVN服务器的下载和安装
笔者安装的ubuntu,通过sudoapt-get install subversion进行安装,如果读者是别的类型的Linux的话,可以访问http://subversion.apache.org/packages.html找到相关的安装方法。
无论安装哪个版本的SVN,Subversion都会分成下面几个部分:
svn 命令行客户端
svnversion 报告工作复制状态(当前修订版本的项目)的工具
svnlook 检查版本库的工具
svnadmin 建立,调整和修补版本库的工具
svndumpfilter 过滤Subversion版本库转储文件的工具
mod_dav_svn Apache HTTP服务器的一个插件,可以让版本库在网络上可见
svnserve 一种单独运行的服务器,可以作为守护进程由SSH调用,另一种让版本库在网络上可见的方式。
二、 创建项目库
Subversion需要使用项目仓库来存储用户的数据,首先用户需要给项目仓库创建一个空白目录,然后使用svnadmin命令进行创建项目库,其命令如下:
在/opt/svnparser/目录下创建项目仓库:
mkdir repos
在/opt/svnparser/repos目录下创建一个项目库:
svnadmin create /opt/svnparser/repos
可以查看到生成的文件。其中,conf目录下存放了版本库的配置文件,包括用户访问控制和权限控制等内容,文件本身的注释说明十分详细,读者可以根据注释自行配置;db目录下存放着Subversion所要管理的所有受版本控制的数据,不同的存储方式(Berkeley DB或FSFS)下有着不同的目录结构,不过我们一般不直接修改和查看这个目录下的内容,Subversion的命令可以安全地操作这个目录;另外,hooks目录存放着钩子脚本及其模版(一种版本库事件触发程序),locks目录存放着Subversion版本库锁定数据,format文件记录了版本库的布局版本号。
版本库只是一个虚拟的版本化文件系统,可以存放你想要的任何文件。有的管理员倾向于一个版本库只存放一个项目,有的则喜欢存放多个项目到一个版本库不同的目录里。每种方式,版本库都是以“项目”管理文件和目录。
三、 项目创建
创建好项目库之后,下面就要向项目库中添加项目。创建项目的命令为“svn import”,其命令格式如下:
svn import [PATH] URL [option]
该命令表示提交PATH文件到URL指定的工程中。如果省略PATH,则默认为“.”;如果PATH是目录,则其下的内容也直接加入到URL指定的位置内。
创建希望导入Subversion版本库的项目,首先把这个项目的文件和目录整理到一个叫做tldw_qp的目录里(假定在/home/stevenqiu下)。
在用户的项目中必须要有branches、tags和trunk 3个顶级目录。trunk目录保存所有的数据,而branches和tags都是空的。
把一系列需要的文件和目录放到trunk下。
下面就将tldw_qp下的文件导入项目库中。命令行下输入:
svn import /home/stevenqiu/tldw_qp file:///opt/svnparser/repos/tldw_qp -m "This is the query parser"
在以上命令中,/home/stevenqiu/tldw_qp表示要导入的源文件,repos/tldw_qp是新建的工程项目名称,-m表示添加的消息日志。
四、 项目查看
创建完项目后,可通过如下命令查看项目:
svn list [TARGET] [Option]
在本例中,要查看tldw_qp中的文件和目录,可输入:
svn list file///opt/svnparser/repos/tldw_qp --verbose
此外,也可使用“svn info”来查看当前项目的详细情况,如下:
svn info file///opt/svnparser/repos/tldw_qp
五、 项目签出
如果要对项目内容进行更改首先要做的就是项目签出。项目签出的命令为“svn checkout”,其格式如下:
svn checkout URL[@REV] [PATH]
该命令格式表示从当前的URL项目库中签出项目,并将其签出到PATH指定的目录中。
如果PATH路径参数省略,则使用URL最末尾的目录名作为签出目录名。如果指定REV,那么就确定了从URL首先查找的版本。
svn checkout file:///opt/svnparser/repos/tldw_qp
六、 项目修改
项目签出后,用户就可以在本地进行修改代码。尽管项目已经签出,但是事实上项目库和签出项目所在的目录时刻都在进行通信,主要进行如比较项目的进展情况、修改检查等工作。
“svn status”表示显示签出目录与版本库中目录的状态对比。
svn status main.cpp -v
“svn diff”命令即可显示当前文件与项目库中文件之间的区别。
svn diff main.cpp
七、 项目提交
做完了修改后,就可以把最新的版本储存到项目仓库中,提交最新版本使用的命令为“svn commit”,其格式如下:
svn commit [PATH]
该命令格式表示将PATH路径下签出的项目提交到项目库中。其中PATH表示使用当前目录。在PATH后面使用“-m”表示用来给所做的改动进行注释,方便以后项目的查阅。
svn commit -m "add a README file."
提交之后,用户可以使用SVN日志功能进行检查是否真的提交。使用日志功能的命令为“svn log”,其格式为:
svn log [PATH]
该命令格式表示查看当前PATH路径下版本库的日志信息。
八、 项目更新
如果签出的副本很长时间没有操作,可能会滞后于项目库中的最新的版本,要实现当前副本与项目库的同步,可以使用“svn update”命令。
svn update
九、 对文件的其他操作
1、 文件添加
svn add [PATH]
该命令行实现的功能是将PATH中的文件和目录纳入版本控制,通过调度加入版本库,在下一次提交时将文件和目录加入。
svn add README
注意,此时项目库中并没有真正把该文件加入项目库,而只是记录了要添加到项目库的名字,因此,要实现真正加入到项目库中还需要使用“svn commit”命令把新文件提交才可以。
2、 文件复制
在Windows下,用户可以手动复制文件,在Linux下用户可以使用“cp”命令复制数据,在SVN下提供使用“svn copy”命令将新文件加入版本控制中。
svn copy SRC[@REV] DST
该命令表示将地址SRC的文件复制到DST所在的路径下,SRC和DST既可以是工作副本路径也可是版本库地址,因此对于复制将出现4种情况:
副本到副本 表示普通文件的复制,同Linux下的cp相同
副本到版本库 表示提交工作副本到版本库
版本库到版本库 表示签出版本库中项目到工作副本,调度增加
版本库到副本 表示完全在版本库中进行复制,一般用于分支、标签和项目复制
例如,将本地工作副本文件README提交到版本库并改名为README.txt可以使用命令:
svn copy README README.txt
3、 文件删除
当文件失效或者编写错误时,用户很多时间都会将该文件删除。SVN版本库也不例外,因此,文件删除在Subversion中将会频繁使用。
在Subversion中使用“svn delete”命令进行文件删除。其格式如下:
svn delete [PATH]
PATH是项目删除文件所在的目录。每个PATH指定的项目会被调度到下次提交时从版本库中删除。
如果PATH是未版本控制或者已修改的项目,或者包含这些项目,那么仅当在PATH后给出“—force”参数时这些项目才会被删除。
svn delete README
4、 文件移动
文件移动(重命名)也是SVN经常使用的操作之一。在Subversion中使用“svn move”进行文件的移动。其格式和使用方法基本同”svn copy“类似。
十、svnserve服务启动与配置
svnserve 是一个轻量级的服务, 使用自定义的协议通过TCP/IP与客户端通讯。客户端通过由 svn:// 或者 svn+ssh:// 开始的URL访问svnserve服务器。
启动服务器
1、 端口监控(inetd)模式
如果你打算用端口监控来启动处理客户的访问请求的进程,你可以通过传入参数-i来启动:
svnserve -i
当使用-i参数启动服务的时候,svnserve通过stdin和stdout用自定义协议和客户端通讯。同时服务侦听3690端口。
2、 独立端口监控进程
使用参数-d启动服务作为一个独立的端口监控进程。
svnserve -d
当运行svnserve在独立端口监控模式时,你可以使用--listen-port=和--listen-host=参数来自定义需要的端口和主机名称。当前模式默认的端口是3690。
当然,也有第三种方法启动svnserve,也就是使用“隧道模式”,使用-t参数启动服务。
这个模式要求远程服务程序,如RSH或SSH,已经成功验证用户,并且使用已经校验的用户启动一个属于该用户的svnserve进程。
当使用该模式提供服务时,要确认启动的用户帐户具备对 Repository的读/写权限。
3、 内置的验证和授权
当客户端连接到一个svnserve进程时,下面的流程就会触发:
1)、客户选择一个指定的Repository;
2)、服务处理Repository的配置文件 conf/svnserve.conf文件,并且开始执行在其中定义的所有验证和授权策略;
3)、依赖与情形和授权策略:
a)客户端也许允许匿名访问而不需要验证,或者
b)客户但也许需要在任何时候被要求验证,或者
c)假如处于"隧道模式"中,客户端将声明自己已经可以被外部验证。
很显然,如上所说,用户文件是一个名为svnserve.conf的,放在conf目录下的文件。
现在我们来看看如何配置这个文件:
这个配置文件放置在Repository的目录中的conf目录下,它有两个节点:
[general]
[users]
其中,[general]的配置信息有:
anon-access = read
auth-access = write
其中表示对于验证有效的以及没通过验证的用户可以做什么事情。分别有read, write和none
[users]的标签的配置内容有:
USERNAME = PASSWORD
password-db = passwd
realm = My First Repository
其中表示,用户名对应的密码是什么,或者指定一个存储用户名和密码的文件的相对或绝对路径以及指定了Repository的验证领域。
如果两个Repository有相同的验证领域,那么它们应该有相同的密码数据库,反之亦然。默认的领域就是指向当前的Repository的路径,与服务器的 Repository的根目录相关。
4、 svnser配置实例
svnserve是SVN自带的一个轻型服务器,客户端通过使用以svn://或svn+ssh://为前缀的URL来访问svnserve服务器,实现远程访问SVN版本库。
svnserve可以通过配置文件来设置用户和口令,以及按路径控制版本库访问权限。本文详细分析了svnserve配置文件格式,并说明如何使用配置文件控制版本库访问权限。
1) svnserve配置文件概述
svnserve配置文件通常由以下3个文本文件组成:
svn服务配置文件,该文件版本库目录的conf目录下,文件名为svnserve.conf。
用户名口令文件,该文件名在文件svnserve.conf中指定,缺省为同目录下的passwd。
权限配置文件,该文件名也在文件svnserve.conf中指定,缺省为同目录下的authz。
2) svn服务配置文件
svn服务配置文件为版本库目录中的文件conf/svnserve.conf。该文件仅由一个[general]配置段组成。
[general]配置段中配置行格式如下:
<配置项> = <值>
配置项分为以下5项:
anon-access 控制非鉴权用户访问版本库的权限。取值范围为"write"、"read"和"none"。
即"write"为可读可写,"read"为只读,"none"表示无访问权限。
缺省值:read
auth-access 控制鉴权用户访问版本库的权限。取值范围为"write"、"read"和"none"。
即"write"为可读可写,"read"为只读,"none"表示无访问权限。
缺省值:write
password-db 指定用户名口令文件名。除非指定绝对路径,否则文件位置为相对conf
目录的相对路径。
缺省值:passwd
authz-db 指定权限配置文件名,通过该文件可以实现以路径为基础的访问控制。
除非指定绝对路径,否则文件位置为相对conf目录的相对路径。
缺省值:authz
realm 指定版本库的认证域,即在登录时提示的认证域名称。若两个版本库的
认证域相同,建议使用相同的用户名口令数据文件。
缺省值:一个UUID(Universal Unique IDentifier,全局唯一标示)。
【说明】版本库认证域
在使用svn客户端访问svnserve服务器时,若需要用户登录,则提示信息如下:
[root@test root]# svn list svn://192.168.3.45/test
Authentication realm:0d545a49-4038-0410-99b4-c66dc73f754e
Password for 'root':
在上述第2行"Authentication realm: "之后显示的字符串为认证域名称。如果在配置文件中为设定认证域,就会提示一个UUID,如上述所示。
如果在配置文件中指定了如下配置项:
realm = test
将在svn客户端提示如下:
[root@test root]# svn list svn://192.168.3.45/test
Authentication realm: test
Password for 'root':
例1:svn服务配置文件conf/svnserve.conf的内容如下:
[general]
anon-access = none
auth-access = write
password-db = ../../conf/passwd
authz-db = ../../conf/authz
realm = test
上述配置文件设定非鉴权用户无权限访问该版本库;鉴权用户可对版本库进行读写;用户名口令文件为相对版本库conf目录的文件"../../conf /passwd";
权限配置文件为相对版本库conf目录的文件"../../conf/authz";版本库的认证域为"test"。
3) 用户名口令文件
用户名口令文件由svnserve.conf的配置项password-db指定,缺省为conf目录中的passwd。该文件仅由一个[users]配置段组成。
[users]配置段的配置行格式如下:
<用户名> = <口令>
注意:配置行中的口令为未经过任何处理的明文。
例2:用户名口令文件conf/passwd的内容如下:
[users]
steven = steven
thinker = 123456
该文件中配置了两个用户,用户名分别为"steven"和"thinker"。其中"steven"用户的口令为"steven";"thinker"用户的口令为"123456"。
4) 权限配置文件
权限配置文件由svnserve.conf的配置项authz-db指定,缺省为conf目录中的authz。该配置文件由一个[groups]配置段和若干个版本库路径权限段组成。
[groups]配置段中配置行格式如下:
<用户组> = <用户列表>
用户列表由若干个用户组或用户名构成,用户组或用户名之间用逗号","分隔,引用用户组时要使用前缀"@"(如:引用用户组"all"要使用字符串"@all")。
版本库路径权限段的段名格式如下:
[<版本库名>:<路径>]
如版本库abc路径/tmp的版本库路径权限段的段名为"[abc:/tmp]"。
可省略段名中的版本库名。若省略版本库名,则该版本库路径权限段对所有版本库中相同路径的访问控制都有效。
如:段名为"[/tmp]"的版本库路径权限段设置了所有引用该权限配置文件的版本库中目录"/tmp"的访问权限。
版本库路径权限段中配置行格式有如下三种:
<用户名> = <权限>
<用户组> = <权限>
* = <权限>
其中,"*"表示任何用户;权限的取值范围为''、'r'和'rw',''表示对该版本库路径无任何权限,'r'表示具有只读权限,'rw'表示有读写权限。
注意:每行配置只能配置单个用户或用户组。
例3:权限配置文件conf/authz的内容如下:
[groups]
g_admin = steven,thinker
[admintools:/]
@g_admin = rw
* =
[test:/home/thinker]
thinker = rw
* = r
在 上述配置文件中,定义了一个用户组"g_admin",该用户组包含用户"steven"和"thinker"。然后定义了2个版本库路径权限段。
其中,版 本库"admintools"只有用户组"g_admin"可读写,其他用户无任何权限;版本库"test"中路径"/home/thinker"只有用 户"thinker"有读写权限,其他用户只有可读权限。
开启服务:
svnserve -d --listen-host [hostname] -r /opt/svnparser/repos/
下载源码:
svn checkout svn://[hostname]/tldw_qp
注意:
为什么要使用trunk、tags和branches 3个文件夹而不是别的?
对于版本库中的主程序,在发布时都会使用“标签”记录这个里程碑似的“记号”,然而,如果随着时间的推移,这个程序可能不能满足当前的需要,必须要对其更新,但是如果任何一位开发人员都对这个重要的程序进行任意更改,那么就可能出现程序被破坏的可能,因此,SVN设计能区别权限的区域,其中“tags”区域就是专门用来存放当前的已经发布的重要程序,它一般是只读的,并且只有SVN配置管理员才有权进行操作,而对于普通的开发人员只能进行浏览。
同样,“branches”被用来作为主干程序的分支,也是一些阶段性的release版本,这些版本可以继续进行开发和维护,也可以被别的项目调用。例如,为不同的用户定制的版本,也可以放在分布中进行开发。
当然,最后剩下的“trunk”是主分支,是日常进行开发的地方。