在开发中最常使用的版本控制工具大致分为两种:git与svn(Subversion)
对比使用来讲svn更利于理解与使用,且与模块式开发思维相符合
但git对于多人协作开发来讲,其模式与设计能更好的利于开发过程中的种种问题
所以,对此,总结分析svn与git的区别:
这是Git和SVN最大的区别。若能掌握这个概念,两者区别基本搞懂大半。因为Git是分布式的,所以Git支持离线工作,在本地可以进行很多操作,包括接下来将要重磅推出的分支功能。而SVN必须联网才能正常工作。
集中式版本管理控制系统
集中式的版本控制系统都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。
Subversion的特点概括起来主要由以下几条:
好处:每个人都可以一定程度上看到项目中的其他人正在做些什么。而管理员也可以轻松掌控每个开发者的权限。
缺点:中央服务器的单点故障。
若是宕机一小时,那么在这一小时内,谁都无法提交更新、还原、对比等,也就无法协同工作。如果中央服务器的磁盘发生故障,并且没做过备份或者备份得不够及时的话,还会有丢失数据的风险。最坏的情况是彻底丢失整个项目的所有历史更改记录,被客户端提取出来的某些快照数据除外,但这样的话依然是个问题,你不能保证所有的数据都已经有人提取出来。
Subversion原理上只关心文件内容的具体差异。每次记录有哪些文件作了更新,以及都更新了哪些行的什么内容
分布式的版本控制系统
分布式的版本控制系统都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们在自己本地也会创建一个库,用于保存自己的修改与提交,之后再将自己库提交至服务器库进行更新.
Git记录版本历史只关心文件数据的整体是否发生变化。Git不保存文件内容前后变化的差异数据。
实际上,Git更像是把变化的文件作快照后,记录在一个微型的文件系统中。每次提交更新时,它会纵览一遍所有文件的指纹信息并对文件作一快照,然后保存一个指向这次快照的索引。为提高性能,若文件没有变化,Git不会再次保存,而只对上次保存的快照作一连接。
在分布式版本控制系统中,客户端并不只提取最新版本的文件快照,而是把原始的代码仓库完整地镜像下来。这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。这类系统都可以指定和若干不同的远端代码仓库进行交互。籍此,你就可以在同一个项目中,分别和不同工作小组的人相互协作。你可以根据需要设定不同的协作流程。另外,因为Git在本地磁盘上就保存着所有有关当前项目的历史更新,并且Git中的绝大多数操作都只需要访问本地文件和资源,不用连网,所以处理起来速度飞快。用SVN的话,没有网络或者断开VPN你就无法做任何事情。但用Git的话,就算你在飞机或者火车上,都可以非常愉快地频繁提交更新,等到了有网络的时候再上传到远程的镜像仓库。换作其他版本控制系统,这么做几乎不可能,抑或是非常麻烦。
Git具有以下特点:
所有同时掌握Git和SVN的开发者都必须承认,Git的命令实在太多了,日常工作需要掌握add,commit,status,fetch,push,rebase等,若要熟练掌握,还必须掌握rebase和merge的区别,fetch和pull的区别等,除此之外,还有cherry-pick,submodule,stash等功能,仅是这些名词听着都很绕。
在易用性这方面,SVN会好得多,简单易上手,对新手很友好。但是从另外一方面看,Git命令多意味着功能多,若我们能掌握大部分Git的功能,体会到其中的奥妙,会发现再也回不去SVN的时代了。
在版本管理里,分支是很常使用的功能。在发布版本前,需要发布分支,进行大需求开发,需要feature分支,大团队还会有开发分支,稳定分支等。在大团队开发过程中,常常存在创建分支,切换分支的需求。
Git分支是指针指向某次提交,而SVN分支是拷贝的目录。这个特性使Git的分支切换非常迅速,且创建成本非常低。
而且Git有本地分支,SVN无本地分支。在实际开发过程中,经常会遇到有些代码没写完,但是需紧急处理其他问题,若我们使用Git,便可以创建本地分支存储没写完的代码,待问题处理完后,再回到本地分支继续完成代码。
Git最核心的一个概念就是工作流。
从SVN切换到Git,最难理解并且最不能理解的是暂存区和本地仓库。熟练使用Git后,会发现这简直是神设计,由于这两者的存在,使许多工作变得易管理。
通常提交代码分为几步:
1.gitadd从工作区提交到暂存区
2.gitcommit从暂存区提交到本地仓库
3.gitpush或gitsvndcommit从本地仓库提交到远程仓库
svn存储版本数据有2种方式:BDB(一种事务安全型表类型)和FSFS(一种不需要数据库的存储系统)。因为BDB方式在服务器中断时,有可能锁住数据,所以还是FSFS方式更安全一点。
BDB
伯克利DB(BerkeleyDB),版本库可以使用一种经过充分测试的后台数据库实现,不能在通过网络共享的文件系统上使用,伯克利DB是Subversion1.2版本以前的缺省版本库格式。
FSFS
一个专用于Subversion版本库的文件系统后端,可以使用网络文件系统(例如NFS或SMBFS)。是1.2版本及其后的缺省版本库格式。
CSV是个基于RCS文件的版本控制系统。每个CSV文件都不过是普通的文件,加上一些额外的信息。这些文件会简单的重复本地文件的树结构。因此,不必担心有什么数据损失,如果必要的话可以手工修改RCS文件。
SVN是基于关系数据库的(BerkleyDB)或一系列二进制文件的(FS_FS)。一方面这解决了许多问题(例如,并行读写共享文件)以及添加了许多新功能(例如运行时的事务特性)然而另一方面,数据存储由此变得不透明,不能像ftp,samba,nfs等看到实体文件了。
小总结:因为BDB方式在服务器中断时,有可能锁住数据(搞ldap时就深受其害,没法根治),所以还是FSFS方式更安全一点,我也选择这种方式。
日常开发过程其实就是这样的(假设你已经Checkout并且已经工作了几天):Update(获得最新的代码)-->作出自己的修改并调试成功-->Commit(大家就可以看到你的修改了)。
如果两个程序员同时修改了同一个文件呢,SVN可以合并这两个程序员的改动,实际上SVN管理源代码是以行为单位的,就是说两个程序员只要不是修改了同一行程序,SVN都会自动合并两种修改。如果是同一行,SVN会提示文件Conflict,冲突,需要手动确认。
(1)目录版本控制
(2)真实的版本历史
自从CVS限制了文件的版本记录,CVS并不支持那些可能发生在文件上,但会影响所在目录内容的操作,如同复制和重命名。除此之外,在CVS里你不能用拥有同样名字但是没有继承老版本历史或者根本没有关系的文件替换一个已经纳入系统的文件。在Subversion中,你可以增加(add)、删除(delete)、复制(copy)和重命名(rename),无论是文件还是目录。所有的新加的文件都从一个新的、干净的版本开始。
(3)自动提交
一个提交动作,不是全部更新到了档案库中,就是不完全更新。这允许开发人员以逻辑区间建立并提交变动,以防止当部分提交成功时出现的问题。
(4)纳入版本控管的元数据
(5)选择不同的网络层
(6)一致的数据处理方式
Subversion使用二进制差异算法来异表示文件的差异,它对文字(人类可理解的)与二进制文件(人类无法理解的)两类的文件都一视同仁。这两类的文件都同样地以压缩形式储存在档案库中,而且文件差异是以两个方向在网络上传输的。
(7)有效的分支(branch)与标签(tag)
(8)Hackability
Subversion没有任何的历史包袱;它主要是一群共用的C程序库,具有定义完善的API。这使得Subversion便于维护,并且可被其它应用程序与程序语言使用。
1、原子提交:一次提交不管是单个还是多个文件,都是作为一个整体提交的,所以要么全部提交成功,要么就是全部不成功,这样就不会引起数据库的不完整和数据损坏。
2、重命名、复制、删除文件等动作都保存在版本历史记录当中。
3、对于二进制文件,使用了节省空间的保存方法。(简单的理解,就是只保存和上一版本不同之处)
4、目录也有版本历史。整个目录树可以被移动或者复制,操作很简单,而且能够保留全部版本记录。
5、分支的开销非常小。
6、优化过的数据库访问,使得一些操作不必访问数据库就可以做到。这样减少了很多不必要的和数据库主机之间的网络流量。
本章讨论了版本控制系统的生命周期。
创建版本库
版本库相当于一个集中的空间,用于存放开发者所有的工作成果。版本库不仅能存放文件,还包括了每次修改的历史,即每个文件的变动历史。
Create操作是用来创建一个新的版本库。大多数情况下这个操作只会执行一次。当你创建一个新的版本库的时候,你的版本控制系统会让你提供一些信息来标识版本库,例如创建的位置和版本库的名字。
检出
Checkout操作是用来从版本库创建一个工作副本。工作副本是开发者私人的工作空间,可以进行内容的修改,然后提交到版本库中。
更新
顾名思义,update操作是用来更新版本库的。这个操作将工作副本与版本库进行同步。由于版本库是由整个团队共用的,当其他人提交了他们的改动之后,你的工作副本就会过期。
让我们假设Tom和Jerry是一个项目的两个开发者。他们同时从版本库中检出了最新的版本并开始工作。此时,工作副本是与版本库完全同步的。然后,Jerry很高效的完成了他的工作并提交了更改到版本库中。
此时Tom的工作副本就过期了。更新操作将会从版本库中拉取Jerry的最新改动并将Tom的工作副本进行更新。
执行变更
当检出之后,你就可以做很多操作来执行变更。编辑是最常用的操作。你可以编辑已存在的文件,例如进行文件的添加/删除操作。
你可以添加文件/目录。但是这些添加的文件目录不会立刻成为版本库的一部分,而是被添加进待变更列表中,直到执行了commit操作后才会成为版本库的一部分。
同样地你可以删除文件/目录。删除操作立刻将文件从工作副本中删除掉,但该文件的实际删除只是被添加到了待变更列表中,直到执行了commit操作后才会真正删除。
Rename操作可以更改文件/目录的名字。"移动"操作用来将文件/目录从一处移动到版本库中的另一处。
复查变化
当你检出工作副本或者更新工作副本后,你的工作副本就跟版本库完全同步了。但是当你对工作副本进行一些修改之后,你的工作副本会比版本库要新。在commit操作之前复查下你的修改是一个很好的习惯。
Status操作列出了工作副本中所进行的变动。正如我们之前提到的,你对工作副本的任何改动都会成为待变更列表的一部分。Status操作就是用来查看这个待变更列表。
Status操作只是提供了一个变动列表,但并不提供变动的详细信息。你可以用diff操作来查看这些变动的详细信息。
修复错误
我们来假设你对工作副本做了许多修改,但是现在你不想要这些修改了,这时候revert操作将会帮助你。
Revert操作重置了对工作副本的修改。它可以重置一个或多个文件/目录。当然它也可以重置整个工作副本。在这种情况下,revert操作将会销毁待变更列表并将工作副本恢复到原始状态。
解决冲突
合并的时候可能会发生冲突。Merge操作会自动处理可以安全合并的东西。其它的会被当做冲突。例如,"hello.c"文件在一个分支上被修改,在另一个分支上被删除了。这种情况就需要人为处理。Resolve操作就是用来帮助用户找出冲突并告诉版本库如何处理这些冲突。
提交更改
Commit操作是用来将更改从工作副本到版本库。这个操作会修改版本库的内容,其它开发者可以通过更新他们的工作副本来查看这些修改。
在提交之前,你必须将文件/目录添加到待变更列表中。列表中记录了将会被提交的改动。当提交的时候,我们通常会提供一个注释来说明为什么会进行这些改动。这个注释也会成为版本库历史记录的一部分。Commit是一个原子操作,也就是说要么完全提交成功,要么失败回滚。用户不会看到成功提交一半的情况。
本次安装在centos7.9上
1.安装
yuminstallsubversion
2.测试安装是否成功
svnserve--version
3.创建目录并配置
建立版本库目录
mkdir-pv/data/svn/tw-hxh/prod配置
svnadmincreate/data/svn/tw-hxh/prod#这里为什么有4级目录?#/data是根目录,这里不做解释#二级目录svn是一个识别目录,让人知道这是svn的存储目录#tw-hxh这是一个项目的所有目录,为什么这里要指定tw-hxh标识?是因为这个项目下面到时候会有很多版本库,比如prod,test,cqc,所有版本库的认证和密码文件也可以放在这里目录下面,那么这样可能就是针对单个项目搭建的svn#prod这是单个版本库的目录,可能有cqc,test等版本库执行上面的命令后,自动建立repo测试库,查看/data/svn/tw-hxh/prod文件夹发现包含了conf,db,format,hooks,locks,README.txt等文件,说明一个SVN库已经建立。
创建svn项目时,用svnadmin来创建项目,如果不是使用svn来创建,那么svn就不是svn可管理的项目了
用svnadmincreate–help也可以看到,svn1.6版本创建的默认文件类型为fsfs
4.配置用户密码
用户名口令文件由svnserve.conf的配置项password-db指定,缺省为conf目录中的passwd。该文件仅由一个[users]配置段组成。
[users]配置段的配置行格式如下:
<用户名>=<口令>
注意:配置行中的口令为未经过任何处理的明文。
建立用户lizexiong,密码huawei
5.权限配置
权限配置文件由svnserve.conf的配置项authz-db指定,缺省为conf目录中的authz。该配置文件由一个[groups]配置段和若干个版本库路径权限段组成。
[groups]配置段中配置行格式如下:
<用户组>=<用户列表>
用户列表由若干个用户组或用户名构成,用户组或用户名之间用逗号","分隔,引用用户组时要使用前缀"@"(如:引用用户组"all"要使用字符串"@all")。
版本库路径权限段的段名格式如下:
[<版本库名>:<路径>]
如版本库abc路径/tmp的版本库路径权限段的段名为"[abc:/tmp]"。
可省略段名中的版本库名。若省略版本库名,则该版本库路径权限段对所有版本库中相同路径的访问控制都有效。如:段名为"[/tmp]"的版本库路径权限段设置了所有引用该权限配置文件的版本库中目录"/tmp"的访问权限。
版本库路径权限段中配置行格式有如下三种:
<用户名>=<权限>
<用户组>=<权限>
*=<权限>
其中,"*"表示任何用户;权限的取值范围为''、'r'和'rw',''表示对该版本库路径无任何权限,'r'表示具有只读权限,'rw'表示有读写权限。
注意:每行配置只能配置单个用户或用户组。
设置哪些用户可以访问哪些目录
6.服务svnserve.conf配置
注意:所有的行都必须顶格,否则报错。
[general]配置段中配置行格式如下:
<配置项>=<值>
配置项分为以下5项:
anon-access控制非鉴权用户访问版本库的权限。取值范围为"write"、"read"和"none"。
即"write"为可读可写,"read"为只读,"none"表示无访问权限。
缺省值:read
auth-access控制鉴权用户访问版本库的权限。取值范围为"write"、"read"和"none"。
缺省值:write
password-db指定用户名口令文件名。除非指定绝对路径,否则文件位置为相对conf
目录的相对路径。
缺省值:passwd
authz-db指定权限配置文件名,通过该文件可以实现以路径为基础的访问控制。
除非指定绝对路径,否则文件位置为相对conf目录的相对路径。
缺省值:authz
认证域相同,建议使用相同的用户名口令数据文件。
缺省值:一个UUID(UniversalUniqueIDentifier,全局唯一标示)。
[sasl]
简单来说就联系windows做验证的,这里用不到
这里在前文创建了统一的密码文件及权限文件文件夹,这里把密码文件和权限文件全部指定到该文件夹下面,这样的好处是当有了多个项目版本库的时候都使用同一个文件
vim/data/svn/tw-hxh/prod/conf/svnserve.conf在[general]下追加以下内容
7.svn目录结构
在svn创建仓库启动后,会有一系列以下目录,这里还是贴出一下解释
8.启动服务
查看svn的服务是否启动
ps-ef|grepsvn如果没有启动执行下面命令即可:
svnserve-d-r/data/svn/tw-hxh/prod--listen-port=3690--log-file/data/svn/tw-hxh/prod/svn.log#这里-r/data/svn/tw-hxh/prod很重要,如果是/data/svn/tw-hxh/prod启动,那么这个目录就是svn的根目录,后面在创建其它版本库就会比较麻烦,因为你指定了一个版本库作为启动根目录svnserve-d-r/data/svn/--listen-port=3690--log-file/data/svn/svn.log#如果是这样/data/svn,那么可以用svnadmin创建很多目录,并且通过统一的auth和passwd来管理用户和权限,甚至可以管理多个项目,如tw-hxh,cn-hxh,等等,但是权限方面就是独立的,这种方式废弃,linux上不存在svnserve-d-r/data/svn/tw-hxh--listen-port=3690--log-file/data/svn/tw-hxh/svn.log#如果是这样/data/svn/tw-hxh,那么可以用svnadmin创建很多目录,并且通过统一的auth和passwd来管理用户和权限,和第二种方式比起来,可以方便的管理一个项目的多个版本库,由于这里只是给单个项目更新用,所以选择这种方式,针对一个项目做管理,折中选择一下
9.访问
svn://ip地址
输入配置好的用户名和密码即可。
1).安装Apache
2).修改配置文件(没有则新建)
3).设置权限
chownapache:apache/data/svn/-R
-c:创建一个加密文件;
-m:默认采用MD5算法对密码进行加密;
-D:删除指定的用户。
-b:在命令行中一并输入用户名和密码而不是根据提示输入密码;
cd/etc/pki/tls/privateopensslgenrsa-outmy.key1024opensslreq-new-keymy.key-outmy.csrcd/etc/pki/tls/certsopensslx509-req-days365-in/etc/pki/tls/private/my.csr-signkey/etc/pki/tls/private/my.key-outmy.crt#以上命令,下面图示演示出使用方式生成服务器用的私钥文件my.key
这里按照提示输入信息,因为这里本人是用ip访问,所以填写的是IP
在网站名称的时候一定要填自己访问时输入的域名或者IP,否者证书会报错
这里写出提示输入的解释
SSLCertificateFile/etc/pki/tls/certs/my.crt
SSLCertificateKeyFile/etc/pki/tls/private/my.key
4).开启ssl模块,开启ssl访问
这里不开启所有ssl访问,否者不管什么访问都是ssl,如果只需要访问本地,只要在subversion.conf开启就可以了
注意,这里的访问链接地址一定要指定到版本库正确地址,否则会出现报错
如,本人版本库是svnrepos,那么链接地址就是
点击那个小锁就会发现出现以下内容
上面访问发现有证书风险,那是因为这个证书包括ca都是自建的,需要让浏览器信任我这个ca机构。(即使现在信任之后,也会有此网站尚未通过身份验证的错误,所以还是建议申请一个免费的ssl证书,腾讯云,阿里云都有)
导入刚才生成的/etc/pki/tls/certs/my.crt文件即可。
导入完成后就变成下面这种没有报错的情况,但是360浏览器还是会报错
ie浏览器显示正常,360可能经过了更新,几年前的360也会显示正常,但是该办法治标不治本,还是建议申请公共免费的ssl证书。
首先还是强调启动的时候/data/svn/tw-hxh为根目录,这样方便添加多版本库以及方便对多版本库管理。
那么就用svncheckouturl--username=lizexiong,以上两种方式都可以拉取代码。
以上命令将产生如下结果:
因为目前里面没有文件,所以啥都没有
在上一章中,我们检出了版本库tw-hxh/prod,对应的目录放在/tmp/svnurl/prod中,下面我们针对这个库进行版本控制。(这里使用svnurl做测试)
我们在库本版中需要增加一个readme的说明文件。
查看工作副本库的状态
此时readme的状态为?,说明它还未加到版本控制中。
将文件readme加到版本控制,等待提交到版本库。
查看工作副本中的状态
此时readme的状态为A,它意味着这个文件已经被成功地添加到了版本控制中。
为了把readme存储到版本库中,使用commit-m加上注释信息来提交。
如果你忽略了-m选项,SVN会打开一个可以输入多行的文本编辑器来让你输入提交信息。
现在readme被成功地添加到了版本库中,并且修订版本号自动增加了1。
当我们想放弃对文件的修改,可以使用SVNrevert命令。
svnrevert操作将撤销任何文件或目录里的局部更改。
我们对文件readme进行修改,查看文件状态。
比如在刚才的readmin文件中新增Thisisav2
现在查看状态
这时我们发现修改错误,要撤销修改,通过svnrevert文件readme回归到未修改状态。
进行revert操作之后,readme文件恢复了原始的状态。revert操作不单单可以使单个文件恢复原状,而且可以使整个目录恢复原状。恢复目录用-R命令,如下。
svnrevert-Rtrunk但是,假如我们想恢复一个已经提交的版本怎么办。
为了消除一个旧版本,我们必须撤销旧版本里的所有更改然后提交一个新版本。这种操作叫做reversemerge。
首先,找到仓库的当前版本,现在是版本2,我们要撤销回之前的版本,比如版本1。
(现在为了模拟环境,我们还是提交一个v2版本)
先准备一下测试环境,来演示下面的案例,因为刚才有个撤销操作,所以这里v3版本实际上是svn的4版本,我测试填写的版本号落后svn一位,这里需要注意。
可以显示所有的信息,如果只希望查看特定的某两个版本之间的信息,可以使用:
[root@publicprod]#svnlog-r4:6------------------------------------------------------------------------r4|lizexiong|2022-09-1918:20:55+0800(一,2022-09-19)|1行tw-hxh/prodv3------------------------------------------------------------------------r5|lizexiong|2022-09-1918:21:10+0800(一,2022-09-19)|1行tw-hxh/prodv4------------------------------------------------------------------------r6|lizexiong|2022-09-1918:21:19+0800(一,2022-09-19)|1行tw-hxh/prodv5------------------------------------------------------------------------如果只想查看某一个文件的版本修改信息,可以使用svnlog文件路径。
如果希望显示限定N条记录的目录信息,使用svnlog-lN-v。
[root@publicprod]#svnlog-l3-vreadme------------------------------------------------------------------------r8|lizexiong|2022-09-1918:21:37+0800(一,2022-09-19)|1行改变的路径:M/readmetw-hxh/prodv7------------------------------------------------------------------------r7|lizexiong|2022-09-1918:21:29+0800(一,2022-09-19)|1行改变的路径:M/readmetw-hxh/prodv6------------------------------------------------------------------------r6|lizexiong|2022-09-1918:21:19+0800(一,2022-09-19)|1行改变的路径:M/readmetw-hxh/prodv5------------------------------------------------------------------------
用来检查历史修改的详情。
(1)、如果用svndiff,不带任何参数,它将会比较你的工作文件与缓存在.svn的"原始"拷贝。
(2)、比较工作拷贝和版本库
比较你的工作拷贝和版本库中版本号为3的文件readme。
(3)、比较版本库与版本库
通过-r(revision)传递两个通过冒号分开的版本号,这两个版本会进行比较。
比较svn工作版本中版本号1和2的这个文件的变化。
如果只是希望检查一个过去版本,不希望查看他们的区别,可使用svncat
这个命令会显示在该版本号下的该文件内容
svnlist可以在不下载文件到本地目录的情况下来察看目录中的文件:
Branch选项会给开发者创建出另外一条线路。当有人希望开发进程分开成两条不同的线路时,这个选项会非常有用。
比如项目demo下有两个小组,svn下有一个trunk版。
由于客户需求突然变化,导致项目需要做较大改动,此时项目组决定由小组1继续完成原来正进行到一半的工作(某个模块),小组2进行新需求的开发。
那么此时,我们就可以为小组2建立一个分支,分支其实就是trunk版(主干线)的一个copy版,不过分支也是具有版本控制功能的,而且是和主干线相互独立的,当然,到最后我们可以通过(合并)功能,将分支合并到trunk上来,从而最后合并为一个项目。
我们在本地副本中创建一个my_branch分支。
[root@publicprod]#svnmkdirtrunktagsbranchesAtrunkAtagsAbranches[root@publicprod]#lsbranchesreadmetagstrunk[root@publicprod]#cdtrunk/[root@publictrunk]#echo"HelloWorld">>HelloWorld.html[root@publictrunk]#svnaddHelloWorld.htmlAHelloWorld.html[root@publictrunk]#svncommit-m"trunk/HelloWorld.thml"正在增加.正在增加HelloWorld.html传输文件数据.提交后的版本为34。[root@publictrunk]#svnstatus#以上是准备环境,先提交一下trunk的环境HelloWorld.html到svn,然后在创建分支[root@publictrunk]#cd../[root@publicprod]#svncopytrunk/branches/my_branchAbranches/my_branch查看状态:
[root@publicprod]#svnstatusAbranchesA+branches/my_branchAtags提交新增的分支到版本库。
这里因为branches,tag,trunk都是一起创建测试的,所以会显示出所有的一起提交,但是不要紧,知道就行。
[root@publicprod]#svncommit-m"addmy_branch"正在增加branches正在增加branches/my_branch正在增加tags提交后的版本为35。接着我们就到my_branch分支进行开发,切换到分支路径并创建index.html文件。
[root@publicprod]#cdbranches/my_branch/[root@publicmy_branch]#lsHelloWorld.html[root@publicmy_branch]#echo"index">>index.html[root@publicmy_branch]#lsHelloWorld.htmlindex.html将index.html加入版本控制,并提交到版本库中。
[root@publicmy_branch]#svnstatusindex.html[root@publicmy_branch]#svnaddindex.htmlAindex.html[root@publicmy_branch]#svncommit-m"addindex.html"正在增加index.html传输文件数据.提交后的版本为36。切换根下,这里是prod,执行svnupdate,然后切换到trunk,然后将my_branch分支合并到trunk中。
[root@publicmy_branch]#cd../../#这里一定要切换到跟下svnupdate,然后切换到trunk下面合并,否则合并信息为空[root@publicprod]#svnupdate正在升级'.':版本36。[root@publicprod]#cdtrunk/[root@publictrunk]#svnmerge../branches/my_branch/---正在合并r35,经由r36,到“.”:Aindex.html---记录合并r35,经由r36,到“.”的信息:G.此时查看目录,可以看到trunk中已经多了my_branch分支创建的index.html文件。
[root@publictrunk]#lsHelloWorld.htmlindex.html[root@publictrunk]#pwd/tmp/svnurl/prod/trunk将合并好的trunk提交到版本库中。
[root@publictrunk]#pwd/tmp/svnurl/prod/trunk[root@publictrunk]#svncommit-m"addtrunkindex.htm"正在发送.正在增加index.html提交后的版本为37。[root@publictrunk]#svnstatus
版本管理系统支持tag选项,通过使用tag的概念,我们可以给某一个具体版本的代码一个更加有意义的名字。
Tags即标签主要用于项目开发中的里程碑,比如开发到一定阶段可以单独一个版本作为发布等,它往往代表一个可以固定的完整的版本,这跟VSS中的Tag大致相同。
我们在本地工作副本创建一个tag。
[root@publicprod]#svncopytrunk/tags/v1.0Atags/v1.0上面的代码成功完成,新的目录将会被创建在tags目录下。
[root@publicprod]#lstags/v1.0[root@publicprod]#lstags/v1.0/HelloWorld.htmlindex.html查看状态。
[root@publicprod]#svnstatusA+tags/v1.0A+tags/v1.0/HelloWorld.html提交tag内容。
[root@publicprod]#svncommit-m"tagsv1.0"正在增加tags/v1.0正在增加tags/v1.0/HelloWorld.html提交后的版本为38。[root@publicprod]#svnstatus
版本冲突原因:
假设A、B两个用户都在版本号为100的时候,更新了kingtuns.txt这个文件,A用户在修改完成之后提交kingtuns.txt到服务器,这个时候提交成功,这个时候kingtuns.txt文件的版本号已经变成101了。同时B用户在版本号为100的kingtuns.txt文件上作修改,修改完成之后提交到服务器时,由于不是在当前最新的101版本上作的修改,所以导致提交失败。
我们已在本地检出prod库,下面我们将实现版本冲突的解决方法。
我们发现HelloWorld.html文件存在错误,需要修改文件并提交到版本库中。
#第一个用户[root@publictrunk]#catHelloWorld.htmlHelloWorld!www.lizexiong.com用下面的命令查看更改:
#第一个用户[root@publictrunk]#svndiffIndex:HelloWorld.html===================================================================---HelloWorld.html(版本36)+++HelloWorld.html(工作副本)@@-1+1@@-HelloWorld+HelloWorld!www.lizexiong.com尝试使用下面的命令来提交他的更改:
因为此时,HelloWorld.html已经被user01修改并提交到了仓库。Subversion不会允许user02(本例使用的svn账号)提交更改,因为user01已经修改了仓库,所以我们的工作副本已经失效。
为了避免两人的代码被互相覆盖,Subversion不允许我们进行这样的操作。所以我们在提交更改之前必须先更新工作副本。所以使用update命令,如下:
默认是更新到最新的版本,我们也可以指定更新到哪个版本
svnupdate-r6此时工作副本是和仓库已经同步,可以安全地提交更改了
[root@publictrunk]#catHelloWorld.htmlHelloWorld!www.baidu.com[root@publictrunk]#svncommit-m"changeHelloWorld.htmlseconduser"正在发送HelloWorld.html传输文件数据.提交后的版本为42。警告:postcommitFSprocessinghaderror:sqlite:attempttowriteareadonlydatabase
1).钩子简介
钩子脚本的具体写法就是操作系统中shell脚本程序的写法,请根据自己SVN所在的操作系统和shell程序进行相应的写作
所谓钩子就是与一些版本库事件触发的程序,例如新修订版本的创建,或是未版本化属性的修改。每个钩子都会被告知足够多的信息,包括那是什么事件,所操作的对象,和触发事件的用户名。通过钩子的输出或返回状态,钩子程序能让工作继续、停止或是以某种方式挂起。
其实简单来说,就是在我的版本更新前或者更新后触发某些事情,如:上传版本前,我限制这个文件大小,提交备注信息的长度,上传版本后,同步svn的文件等
默认情况下,钩子的子目录中包含各种版本库钩子模板。
$lsrepos/hooks/post-commit.tmplpre-revprop-change.tmplpost-revprop-change.tmplstart-commit.tmplpre-commit.tmpl提示
由于安全原因,Subversion版本库在一个空环境中执行钩子脚本—就是没有任何环境变量,甚至没有$PATH或%PATH%。由于这个原因,许多管理员会感到很困惑,它们的钩子脚本手工运行时正常,可在Subversion中却不能运行。要注意,必须在你的钩子中设置好环境变量或为你的程序指定好绝对路径。
2.)钩子的默认模版
目前Subversion有已实现了五种钩子:
start-commit.bat
它在提交事务产生前已运行,通常用来判定一个用户是否有权提交。版本库传给该程序两个参数:到版本库的路径,和要进行提交的用户名。如果程序返回一个非零值,会在事务产生前停止该提交操作。如果钩子程序要在stderr中写入数据,它将排队送至客户端。
pre-commit.bat
在事务完成提交之前运行,通常这个钩子是用来保护因为内容或位置(例如,你要求所有到一个特定分支的提交必须包括一个bug追踪的ticket号,或者是要求日志信息不为空)而不允许的提交。版本库传递两个参数到程序:版本库的路径和正在提交的事务名称,如果程序返回非零值,提交会失败,事务也会删除。如果钩子程序在stderr中写入了数据,也会传递到客户端。
post-commit.bat
它在事务完成后运行,创建一个新的修订版本。大多数人用这个钩子来发送关于提交的描述性电子邮件,或者作为版本库的备份。版本库传给程序两个参数:到版本库的路径和被创建的新的修订版本号。退出程序会被忽略。
Subversion分发版本中包括mailer.py和commit-email.pl脚本(存于Subversion源代码树中的tools/hook-scripts/目录中)可以用来发送描述给定提交的email(并且或只是追加到一个日志文件),这个mail包含变化的路径清单,提交的日志信息、日期和作者以及修改文件的GNU区别样式输出。
Subversion提供的另一个有用的工具是hot-backup.py脚本(在Subversion源代码树中的tools/backup/目录中)。这个脚本可以为Subversion版本库进行热备份(BerkeleyDB数据库后端支持的一种特性),可以制作版本库每次提交的快照作为归档和紧急情况的备份。
pre-revprop-change.bat
因为Subversion的修订版本属性不是版本化的,对这类属性的修改(例如提交日志属性svn:log)将会永久覆盖以前的属性值。因为数据在此可能丢失,所以Subversion提供了这种钩子(及与之对应的post-revprop-change),因此版本库管理员可用一些外部方法记录变化。作为对丢失未版本化属性数据的防范,Subversion客户端不能远程修改修订版本属性,除非为你的版本库实现这个钩子。
这个钩子在对版本库进行这种修改时才会运行,版本库给钩子传递四个参数:到版本库的路径,要修改属性的修订版本,经过认证的用户名和属性自身的名字。
3.)钩子的基本使用简介
1.把文件改名把后缀.tmpl去掉
2.赋予钩子文件755权限
3.钩子执行的命令就是shell脚本,只要在文件尾部写入可执行的shell命令即可
就拿上面的tw-hxh来说,假设tw-hxh下面有prod代码,test代码,cqc的代码,我们怎么控制权限和用户,总不能一个代码库一套用户和密码吧?虽然是可以,但是一般情况下,一个版本库里面都是一组相同的研发人员,每个代码库都使用相同的authz和passwd文件,那不是太繁琐了吗?
假设我们的代码树目录是这样的。
[root@publictest]#treetw-hxh/tw-hxh/├──cqc├──prod└──test碰到以上情况,使用svdadmincreatecqc?prod?test?每个配置文件都独立吗?
当然不用,完全可以在每个代码库的conf的svnserve.conf下指定公用的authz和passwd文件即可。
当然,配置文件肯定有小小的改动。
1.创建目录并配置
建立对应的所有的版本库目录
mkdir-pv/data/svn/tw-hxh/prodmkdir-pv/data/svn/tw-hxh/testmkdir-pv/data/svn/tw-hxh/cqc配置
svnadmincreate/data/svn/tw-hxh/prodsvnadmincreate/data/svn/tw-hxh/testsvnadmincreate/data/svn/tw-hxh/cqc#这里为什么有4级目录?这里就不做解释,查看第3节SVN安装即可
2.配置用户密码
这里的区别就体现出来了,因为之前的passwd文件是不是在/data/svn/tw-hxh/prod/conf/passwd下面?
那么尽然/data/svn/tw-hxh/是项目版本库,prod,cqc,test都是他们的一套管理代码流程,那么passwd就能放在/data/svn/tw-hxh下面呀,其它的cqc和test也好调用。所以见如下:
[root@k8s-lizexiongtw-hxh]#lscqcpasswdprodsvn.logtest[root@k8s-lizexiongtw-hxh]#pwd/data/svn/tw-hxh所以单个代码库的conf下面就不用passwd文件了。passwd放到项目的跟目录就行
当然以下还是多添加2个用户来做等会的测试
[root@k8s-lizexiongtw-hxh]#cat/data/svn/tw-hxh/passwd[users]lizexiong=huaweiwuxinzhe=huaweiliuwen=huawei
3.权限配置
尽然passwd可以这么做,那么authz当然可以一样。
[root@k8s-lizexiongtw-hxh]#cat/data/svn/tw-hxh/authz[aliases]#joe=/C=XZ/ST=Dessert/L=SnakeCity/O=SnakeOil,Ltd./OU=ResearchInstitute/CN=JoeAverage[groups]#*=r[/]lizexiong=rw[cqc:/]wuxinzhe=rw[test:/]liuwen=r
4.服务svnserve.conf配置
重要的来了,passwd和authz都移动到了版本库的根目录下,怎么才知道代码库的权限和予许哪些用户访问呢?
这里的svnserve.conf就必须独立了,都各自放到单独的代码库下面
5.服务启动
之前第三节svn安装里面非常明确的讲解过,到底哪一层为工作目录,这个非常重要,这次的案例就是以下:(一定记得要重启)
svnserve-d-r/data/svn/tw-hxh--listen-port=3690--log-file/data/svn/tw-hxh/svn.log
6.HTTP以及HTTPS
对应的HTTP以及HTTPS这里就不用多说,和svn更改方式一样,所以这里就略过了
7.测试
首先验证wuxinzhe和liuwen对prod代码库没有访问权限
wuxinzhe对test没有读写权限
liuwen对cqc没有读写权限
然后验证wuxinzhe对cqc代码有读写权限
接下来liuwen对test只有读权限
最后lizexiong对所有仓库拥有所有权限
以下该章节就保留了,以下演示是个错误的,因为无法使用svnserve-r/data/svn直接控制深入的2级目录,如果想实现一个项目,下面很多文件夹,然后根据项目/文件夹访问,那么只有windows上的版本可以实现,目前,windows版本已经收费了,所以linux上可以使用12小结通过不同的版本和名称来控制,但是不太规范,也可以实现。
以下的方式是有问题的,因为这里做了,所以这里还是保留我的错误示范,如果需要多版本库管理和控制,参考12小结即可
和上一小节来对比,这里说出了多个项目,多个项目什么意思?
就拿上面的tw-hxh来说,假设tw-hxh下面有prod代码,test代码,cqc的代码,直接在/data/svn/tw-hxh下公共管理项目用户和权限就行了
那如果有多个项目呢?比如tw-hxh,tw-yuu,那么怎么办?
其实也很好解决,每个项目就像上一小节一样创建就行,并且权限代码也是相同管理,但是启动目录需要改成,还要向上一层,比如一个版本库,多个代码库,启动目录是/data/svn/tw-hxh,现在多个项目,那么就是/data/svn/了
那么目录树就变成这个样子了
[root@k8s-lizexiongsvn]#tree/data/svn/-L2/data/svn/├──svn.log├──tw-hxh│├──authz│├──cqc│├──passwd│├──prod│├──svn.log│└──test└──tw-yuu├──authz├──cbt├──passwd└──prod以上的tw-hxh的权限和任何都不需要改,直接新建tw-yuu的项目所需信息就行了。
mkdir-pv/data/svn/tw-yuu/prodmkdir-pv/data/svn/tw-yuu/cbt配置
svnadmincreate/data/svn/tw-yuu/prodsvnadmincreate/data/svn/tw-yuu/cbt
那么tw-yuu的帐号认证信息当然也是放在他自己的目录/data/svn/tw-yuu下了
[root@k8s-lizexiongtw-yuu]#lsprodcbt[root@k8s-lizexiongtw-yuu]#pwd/data/svn/tw-yuu所以单个代码库的conf下面就不用passwd文件了。
[root@k8s-lizexiongtw-yuu]#cat/data/svn/tw-yuu/passwd[users]zhuwenjing=huaweiqinhaiwei=huawei
[root@k8s-lizexiongtw-yuu]#cat/data/svn/tw-yuu/authz[aliases][groups][/]zhuwenjing=rw[cbt:/]qinhaiwei=rw
以下的代码不用多解释,按照一个版本库的案例配置即可,一摸一样即可
这里就是最重要的,启动工作目录一定要是/data/svn了,否则就是一个版本仓库了,所以基本多个项目就启动这里有这么点区别。(日志最好也可以改改,但是不改问题也不大)
svnserve-d-r/data/svn/--listen-port=3690--log-file/data/svn/svn.log
权限什么都不对,直接废弃,不做测试
运行下载的TortoiseSVN安装程序
正确安装后,应该进行一次的重开机,以确保TortoiseSVN的正确无误。
修改TortoiseSVN默认语言
TortoiseSVN安装完后默认的界面是英文的,我们可以通过设置修改成已安装语言
所谓的svntest目录其实就是您平常用来存放工作档案的地方。通常我们会等到自己的工作做的一个段落的时候再进行备份。所以我们平常都是在svntest目录下面工作,等到适当时机在commit到repository中。举例来说,我们想在D盘下面建立一个名为svntest的目录。首先先把这个目录建立出来。
进入创建的目录在空白处按下右键后(您可以在MyWork目录的icon上按,也可进入MyWork目录后,在空白的地方按),选择SVNcheckout。
接着您可以看到如下的画面:
首先我们要填入的是repository(版本库)的位置,对于SVN来说,repository的位置都是URL。版本库URL这里填入我们测试的版本仓库地址svn://172.21.161.161/prod。
接着,稍微看一下Checkoutdirectory(检出至目录),这个字段应该要指向您的svntest目录。
确认后,按下OK按钮,然后输入用户名和密码。您应该可以看到如下的信息窗口。
这样就表示动作完成。按下OK按钮后,再到您刚刚建立的目录下。您将会看到MyWork目录下面多了一个名为.svn的目录(这个目录是隐藏的,如果您的档案管理员没有设定可以看到隐藏目录,您将无法看到它)。当然还有一些之前的测试文件以及目录。这些测试文件这里就先删除了。以便后面测试的时候看的清晰点。
如果您要在一个已经存在的SVNServer上面checkout出上面的档案,您只需要给定正确的SVNURL以及要checkout目录的名称。就可以取得指定的档案及目录了。
创建目录dir01,在目录里新增文件
将新增的文件加入到SVN版本控制中,TortoiseSVN会把准备要加入的档案及目录,勾选需要加入的文件。(文件夹右键→TortoiseSVN→增加)
按下OK后,您将会看到如下的讯息窗口:
这个Add(增加)的动作并未真正的将档案放到Repository中。仅仅是告知SVN准备要在Repository中放入这些档案。此时的文件状态为:(文件夹右键→TortoiseSVN→检查修改)
这些档案真正的放入到Repository中,空白处右键选择SVNcommit(提交)紧接着,您将会看到如下的窗口出现:
在这里可以清楚地了解到哪些档案要被commit到repository(版本库)中。同样的,如果您有档案不想在这个时候commit到Repository,您可以取消选取的档案,这样他们就不会被commit到Repository中。在"信息"文本框中可以写入对本次commit的说明。
点击"确认"后完成commit动作,然后您可以到svntest目录中,确定是否所有的档案icon都有如下的绿色勾勾在上面,这样代表您的档案都正确无误的到repository中。
由于版本控制系统多半都是由许多人共同使用。所以,同样的档案可能还有人会去进行编辑。为了确保您工作目录中的档案与Repository中的档案是同步的。建议您在编辑前都先进行更新的动作。
在想要更新的档案或目录icon上面按下鼠标右键。并且选择SVNUpdate
有时我们需要回溯至特定的日期或是版本,这时就可以利用SVN的Updatetorevision的功能。在想要更新的档案或目录icon上面按下鼠标右键。并且选择TortoiseSVN->Updatetorevision(更新至版本)。
很多时候您会希望有另外一个复制的目录来进行新的编修。等到确定这个分支的修改已经完毕了,再合并到原来的主要开发版本上。举例来说,我们目前在svntest/trunk下面有如下的目录及档案:
准备环境:以下trunk/file.txt已经提交到svn
现在,我们要为trunk这个目录建立一个branch。假设我们希望这个目录是在D:\svntest\branch。首先我们可以在trunk目录下面的空白处,或是直接在trunk的icon下面按下鼠标右键选择Branch/Tag…(分支/标记)这个选项,您将会看到如下的对话框出现。
如果成功,将可以看到下面的画面:
按下OK就可以关闭这个窗口了。如果您此时立刻去svntest目录的branch子目录下面,您将会失望的发现在该目录下面并没有刚刚指定的目录存在。这是因为您svntest目录的部份还是旧的,您只需要在branch子目录下面进行SVNupdate就可以看到这个新增的目录了。新增的目录就与原来的目录无关了。您可以任意对他进行编辑,一直到您确认好所有在branch下面该做的工作都完成后,您可以选择将这个branchmerge回原来的trunk目录,或者是保留它在branch中。
(这里一定要svnupdate一波)
假如我们在branch分支中对文件进行了修改或增加了文件,要merge回trunk目录中,方法很简单。以上面的例子来说,我们在D:\svntest\trunk目录空白处,按下鼠标右键,选择Merge(合并):
以下画面主要分为三个部份,前面的From:与To:是要问您打算从Branch中的哪个版本到哪个版本,merge回原来的trunk目录中。因此,From跟To的URL字段应当都是指定原来branch的目录下。剩下的就是指定要merge的revision范围。以上面的例子而言,我们从Branch的Revision50开始merge到Branch下面的最新版本。您可以透过,Dryrun按钮,试作一次Merge。这个merge只会显示一些讯息,不会真正的更新到trunk的目录去。只有按下Merge按钮后,才会真正的将branch的档案与trunk的档案合并起来。
查看trunk文件夹是否多出了branch的新增文件
如果您确认这次的merge没有问题,您可以直接使用commit来将这两个被修改的档案commit回SVNrepository上。如果有问题,您可以直接修改这两个档案,直到确认ok了,再行commit。
所谓的Tag或是Release就是一个特别的版本,因为这个版本可能有特别的意义。例如:这个版本是特别的Milestone或是release给客户的版本。其实,Tag与Release的作法与Branch完全相同。只是Branch可能会需要merge回原来的trunk中,而tag及release大部分都不需要merge回trunk中。
成功的话,您就在对应的Tag目录下面建立了一个v1.0的目录。当然,如果您这时到Tag的目录下面去(如果这个tag目录是手动创建的),会看不到这个目录,您需要在Tag目录下面update一下,才能看到它。