SVN版本控制
需求:多人协同开发:多人使用,多人编辑
不能存本机,不能使用共享(NFS,samba,ftp,http),版本控制软件能实现此需求。
Subversion(简称SVN)是一个自由开源的版本控制系统。在Subversion管理下,文件和目录可以超越时空。Subversion将文件存放在中心版本库里,这个版本库很像一个普通的文件服务器,不同的是,它可以记录每一次文件和目录的修改情况,这样就可以借此将数据恢复到早期版本,并可以查看数据修改的历史(更改的细节)。正因为如此,许多人将版本控制系统当作一种神奇的“时间机器”。
应用场景:Subversion是一个梦幻般的锤子,但要小心不要把任何问题当作钉子
Ø 如果你希望文件和目录旧版本,有可能要恢复或需要查看日志获得其修改的历史
Ø 如果你需要和别人协作文档并跟踪所做的修改
简介
Subversion是近年来崛起的版本管理软件系统,是CVS的接班人。目前,绝大多数开源软件都使用SVN作为代码版本管理软件。相对于的RCS、CVS,采用了分支管理系统,它的设计目标就是取代CVS。互联网上免费的版本控制服务多基于Subversion。
Subversion的版本库可以通过网络访问,从而使用户可以在不同的电脑上进行操作。从某种程度上来说,允许用户在各自的空间里修改和管理同一组数据可以促进团队协作。因为修改不再是单线进行(单线进行也就是必须一个一个进行),开发进度会进展迅速。此外,由于所有的工作都已版本化,也就不必担心由于错误的更改而影响软件质量—如果出现不正确的更改,只要撤销那一次更改操作即可。某些版本控制系统本身也是软件配置管理系统(SCM),这种系统经过精巧的设计,专门用来管理源代码树,并且具备许多与软件开发有关的特性——比如对编程语言的支持或者提供程序构建工具。不过Subversion并不是这样的系统,它是一个通用系统,可以管理任何类型的文件集。
Git是未来发展最有前景的版本控制系统。
历史
早在2000年,CollabNet就开始寻找CVS替代产品的开发人员。CollabNet提供了一个名为CollabNet企业版(CEE)的协作软件套件。这个软件套件的一个组成部分就是版本控制系统。尽管CEE在最初采用了CVS作为其版本控制系统,但是CVS的局限性从一开始就很明显,CollabNet知道迟早要找到一个更好的替代品。遗憾的是,CVS已经成为开源世界事实上的标准,很大程度上是因为没有更好的替代品,至少是没有可以自由使用的替代品,所以CollabNet决定从头编写一个新的版本控制系统,这个系统保留CVS的基本思想,但是要修正其中错误和不合理的特性。
2000年2月,他们联系到OpenSource Development with CVS(Coriolis,1999)的作者Karl Fogel,并且询问他是否希望为这个新项目工作。巧合的是,当时Karl正在与朋友Jim Blandy讨论设计一个新的版本控制系统,1995年时,他们两人曾经开办了一个提供CVS支持的公司CyclicSoftware,尽管他们最终卖掉了公司,但还是天天使用CVS进行日常工作。使用CVS时的挫折促使Jim认真的思考如何管理版本化的数据,并且他当时不仅使用了“Subversion”这个名字,并且已经完成了Subversion版本库的最初设计,所以当CollabNet提出邀请的时候,Karl马上同意为这个项目工作,同时Jim也找到了他的雇主(RedHat软件公司)允许他到这个项目工作,并且没有限定最终的期限。CollabNet雇佣了Karl和BenCollinsSussman,详细设计工作从三月开始,在Behlendorf、CollabNet、JasonRobbins和GregStein(当时是一个独立开发者,活跃在WebDAV/DeltaV系统规范制订工作中)恰到好处的激励下,Subversion很快吸引了许多活跃的开发者,结果是许多对CVS有过失望经历的人很乐于为这个项目做些事情。
最初的设计小组设定了简单的开发目标。他们不想在版本控制方法学中开垦处女地,他们只是希望修正CVS。他们决定Subversion应符合CVS的特性,并保留相同的开发模型,但不再重复CVS的一些显著缺陷。尽管Subversion并不需要成为CVS的完全替代品,但它应该与CVS保持足够的相似性,以使CVS用户可以轻松的转移到Subversion上。
经过14个月的编码,2001年8月31日,Subversion能够“自己管理自己”了,开发者停止使用CVS保存Subversion的代码,而使用Subversion本身。
虽然CollabNet启动了这个项目,并且一直提供了大量的工作支持(它为一些全职的Subversion开发者提供薪水),但Subversion像其它许多开源项目一样,被松散的、透明的规则管理着,这样的规则激励着知识界的精英们。CollabNet的版权许可完全符合Debian的自由软件方针。也就是说,任何人都可以根据自己的意愿自由的下载、修改和重新发布Subversion,不需要CollabNet或其他人的授权。
Subversion架构:客户端、通信方式、仓库存储
1)客户端:命令行、图形
2)通信方式:本地访问、SVN服务器、Web服务
3)仓库存储:文件系统、数据库
基本概念
版本库:典型的S/B系统,是版本控制的核心,任意数量客户端可以通过写数据库分享代码
Subversion特点:记录每一次改变
版本模型:版本控制系统的核心任务是协作编辑和数据共享
文件共享的问题:怎样让系统允许用户共享信息且防止版本库数据被别人意外覆盖
锁定-修改-解锁的问题
锁定可能导致管理问题:A锁定文件后忘记解锁等问题
锁定导致不必要的串行开发:A想修改一个文件的开始,B想修改一个文件的结尾
如果能进行正确的合并,则可以更轻松的工作,没必要轮流工作
解决方法:Subversion控制系统使用拷贝-修改-合并模型。即
Ø 每个客户连接版本库,并建立个人工作副本
Ø 用户并行工作,修改自己的副本
Ø 最终合并版本!
Ø 个别突出问题,需要人为手动解决
流程:Harry拷贝副本,Sally拷贝副本
Hary修改A1,Sally修改A2
Harry上传A1后,Sally上传A2,会提示Sally的文件已过期
Sally更新文件(合并)后上传新的A3
SVN基础
安装Subversion服务器
步骤一:创建版本库
1)YUM安装subversion软件
[root@Web1 ~]# yum -y install subversion
[root@Web1 ~]# rpm -q subversion
2)创建目录并创建版本库
利用svnadmin命令可创建服务器版本库
subversion版本库管理工具,帮助:svnadmin help
用法:svnadmin 命令 /版本库路径 【选项】
命令:create 创建一个新的版本库
[root@Web1 ~]# mkdir /var/svn/
[root@Web1 ~]# svnadmin create /var/svn/project //project为仓库名
[root@Web1 ~]# ls /var/svn/project/
conf/ db/ format hooks/ locks/ README.txt
步骤二:导入初始化数据
1)本地导入初始化数据
使用svn命令将项目代码导入版本库中
import指令执行导入操作
-m选项设置说明性的字符串
# cd 目录
# svn import . file://本地仓库路径 -m “说明性字符串” // . 代表当前目录 [root@Web1 ~]# du -sh /var/svn/project/ //未导入时目录大小
[root@Web1 ~]# cd /usr/lib/systemd/system/ //为服务存放路径
[root@Web1 system]# svn import . file:///var/svn/project/ -m "Init Data"
2)列出仓库清单
svn list file://本地仓库路径
[root@Web1 ~]# svn list file:///var/svn/project/
[root@Web1 ~]# du -sh /var/svn/project/ //导入数据后目录大小
步骤三:配置服务。修改配置文件,创建账户与密码(能远程访问)
**所有配置文件,必须顶头写,不能有空格
认证与授权:使用SVN内置的认证机制可以有效地增强客户端访问版本库的安全性
当客户端访问版本库服务器时,服务器会根据版本库目录下conf/svnserve.conf文件中定义的认证与授权策略实现权限的控制
使用SVN内置的认证机制可以有效地增强客户端访问版本库的安全性
[root@Web1 ~]# vim /var/svn/project/conf/svnserve.conf //去掉注释
anon-access = none (19行) //设置拒绝匿名帐户访问,此处可设置为none、read、write
auth-access = write (20行) //经过认证的帐户权限为可写权限
password-db = passwd (27行) //帐户名称与密码的存放文件名,该文件在conf目录下
authz-db = authz (34行) //基于路径的ACL文件名(可以对文件或目录设置权限)
[root@Web1 ~]# vim /var/svn/project/conf/passwd //设置帐户信息
[users]
harry = pass1 //用户名harry和密码pass1
tom= pass2 //用户名tom和密码pass2
[root@Web1 ~]# cat /var/svn/project/conf/authz //设置访问控制权限
[groups]
harry_and_tom = harry,tom //定义组账户,组成员为harry和tom
[/] //定义ACL访问控制权限,也可设置其他路径
harry = rw //用户对项目根路径可读、可写
tom = rw
@admins = rw //admins组中的用户可读、可写
* = r //其他人只读
**//权限列别:只读“r”,读写“rw”,无权限“”
**//格式:[路径] 用户名=权限
步骤四:启动服务
<-
svnserve服务
svnserve命令即可启动SVN服务进程 (推荐使用)
-d //以守护进程方式运行svnserve,建议加&挂入后台
--listen-port=port //监听的端口,默认端口号为3690
-r 仓库路径 //设置一个虚拟路径,默认客户端要指定绝对路径访问库
svnserve运行后,会将所有的版本库发布至网络
Ø 客户端需要指定绝对路径访问版本库
Ø 如,svn://centos.example.com/var/svn/project
Ø 服务器端如果需要在authz文件中为目录设置权限,路径应该为[projet:/]或[project2:/test]
Ø [project:/]表示project版本库的根
Ø [project2:/test]表示project2下的test目录
但有时我们仅希望发布其中一个版本库时
Ø 就需要限制仅发布一个版本至网络
Ø 客户端也可以使用相对路径访问版本库
Ø 如,svn://centos.example.com/project
Ø 服务器端如果需要在authz文件中为目录设置权限,路径应该为[/]或[/test]
Ø 根(/)表示project版本库
Ø /test表示project下的test目录
两种方法启动SVN服务进程
1)systemctl restart svnserve,把所有仓库都共享
客户端访问:svn://IP地址:/var/svn/{project1|shell|test} //共享了多个仓库,要加具体仓库
2)svnserve -d -r /var/svn/project1 (只共享一个仓库)
客户端访问:svn://IP地址/[project1] //共享了一个仓库,无需加具体仓库
->
[root@Web1 ~]# systemctl start svnserve
或[root@Web1 ~]# svnserve -d -r /var/svn/project/
[root@Web1 ~]# netstat -nutlp |grep svnserve //端口号tcp 3690
客户端操作(下载和上传都需在指定的目录内完成)
访问方式:本地磁盘、SVN、Web
Windows客户端软件:TortoiseSVN (不要用汉化版,尽量使用官方)
svn命令[选项]:
--password 密码
--username 用户名
--revision (-r) 指定要检查的特定版本
使用svn命令测试svnserver服务时可以使用的命令列表如表所示。
checkout命令(初始化检出)
checkout URL[@REV] [PATH]
从服务器版本库中复制一份副本至本地
URL定位版本库
通过REV可以下载特定版本的数据
PATH为本地工作副本路径
[root@Web2 ~]# cd /var/tmp
[root@Web2 tmp]# svn co --username harry --password 123456 svn://192.168.2.100/ harry
//从192.168.2.100服务器下载代码,放到harry目录,用户名harry,密码123456
//co,为checkout的简写
……
Store password unencrypted (yes/no)? yes //提示是否保存密码
[root@Web2 ~]# cd /var/tmp/harry
[root@Web2 harry]# ls
[root@Web2 harry]# vim test.sh
//新建脚本文件,内容无所谓。创建后不能直接提交,要svn add后再提交
[root@Web2 harry]# chmod +x test.sh
[root@Web2 harry]# svn add test.sh //将文件或目录加入版本控制
A test.sh
add命令(本地版本库添加新文件)
在本地版本库副本,添加新的文件 # echo “test” >>test.sh
注意,add不会自动提交版本库服务器
需要使用commit命令提交服务器 # svn ci -m “add test file”
[root@Web2 harry]# svn mkdir subdir //创建本地版本库子目录
A subdir
[root@Web2 harry]# svn status //检查状态,结果为两个添加append
A test.sh
A subdir
[root@Web2 harry]# svn del user.slice //删除版本库中的文件,与svn rm user.slice等同
D user.slice
del命令(本地版本库删除文件)
删除本地版本库副本文件
注意,del不会自动提交版本库服务器
需要使用commit命令提交服务器
[root@Web2 harry]# svn move test.sh test //脚本重命名
A test
D test.sh
commit命令(提交修改)
在本地修改本地副本中的代码后,commit可以提交该修改,原子事务提交
update命令:将服务器上其他人的修改的代码更新到本地
[root@Web2 harry]# svn ci -m "add a file and subdir,remove user.slice file"
//ci是commit的缩写,将本地修改提交到服务器版本库,引号内为描述性字符
Deleting cups
Adding subdir
Adding test
Transmitting file data .
Committed revision 2.
[root@Web2 harry]# sed -i '1a##test###' sshd.service //修改本地副本中的代码文件
[root@Web2 harry]# sed -i '2a###test###' sshd.service
diff命令(数据对比):对比本地副本与服务器数据
# echo “add test file” > sshd.service
[root@Web2 harry]# svn diff sshd.service //查看单个文件本地副本与版本库的差异
[root@Web2 harry]# svn diff //查看所有本地副本与版本库的差异
//也可用#svn cat svn://192.168.2.100/文件名 与本地# cat 文件名,自己对比
查看版本库信息:查看版本仓库信息:info命令
查看版本修改历史:log命令
[root@Web2 harry]# svn log svn://192.168.2.100/var/svn/project //查看修改历史
[root@Web2 harry]# svn info svn://192.168.2.100/var/svn/project
数据更新:
[root@Web2 harry]# svn update //更新本地副本文件,从版本库下载更新数据
版本回滚:
1.revert命令——本地副本修改后,但未commit提交修改时回滚数据
# sed -i ‘1d’ 文件名
# head 文件名
# svn revert 文件名
# head 文件名
2.merge命令——本地副本修改commit提交后,使用该命令回滚
# echo “xx” >> user.slice
# svn ci -m “xx”
# svn update
# svn merge -r6:5 user.slice //将文件user.slice文件从6版本还原至5版本
3.还原整个版本至历史版本
[root@Web2 harry]# cd /var/tmp
[root@Web2 tmp]#svn –r2 co svn://192.168.2.100/var/svn/project code
//下载历史版本2
第一步:从服务器下代码svn co --username 用户名 --password 密码 svn://服务器IP/ 目录
首先装subversion包 yum -y install subversion
例子:svn co --username tom --password 123456 svn://192.168.2.100/code(会自动创建)
第二步:在本地改代码后,commit提交修改,update将服务器上其他人改的代码更新到本地
例子:svn ci -m “说明性字符串”--------------------->svn update
查看版本库信息svn info svn://服务器IP/版本库 例子:svn info svn://192.168.2.100/
查看版本修改历史svn log svn://服务器IP/版本库 例子:svn log svn://192.168.2.100/
第三步:add添加新文件并ci提交给服务器(add不会自动提交版本库服务器)
例子:echo “新建版本4” > banben.txt
svn add banben.txt
svn ci -m “four”
第四步:del/rm删除\、mkdir创建、mv移动、cp复制版本库文件并ci提交给服务器
del/rm删除\、mkdir创建、mv移动、cp复制不会自动提交版本库服务器
例子:del/rm/mkdir/mv/cp banben.txt [....]
svn ci -m “five”
第五步:diff命令数据对比本地副本与服务器数据svn diff [文件]
例子:svn diff //对比所有文件
svn diff banben.txt //对比单个文件
cat命令查看版本库数据的内容,本地副本可以直接cat查看
例子:svn cat svn://192.168.2.100/banben.txt svn cat banben.txt
第六步:版本回滚,数据恢复
1)本地副本修改后,但未commit提交修改时回滚数据svn revert 文件
例子:echo “aa” > banben.txt------->svn revert banben.txt
2)本地副本修改后并提交,使用svn merge -r 现版本:现版本之前版本 文件名
适用于少文件:echo “xixixi” > system.slice--------->svn merge -r 7:2 system.slice
适用于多文件:1)cd 新目录 2) svn -r 版本号 co svn://服务器IP/ 目录(会自动创建)
3)本地rm删除数据,svn update 恢复
使用Subversion协同工作
步骤一:多人协同工作
1)远程连接两个终端,每个人下载代码本地副本,注意Web1和Web2代表了两个不同的主机,看清楚操作是在哪一台计算机上执行!
[root@Web1 ~]# svn --username harry --password pass co svn://192.168.2.100/ harry
[root@Web1 ~]# ls harry
[root@Web2 ~]# svn --username tom --password pass co svn://127.0.0.1/ tom
[root@Web2 ~]# ls tom
2) harry和tom修改不同的文件:修改----->上传----->更新
[root@Web1 ~]# cd /var/tmp/harry
[root@Web1 harry]# sed -i "3a###harry\'s modify#####" vmtoolsd.service
[root@Web1 harry]# svn commit -m "vmtoolsd has modified"
[root@Web2 ~]# cd /var/tmp/tom
[root@Web2 tom]# sed -i "3a###tom\'s modify#####" sshd.servie
[root@Web2 tom]# svn commit -m "sshd has modified"
[root@Web1 harry]# svn update
[root@Web2 tom]# svn update
3)harry和tom修改相同文件的不同行
//用户harry先修改上传--->用户tom修改更新上传--->用户harry更新
[root@Web1 ~]# cd /var/tmp/harry
[root@Web1 harry]# sed -i "3a###harry\'s modify#####" user.slice
[root@Web1 harry]# svn commit -m "user.slice has modified"
[root@Web2 ~]# cd /var/tmp/tom
[root@Web2 tom]# sed -i "6a###tom\'s modify#####" user.slice
[root@Web2 tom]# svn commit -m "user.slice has modified" //提示失败
Sending svnserve
Transmitting file data .svn: Commit failed (details follow):
svn: File '/user.slice' is out of date
[root@Web2 tom]# svn update //提示失败后,先更新再提交即可,会自动合并
[root@Web2 tom]# svn commit -m "user.slice has modified"
Sending user.slice
Transmitting file data .
4) harry和tom修改相同文件的相同行
//用户harry先修改上传----->用户tom修改更新产生冲突后选择p将mine的覆盖原始版本,删除其他版本------->用户tom上传----->用户harry更新
[root@Web1 ~]# cd /var/tmp/harry
[root@Web1 harry]# sed -i "8c###harry\'s modify#####" zram.service
[root@Web1 harry]# svn commit -m "zram.service has modified"
[root@Web2 ~]# cd /var/tmp/tom
[root@Web2 tom]# sed -i "8c###tom\'s modify#####" zram.service
[root@Web2 tom]# svn commit -m "zram.service has modified" //出现冲突
svn commit -m "zram.service has modified"
Sending zram.service
Transmitting file data .svn: Commit failed (details follow):
svn: File '/zram.service' is out of date
[root@Web2 tom]# svn update //出现冲突,需要人为处理,如线下处理
Conflict discovered in 'zram.service'.
Select: (p) postpone, (df) diff-full, (e) edit,
(mc) mine-conflict, (tc) theirs-conflict,
(s) show all options:
**//p 标记冲突,稍后解决 (一般使用此选项)
**//df 对比不同
**//e 直接修改文件,修改后选择r
**//mc 冲突以本地为准
**//tc 冲突以服务器为准
**//s 显示所有选项
[root@Web2 tom]# ls //选择postpone标记后,本地副本会多几个文件
zram.service //本地副本文件
zram.service.mine //我的修改副本
zram.service.r10 //第10个版本
zram.service.r9 //第9个版本
保留需要的文件覆盖掉halt后,rm删除其他即可
[root@Web2 ~]# cd /var/tmp/tom
[root@Web2 tom]# mv zram.service.mine zram.service;chmod +x zram.service
[root@Web2 tom]# rm zram.service.*
[root@Web2 tom]# svn commit -m "zram.service has modified" //解决冲突
服务器的备份与还原
1.使用dump指令备份版本库svnadmin dump 仓库路径 > 名字.bak
[root@Web1 ~]# svnadmin dump /var/svn/project > project.bak
2.使用load指令还原版本库svnadmin load 仓库路径 < 名字.bak
找一台全新的服务器还原
创建一个仓库: [root@Web3 ~]# svnadmin create /var/svn/project2
[root@Web3 ~]# svnadmin load /var/svn/project2 < pro.bak
cd nginx-…… [C源码]
./configure
make [C源码 ---> 二进制]
make install [二进制拷贝到系统/usr]