和git一样,svn(subversion)作为一个版本控制系统,它主要实现的功能无非是三个:第一,保存你的项目文件,就算你的电脑不幸坏了,也能找回你的项目;第二,版本控制,像时光机一样让你在你的项目之前保存的版本里面自由穿梭;第三,团队协作,让多个人共同完成一个项目成为可能。
下面在Mac系统中用命令行的方式简单演示一下svn上述的三大功能。
架构
在开始接触svn之前,先看一下svn的架构图:
svn架构
这个架构图中,上面一端是客户端程序,下面一端是Subversion仓库(后面简称仓库),整个图大致说明了客户端和仓库的通讯方式。我们从上往下看:
图的顶部,是command-line
和GUI client apps
,代表我们使用svn的两种类型的客户端:命令行客户端或者图形界面客户端。这篇文章介绍的是命令行客户端的使用方式。
再往下看,是客户端访问仓库的三种方式:HTTP
,SVN
,Local
,HTTP
,SVN
都是通过网络访问资源库的,Local
就是直接访问本地的仓库。
最下面,是Subversion Repository
,也就是我们的仓库。
svn是集中式的版本控制 (centralized version control)—有一个远程的主仓库, 仓库中存放了被版本控制的数据, 用户在本地操作数据的浅拷贝副本(而鼎鼎大名的Git是分布式版本控制系统)。
保存项目文件
在开始之前,先确认你的Mac里安装了svn。如果你安装了Xcode,Xcode会自动为你的Mac安装svn。
终端指令(文章后面没有特别提示,都是终端指令):
svn --version
如果能看到svn的版本信息,说明你的电脑已经安装了svn。
下面从创建仓库、添加仓库用户和将已有项目导入到仓库三个部分,演示如何用svn仓库来保存你的项目文件。
创建仓库
确认电脑安装了svn后,我们就来创建仓库。创建仓库使用的app是svnadmin
,使用的指令是:
svnadmin create [仓库路径]
[仓库路径]
指向一个空文件夹,使用绝对路径和相对路径都可以。假设我们设置的路径是/users/xiaoming/repos
,上述命令执行完后,如果成功创建了仓库,/users/xiaoming/repos
文件夹里应该会生成如下文件:
README.txt conf db format hooks locks
看到这些文件,代表我们的仓库创建成功了。
配置用户
仓库的使用者分为游客和用户两种类型。下一步,是要为仓库添加用户。进入文件夹/users/xiaoming/repos/conf
,我们发现conf
文件夹里有以下文件:
authz hooks-env.tmpl passwd svnserve.conf
其中passwd
是配置用户信息的, authz
是配置用户权限的,但默认情况下这两个文件是无效的,我们先要去同一目录下的svnserve.conf
文件内进行修改,让这两个文件生效:
使用vim
编辑器打开svnserve.conf
文件:
vi svnserve.conf
打开svnserve.conf
文件后,我们发现里面一大堆的注释,关于svnserve.conf
文件如何配置,这些注释写的很清楚,英文好的可以认真读一下。下面直接说一般情况下如何修改。
首先,找到anon-access
和auth-access
这两个配置项,并取消它们的注释。anon-access
配置的是游客访问仓库的权限,默认是只读;auth-access
配置的是用户访问仓库的权限,默认是可读可写:
anon-access = read
auth-access = write
然后,找到password-db
配置,并去除注释。该配置默认的值是passwd
,也就是前面我们说的配置用户信息的passwd
文件。这样passwd
文件就生效了。
最后,找到authz-db
配置,并去除注释。该配置默认的值是authz
,也就是前面我们说的配置用户权限的authz
文件。这样authz
文件就生效了。
保存退出,svnserve.conf
文件就配置完毕了。下面我们就来添加用户:
打开passwd
文件:
vi passwd
里面也有很多注释,通过注释我们知道添加用户的格式是:
# harry = harryssecrt
比方说我们要添加两个用户:用户名xiaoming
,密码xm666
; 用户名tom
,密码tom666
;那么我们应该这么写:
[users]
xiaoming = xm666
tom = tom666
保存退出,我们就成功添加用户xiaoming
和tom
了。
前面在svnserve.conf
文件中我们已经对游客和用户的权限进行了全局配置,但由于我们激活了authz
文件,所以我们需要在authz
文件中对用户的权限进行更详细的设置。
打开authz
文件:
vi authz
打开authz
文件后,里面同样有很多注释,英文好的看注释也能大概知道怎么配置。authz
文件能配置的信息主要是:
1.添加组。例如和可以将xiaoming
和tom
编为一组,并设置组名;
2.指定用户在特定仓库路径的权限。例如,我们可以指定仓库中xxx/core
这个文件夹,哪些用户可以读写,哪些用户只能读,哪些用户不可访问。
例如,我要将xiaoming
和tom
编为一组,取组名为developer
,developer
这个组可以读写仓库根目录下的所有文件;另外,我还要特别指明xiaoming
不可访问根目录下的tom_only.txt
文件。那么我们应该这么配置:
#将xiaoming和tom编为一组,组名是developer
[groups]
developer = xiaoming,tom
#在仓库根目录下,developer组的所有成员都能读写
[/]
@developer = rw
#xiaoming不能访问根目录下的tom_only.txt文件
[/tom_only.txt]
tom = rw
xiaoming =
[/]
表示仓库的根目录,然后仓库的其他目录你应该知道怎么写了,比如根目录下的tom_only.txt
文件就是[/tom_only.txt]
。
在设置组名权限时,组名需要用@
开头,上面设置developer
组时是这样写的@developer = rw
。r
表示只读,rw
表示读写,留空表示不可访问。
上传项目到仓库
目前仓库已经创建好,也配置了该仓库的用户,但是现在仓库还是空的。假设我们现在已经有一个项目在/users/xiaoming/ios
路径下, ios
这个文件夹里是我们的项目文件。那么我们可以通过命令:
svn import [项目路径] [仓库路径] --username=[用户名] -m '[信息]'
[项目路径]
就是你已经有的项目的路径,可以使用相对路径。需要特别说明的是[仓库路径]
,上面我们看架构图时,已经知道客户端和仓库通讯的方式有三种:1. HTTP;2.svnserve;3.Local。不同的通讯方式使用不同的通讯协议。对于Local的方式,仓库路径需要用file://
开头,然后后面接上本地仓库的绝对路径。例如当前仓库的绝对路径是/users/xiaoming/repos
,假设要把项目导入到仓库的ios
文件夹里,那么仓库路径应该是file:///users/xiaoming/repos/ios
。[用户名]
指定执行导入任务的用户。[信息]
就是对你的这次导入写一点备注。
那么导入已有的项目到本地仓库的指令示例如下:
svn import /users/xiaoming/ios file:///users/xiaoming/repos/ios --username=xiaoming -m 'initial import'
通常我们不是只有一个项目。假设我还有一个android
项目也需要使用svn进行版本管理,那么我们可以有两种方案:
-
再创建一个svn仓库;
-
将
android
项目也放到上述仓库中。
是的,一个仓库是可以存放多个项目的,理论上可以存无限个项目。其示意图如下:
仓库目录那么我们可以将我们的android
项目也放到仓库的android
目录中:
svn import /users/xiaoming/android file:///users/xiaoming/repos/android --username=xiaoming -m 'initial import'
至此,我们的仓库就大功告成了,你的项目就能保存在svn仓库里了。
版本管理
版本管理是最重要的功能了。下面从检出工作副本、提交版本和时光机三个部分演示版本管理功能。
检出工作副本
我们不会在仓库里工作,就算你想这么干,也不可能。因为就算你已经把项目导入到仓库,你发现在仓库里根本看不到你的项目。你发现你的仓库依然只有这些文件:
README.txt conf db format hooks locks
真正工作的地方,是工作副本。你需要从仓库检出工作副本,然后在工作副本上工作。检出工作副本的指令是:
svn checkout [仓库路径] [项目路径] --username=[用户名] --password=[用户密码]
这里再重复一次,客户端和仓库通讯的方式有三种:1. HTTP;2.svnserve;3.Local。和本地仓库通讯的协议是file://
。所以从本地仓库检出工作副本的指令示例:
svn checkout file:///users/xiaoming/repos/ios ./ios --usernae=xiaoming --password=xm666
注意上面示例中,[本地路径]
是可以使用相对路径的。这样就可以检出工作副本了,然后就可以在工作副本中愉快地开始你的项目了。
提交版本
首先,如果你在工作副本中创建了新的文件,新创建的文件是不会被svn进行版本管理的。需要使用如下指令添加到svn进行管理(下面的终端指令都是在你的工作副本中执行的):
svn add [文件路径]
然后,你可以使用:
svn revert
撤销你当前还没有保存的所有代码。
当然你也可以:
svn revert [文件路径]
撤销指定文件还没有保存的代码。
OK,现在你改了很多内容,你想看看你具体改了哪些,你可以在你的工作副本中使用如下命令来查看更改:
svn status
没有其他问题的话,就能提交提交新版本了:
svn commit -m '[信息]'
每次提交新版本后,你最好使用将你的工作副本更新到仓库的最新版本:
svn update
这里顺便一提svn提交版本的一个硬伤:如果你是通过网络来访问仓库,那么离线的状态下你是无法提交版本的(而隔壁家Git就没有这个问题)。
时光机
时光机,就是在不同的版本中切换。首先我们要知道当前有哪些版本:
svn log
输出:
r3 | xiaoming | 2020-04-03 20:58:31 +0800 (五, 03 4 2020) | 1 line
foo
------------------------------------------------------------------------
r1 | xiaoming | 2020-04-03 20:03:59 +0800 (五, 03 4 2020) | 1 line
initial import
------------------------------------------------------------------------
上面日志输出了两个版本,其中r1
和r3
就是它们的版本号。我们可以通过指令:
svn update -[版本号]
将工作副本切换到不同的版本,例如
svn update -r1
我们就能切换到版本r1
。
多人协作
多人协作,往往离不开分支。每人开辟自己的分支,在自己的分支上工作,就不会影响其他人的进度,等到分支的任务完成,就合并到主分支。合并主分支时,可能会和其他人修改了同一个地方,那么就会产生冲突,所以需要解决冲突之后才能顺利合并分支。
分支示意图下面从创建分支和合并分支两部分演示分支的使用。
创建分支
创建分支非常简单:就是用命令svn copy
在仓库中为项目创建一个副本。所以在svn中,分支就是一个副本(注意区别工作副本)。
比如说,当前仓库中项目的位置是file:///users/xiaoming/repos/ios
(本地仓库),准备把它拷贝到位置file:///users/xiaoming/repos/ios-branch-dev
,那么指令是:
svn copy file:///users/xiaoming/repos/ios file:///users/xiaoming/repos/ios-branch-dev -m 'create branch dev'
那么,副本file:///users/xiaoming/repos/ios-branch-dev
就是我们的分支了。
那么怎么使用分支呢?因为分支其实是仓库中的一个副本,所以需要将这个分支检出工作副本,还是老样子,在工作副本中工作。假设要检出到本地的路径是/users/xiaoming/ios-dev
:
svn checkout file:///users/xiaoming/repos/ios-branch-dev /users/xiaoming/ios-dev --username=xiaoming --password=xm666
如果你要使用分支,仓库的目录结构最好调整一下。前面我们创建的仓库目录结构是:
简单的仓库目录结构使用分支后,行业中比较推荐的目录结构是:
推荐的目录结构之前我们直接在iOS
文件夹里放我们的项目文件,但是使用分支后,建议改为在iOS
文件夹里放两个文件夹:trunk
文件夹和branches
文件夹,trunk
相当于主分支,branches
文件夹里存放的是你的其他分支。
合并分支
前面我们通过svn copy
的方式在仓库里创建了分支,而且在在本地检出了分支的工作副本。在分支工作副本上工作时,建议经常将分支工作副本和仓库主分支合并一下,因为其他人可能已经更改了主分支,你需要通过合并来及时解决冲突,保证你的分支和主分支的同步。
我们使用svn merge
指令来合并分支:
svn merge [仓库分支路径] [工作副本分支路径]
注意svn merge
指令只能将仓库中的分支合并到工作副本的分支,而不能反过来将工作副本的分支合并到仓库中的分支。具体指令是:
svn merge file:///users/xiaoming/repos/ios/trunk /users/xiaoming/ios-dev
如果合并出现冲突,就需要先解决冲突。解决冲突有很多方式。假设我们使用手动解决冲突的方式,在出现冲突的文件中手动修改了出现冲突的地方。然后需要:
svn resolve –accept working [出现冲突的文件的路径]
取消冲突错误提示,然后才能:
svn commit -m 'fix conflict'
提交版本。
现在我们知道怎么合并分支了。那么当分支的内容完成后,要将分支内容合并到主分支应该怎么做呢?
前面我们知道,合并操作只能从仓库上的分支合并到工作副本的分支。所以我们先要检出主分支的工作副本,然后再和分支进行合并,具体操作这里就不再赘述了。
远程仓库
上面演示的都是本地仓库,那么怎样创建一个仓库,让其他人可以通过网络来访问呢?
如果你已经通过上面的方法创建了一个本地仓库,那你只需要使用svnserve
就能让你的仓库能够远程访问:
svnserve -d -r [服务器目录] --listen-port [服务端口号]
其中[服务端口号]
可以缺省,svn默认监听端口3690
。这里重点要说的是[服务器目录]
。前面我们说过,如果你有多个项目需要使用svn进行版本管理,你可以创建一个仓库来存放所有项目,也可以创建多个仓库,一个仓库放一个项目。对于第一种情况,[服务器目录]
就是你的仓库目录。对于第二种情况,建议把所有仓库放到同一个文件夹里,然后这个文件夹就是[服务器目录]
。
上面我们使用的是一个仓库存放所有项目的情况,所以为该仓库开启远程服务的指令是:
svnserve -d -r /users/xiaoming/repos
这样我们的仓库就支持远程访问了。使用svnserve
开启服务后,访问仓库的协议是svn://
,所以访问仓库的路径是(在本地访问本地的远程仓库)svn://localhost/ios
。假设你的电脑的IP是192.168.1.6
,那么另一台电脑访问你电脑的远程仓库的地址是svn://192.168.1.6/ios
。
参考文档
svn功能非常强大,前面只是粗略地介绍一些基本知识和用法。需要深入了解svn的,可以去看一下《svn官方手册》,是中文的。
网友评论