本文来自慕课网 SVN从入门到放弃
1. 课程介绍
1. 版本控制简介
版本控制是一种软件工程技巧,确保不同人所编辑的同一代码文件都得到同步。
2. 版本控制工具简单比较
特性 | CVS | SVN | GIT |
---|---|---|---|
并发修改 | 支持 | 支持 | 支持 |
并发提交 | 不支持 | 支持 | 支持 |
历史轨迹 | 不支持更名 | 支持 | 支持 |
分布式 | 不支持 | 不支持 | 支持 |
- CVS由RCS发展而来。RCS不支持并发修改。假如用户A操作文件a,文件a锁定,用户B无法操作,用户A操作完成提交后,用户B才能操作。CVS在此基础上做了优化,做到了支持并发修改操作。
- 并发提交:CVS是每个都依次提交,每个文件都记录对应的版本号。占用磁盘空间,但便于定位bug;SVN和GIT支持并发提交,多个文件一起提交,会被标记为一个版本号。节省磁盘,但搜索bug需要挨个文件检查,比较费时。
- 历史轨迹:假如一个文件名修改,CVS无法追踪到修改文件名之前的历史版本;SVN和GIT可以追踪到所有历史版本
- 分布式:是否需要一台专门的服务器运行版本控制系统。CVS和SVN属于集中式版本控制系统,需要专门的服务器来运行版本控制系统;GIT属分布式,不需要专门服务器去运行,每个开发人员各自的电脑组成的网络就可以运行GIT,特别适合源代码的发布和交流。很多开源项目都使用GIT,比如GitHub、Gitlab。
- 根据应用场景选择不同的版本控制工具。一些超大型项目往往会在GIT的基础上再加一层SVN来实现更复杂的版本控制需求。
2. SVN服务端及客户端环境搭建
1. SVN的安装(Linux)
安装前更新yum源。
Ubuntu:
apt-get install subversion
CentOS:
yum install subversion
Subversion 软件包内已包含服务端和客户端两个部分。
2. 服务端命令与客户端命令
1. 服务端命令
svnserve
:控制SVN系统服务的启动等svnadmmin
:版本库的创建/导出/导入/删除等svnlook
:查看版本库的信息等
2. 客户端命令
- svn:版本库的检出/更新/提交/重定向等
3. 版本库的创建与删除
创建版本库:
svnadmin create /path/repos
- 绝对路径和相对路径都可以
svnadmin create --fsfs-type xxxx
- 数据保存类型:
fsfs
和dbd
两种,推荐fsfs
。
删除版本库:
rm -rvf /path/repos
4. 版本库配置及权限分组
1. 配置文件
配置文件位于 /path/repos/conf
authz
:配置用户组以及用户组权限passwd
:配置用户名和密码svnserver.conf
:配置默认权限、权限配置文件及密码配置文件
2. SVN的更新和提交
- 更新
update
:从服务器把代码下载到本地 - 提交
commit
:把本地代码提交到svn服务器,然后写入版本库(两个操作)
3. 配置文件介绍
vi svnserver.conf
[general]
# anon-access = read 指未验证(没有用户名密码)的用户访问该版本库时拥有的权限
# auth-access = write 指已验证(有用户名和密码)的用户方法该版本库时拥有的权限
- 权限选项有三个:
none
(什么都没有)、read
(允许更新代码)、write
(允许提交代码)。配置时需要把该两行的注释去掉(去掉前边的#
号),才可以生效
以下两个配置文件可以放到别的目录下,也可以改名,只要路径配置正确即可。这两个文件必须具备可读写权限。
# password-db = passwd 指定用户的用户名密码配置的文件路径,支持绝对/相对路径
# authz-db = authz 指定权限分组配置的文件路径,支持绝对/相对路径
vi passwd
[users]
isvn = 123456
用户名 = 密码
。指创建一个用户名为isvn
密码为123456
的用户
vi authz
[aliases] 配置别名,忽略
[group] 用户组配置
pm = isvn
dev = isvn2,isvn3
rookie = isvn4
- 组名 = 用户名列表,比如
group1 = user1,user2,user3
[ / ] 版本库根目录,该权限适用于所有指向该配置文件的版本库
@pm = rw
@dev = r
@rookie = r
[isvn:/] 版本库名:/
:指只适用于版本库名为isvn
版本库的权限
@pm = rw
isvn2 = rw
isvn3 = r
isvn4 = # 什么权限都没有
- @pm = rw 组权限,组名前加
@
,r --更新;w --提交 - isvn2 = rw 用户权限,用户名 = 权限,空则没有任何权限
[repo:/xxx] 指定某个版本库下某个路径的权限(更详细的设置权限)
* = r
5. 版本库的访问
- svn属于集中式版本控制系统,一台svn服务器服务于多台svn客户端
- svn是跨平台的,其服务端和客户端可以搭建在Windows、Linux、macOS等任意操作系统的机器上,相互不受影响
1. 访问SVN版本库方式
- 命令行方式访问
- 图形可视化操作
2. 开启SVN服务
svnserve -d -r /path
3. 访问SVN版本库
客户端:
1. 检出版本库
检出版本库作用:在本地创建一个工作副本
1. 命令行方式检出版本库:
创建文件夹(svntest)用于存放工作副本
mkdir svntest
cd svntest
检出版本库:
svn checkout svn://ip --username 版本库名 --password 密码 # 缩写: svn checkout --> svn co
或者
svn checkout svn://ip # 后续会提示输入操作系统密码、版本库密码
# ip后正常是ip:port,如果端口不写,则端口默认3690
会出现
取出版本 0。
ll
查看一下会有一个.svn
的文件夹。
2. 图形可视化工具检出版本库:
操作工具:TortoiseSVN
下载地址:https://tortoisesvn.net/ 进行安装客户端
Windows桌面创建文件夹 svntest
选中该文件夹后鼠标右击选择“检出svn”
填写版本库url、版本库路径、检出目录
- 注意:前面的协议名称是
svn
点击确定后输入svn用户名、密码,之后就会自动检出
完成后文件夹上有个绿色的对号就完成了,可进入查看
- 如果显示为空,就打开“取消隐藏文件”
小结:
- Windows系统,建议使用小乌龟软件(TortoiseSVN)
- Linux系统,建议使用命令行方式访问
6. SVN服务自启动
服务自启动:开启自动启动
Linux有具体的文件,根据 系统启动级别 分别对指定软件进行启动
Ubuntu自启动脚本文件:/etc/rc.local
- 该文件保存了所有的自启动服务
在exit 0
之前添加svn启动的命令:
svnserve -d -r /path
保存退出即可。
也可以单独创建自启动脚本文件。
3. SVN基本操作
1. SVN常见术语及文件状态
常见的,并不是所有的
1. 常见术语
版本库:svn版本库
检出:checkout操作,把svn版本库文件下载到本地
工作副本:checkout下载下来的文件夹,称为工作副本
更新:更新update
操作,把svn版本库数据同步到本地,直接更新会更新到最新版本,也可以通过命令行方式更新到指定版本
提交:提交commit
操作
版本:svn版本库的版本
版本号:svn文件的版本号码,从0开始。客户端进行commit
提交操作,版本号会+1
。
2. 文件状态
无版本控制:新增代码文件或修改文件代码等操作后的状态
增加:对文件进行版本控制,进行增加操作后的状态
修改:modify
,把更新update
下来的代码做修改操作后的状态
常规:checkout的版本库文件,未操作过的状态;或commit之后与svn库版本一致的状态
冲突:本地工作副本和svn版本库的版本不一致,本地修改后做提交操作引发冲突
删除:missing
,本地删除文件或目录
锁定
建议:
- 养成经常更新的好习惯,让工作副本和版本库尽可能的保持一致
- 在开发中最大程度的避免数据冲突
2. checkout 和 export 区别
checkout:检出
- checkout 检出的工作副本目录中含
.svn
文件夹 - 版本控制中有一种文件状态:无版本控制
svn checkout -r 2 # 检出版本2
- 如果单纯 svn checkout 会检出最新版本
export:导出
- 导出项目不存在
.svn
文件夹
svn export -r 3 # 导出版本3
小结:
-
checkout检出的工作副本是在版本控制之内;
-
export导出的项目文件不在版本控制之内
-
checkout --> .svn + 项目文件
-
export --> 项目文件
-
export导出的文件不能称之为工作副本
checkout与export的区别和使用
- .svn 记录着工作副本最后一次更新后的文件状态
- .svn 标记工作副本的一切变化
3. add、ci、up、del
注意: 使用svn命令时要注意自己使用的是服务端命令还是客户端命令。
常见SVN客户端命令
命令 | 说明 |
---|---|
svn add | 把无版本控制的文件添加到版本控制 |
svn commit | 提交修改到服务器,创建一个新版本号 |
svn update | 更新工作副本。特性:默认情况下,每个文件只会从服务端更新一次最新版本 |
svn delete | 从版本库中删除文件或目录 |
**demo:**本地新建了一个 index.html、css文件夹(内部包含a.css和b.css)、js文件夹(内部包含a.js和b.js)
add
用户1
-
把 index.html 添加到版本库:
# 语法: svn add 文件名 svn add index.html
-
把 css 文件夹添加到版本库:
svn add css
- 该操作会把css整个文件夹(包括a.css和b.css)递归添加到版本库
-
把当前目录下所有无版本控制的文件和目录都增加到版本控制里
svn add * --force
--force
参数会强制扫描所有已添加和未添加文件和文件夹下的所有文件,属无版本控制的进行增加操作;- 如果没有
force
参数,就不会把css下的a.css和b.css增加到版本控制里,因为css文件夹已添加,它就不会再去扫描该文件夹内的文件
-
把js空文件夹添加到版本库:
# 语法: svn add 文件名 --non-recursive svn add js --non-recursive
commit
-
提交文件到svn版本库:
# 语法:svn commit -m "注释说明" 文件名 svn commit -m "添加index.html文件" index.html
- commit 可缩写为 ci,注释说明可省略,但双引号要有不能省略
用户2
update
-
更新文件到本地
svn update
- update 缩写 up
4. add、ci、up、del - up
-
查看某个版本的某个文件。
# 语法: svn up -r 版本号 文件名 svn up -r 1 index.html
- 如果index.html当前版本是2,使用一次svn up -r 1 index.html后,再执行
2
不会继续更新至2
。
- 如果index.html当前版本是2,使用一次svn up -r 1 index.html后,再执行
-
强制把所有文件更新至最新版本
svn up *
- svn up 默认只更新一次
del
-
删除 index.html
# 语法: rm 文件名 rm index.html
-
再执行 svn up 会把 index.html 恢复,因为 Linux删除和 svn删除是两回事
svn up :
-
默认情况下只更新一次。如果当前最新版本是
2
,执行一次更新1
后再更新不会更新到版本2
。 -
当工作副本缺失某个文件时,使用该命令后,服务端还是会把缺失文件的最新版本更新到本地。
-
如果一个文件被更新至某个版本,之后想更新到最新版本,可以先
rm
本地文件,然后执行该命令更新至最新版本。 -
删除版本库中的文件
svn delete 文件名 -m "注释说明" svn remove 文件名 - m "注释说明"
- delete 缩写
del
;remove 缩写rm
- 删除命令后的
-m "注释说明"
可省略
- delete 缩写
-
删除后记得提交
svn ci -m ""
5. diff、mkdir、cat_1
常见客户端命令
命令 | 说明 |
---|---|
svn diff | 版本差异比较 |
svn mkdir | 创建目录并增加到版本控制 |
svn cat | 不检出工作副本直接查看指定文件 |
diff
比较两个文件的不同
-
比较当前版本和工作副本的差异
- 语法:
svn diff 文件名
(diff 缩写 di)
# 比较index.html文件当前版本和工作副本的差异 svn di index.html # 返回内容如下: Index: index.html --- index.html (revision 3) # 前边减号指最后一次更新得到的版本3的内容 +++ index.html (working copy) # 前边加号指工作副本中被修改的内容,working copy: 工作副本 @@ -0,0 +1,12 @@ # 0,0表示原文件;1,12表示文件存在差异的行号,存在差异的是第1到第12行 # 再下边的内容是该文件存在差异的内容
- 行头
-
号表示修改前的内容;行头+
号表示修改后的内容,即工作副本的内容;行头无符号表示该行无变化 - 提交该文件时,svn会把
-
号行删掉,把+
号行添加
- 语法:
-
指定版本和工作副本的比较
# 比较index.html文件版本2和工作副本差异 svn di -r 2 index.html
-
比较一个文件任意两个版本的差异
# 比较index.html文件版本1和版本3的差异 svn di -r 1:3 index.html
-
比较批量文件所有版本的差异
svn di
- 该命令会比较当前目录下所有文件的所有版本的差异(不推荐)
mkdir
-
创建doc文件夹并添加到svn版本库中
# 语法:svn mkdir 目录名 svn mkdir doc
cat
可脱离工作副本的目录执行(就是不在svn目录下执行)
-
查看index.html文件内容
# 语法:svn cat svn://ip/文件名 svn cat svn://192.168.0.130/index.html
6. 工作副本还原 revert
称为:SVN版 Ctrl + z
,即还原工作副本至最后一次更新得到的版本文件。
语法:svn revert [--recursive] [filename|*]
-
恢复 index.html 为最后一次更新得到的版本文件
svn revert index.html
-
恢复当前目录下的所有文件(当前目录下有文件夹的话不会递归扫描文件夹下的文件)
svn revert *
-
恢复当前目录下的所有文件、文件夹及其文件
svn revert --recursive *
7. 二进制冲突与树冲突
1. 什么是冲突以及冲突的产生条件
什么时候产生冲突: 冲突常出现于工作副本长时间未更新时
冲突产生的原因: 更新到的数据与工作副本的修改正好在同一地方
1. 二进制冲突
2. 树冲突
-
发生树冲突的文件都不是二进制文本文件
-
树冲突无法精确到行,并且处理树冲突必须处理整个文件
2. 如何尽可能的避免冲突
养成经常更新的好习惯,让工作副本和版本库尽可能的保持一致。
3. 如何解决冲突
情景: 假设用户A和用户B都update了最新的代码,用户A和用户B都修改了index.html的第5行,之后用户A先commit,svn版本从0更新到1,用户B在版本0的前提下commit,会报该文件is out of date
,从而引发了冲突。
使用svn up
查看冲突情况:
会有Select
选项:
Select
(p) postpone, (df) show diff, (e) edit file, (m) merge
(mc) my side of conflict, (tc) their side of conflict,
(s) show all options:
-
(mc): 保留我自己的版本
-
(tc): 保留别人的版本
-
( p): 推迟提交(推荐)
选择该选项,会提示冲突文件,svn会把冲突信息发送给与自己发生冲突的用户,不会影响线上,冲突只会存在于冲突用户的工作副本中 -
(e): 编辑文件
修改完按 ctrl + x 退出 -
(df): 比较差异
<<<<<<<<.mine 自己的代码 ======== 发生冲突的代码,即别人提交的代码 >>>>>>>> .r5
使用命令的方式修改冲突文件
# 语法: svn resolve 文件名
svn resolve index.html
- 会弹出选项信息
注意: 冲突处理完需要告诉服务端冲突已解决,否则服务端会一直记录该冲突。
# 语法: svn resolved 文件名
svn resolved index.html
- 使用直接编辑冲突文件的方式处理冲突,处理完必须要执行该步骤
- 使用命令的方式(resolve)处理冲突,处理完不需要再执行该步骤
8. 锁定lock与解锁unlock
svn lock 文件名
: 锁定文件,防止其他成员对文件进行提交
svn unlock 文件名
: 解锁文件
优点:用户锁定一个文件并对其编辑,编辑完后再解锁,可有效防止冲突;
缺点:如果多个用户同时操作同一文件的不同行,有一个用户对该文件进行锁定会影响其他用户的开发,导致团队开发效率降低。
demo:
- user1锁定index.html
svn lock index.html
# 返回信息:
'index.html' locked by user 'user1'
- user2编辑index.html,这个是没问题的,保存后提交
svn ci -m "" index.html
# 返回信息:
失败,User user2 does not own lock on path '/index.html' (currently locked by user1)
- user1解锁index.html文件
svn unlock index.html
# 返回信息:
'index.html' unlocked.
- user2提交index.html文件
svn ci -m "" index.html
# 返回成功
注意:
- 如果用户锁定文件后进行编辑,编辑完进行commit,文件会自动解锁,不用再执行
svn unlock
命令。 - 如果用户锁定文件,提交后不想该文件自动解锁,则提交命令改为:
svn ci -m "" --no-unlock index.html
4. SVN进阶应用
1. ls、st、log、info
命令 | 说明 |
---|---|
svn list (缩写 svn ls) | 列出当前目录下处于版本控制的所有文件(夹) |
svn status (缩写 svn st) | 列出工作副本中的文件(夹)的状态 |
svn log | 查看提交日志(来自 svn ci 的 -m 参数) |
svn info | 工作副本及文件(夹)的详细信息 |
svn list
# 准备工作: .svn同目录下创建 test.html
svn ls
# 可以查看到除test.html之外的工作副本的文件(夹),文件夹内部文件不显示
svn ls --recursive
# 可以看到包含test.html在内的所有本目录下的文件、文件夹及其内部所有文件
svn ls -v 或 svn ls -v --recursive
# 查询当前目录所有文件的详细信息,类似于Linux的`ll`命令
svn status
以下状态不是所有的
状态 | 说明 |
---|---|
? | 无版本控制,未加到版本控制中 |
D | 已被标记从版本库中删除 |
M | 已被编辑过 |
A | 已被标记增加到版本控制中 |
R | 文件被替换(指文件用svn rm删除后,又创建了同名字的文件添加到版本库中) |
C | 文件存在冲突 |
! | 文件缺失(指本地删除但svn版本库未删除) |
- svn update 执行后会出现
U
标记,status里不包含
svn log
-
查看指定文件的提交日志
svn log index.html
svn info
-
查看某个指定文件(夹)的信息
svn info index.html
-
使用xml格式显示指定文件的信息
svn info index.html --xml
-
使用Linux管道保存xml格式显示出的指定文件的信息
svn info --xml >> info.xml
- 这样就在该目录下生成info.xml文件
2. 多版本库解决方案-A
多版本库:一台SVN服务器上同时运行多个版本库
解决方案:创建多个版本库,手动给每个版本库服务指定不同的端口号。
端口号用途 | 端口号 |
---|---|
TCP/IP协议规定端口号范围 | 0-65535 |
公认端口 | 0-1023 |
注册端口 | 1024-49151 |
私有端口 | 49152-65535 |
svn默认端口号:3690
-
修改svn端口号:
svnserve -d -r /路径 --listen-port 端口号
-
停止所有svn版本库服务
killall svnserve
3. 多版本库解决方案-B
解决方案:多个版本库创建在同一目录下,启动svn服务,路径是svn版本库的上一级目录,就可以只使用一个端口号运行多个版本库。
-
检出某个版本库
svn co svn://ip/路径/版本库名
- port不用写,默认3690
4. 多版本解决方案-总结
方式 | 优点 | 缺点 |
---|---|---|
多个端口号 | 版本库可以创建在任意位置 | 端口号容易混淆 |
一个端口号 | 版本库必须创建在同一目录下 | 无需分配端口号 |
5. copy
部分功能:关联工作副本和操作线上svn服务
功能:
- 工作副本 → 工作副本
- 工作副本 → 版本库(不可跨库)
- 版本库 → 工作副本(允许跨库)
- 版本库 → 版本库(不可跨库)
注意:提交无法跨库
1. 工作副本 → 工作副本
-
复制工作副本中的index.html到工作副本
# 语法:svn copy 原文件名 目标文件名 # copy 缩写: cp svn cp index.html copy.html A copy.html
- 如果使用Linux原生复制命令,复制得到的文件是无版本控制状态,需使用
svn add
添加到版本控制状态
- 如果使用Linux原生复制命令,复制得到的文件是无版本控制状态,需使用
-
复制工作副本中的index.html的指定版本到工作副本
# 语法:svn cp -r 版本号 原文件名 目标文件名 svn cp -r 4 index.html
-
复制批量文件到指定文件夹
# 创建目标文件夹 svn mkdir temp # 复制文件到temp文件夹 # 语法:svn cp 文件1 文件2 ... 目标文件夹路径 svn cp index.html about.html ./temp
- 多个文件名之间用空格隔开
2. 工作副本 → 版本库
-
复制工作副本中的index.html到版本库
# 语法:svn cp 原文件名 svn://ip/路径/目标文件名 -m "提交备注" svn cp index.html svn://192.160.0.130/imooc/target.html -m "copy a file"
- 不通过工作副本直接提交到版本库,之后需要进行
svn update
进行更新 - 上边的命令也可以通过
-r
指定版本号
- 不通过工作副本直接提交到版本库,之后需要进行
注意:从工作副本复制到版本库不支持跨库操作。即检出的工作副本只能复制到被检出的版本库中
3. 版本库 → 工作副本
-
从线上版本库中复制index.html文件到工作副本,取名为demo.html
# 语法:svn cp svn://ip/路径/原文件名 目标文件名 svn cp svn://192.168.0.130/imooc/index.html demo.html
注意: 从线上版本库复制到本地工作副本支持跨库操作。
-
比如:从线上a版本库复制文件到本地b工作副本中
svn cp svn://192.168.0.130/hello/index.html demo2.html
4. 版本库 → 版本库
- 把svn版本库根目录下的文件复制到版本库某个文件夹下
# 语法:svn cp svn://ip/原文件路径 svn://ip/目标路径(跟原文件同库,因为不允许跨库) -m "提交备注"
svn cp svn://192.168.0.130/imooc/ svn://192.168.0.130/imooc/trunk -m "set a trunk"
6. 主干版本与分支版本
创建分支版本库的过程是脱离工作副本的,跟工作副本无关。
创建分支版本,通常会在版本库中增加一层目录,用来区分主干版本和分支版本。
- 创建分支版本
# 把svn版本库根目录下的文件复制到文件夹
# 语法:svn cp svn://ip/原文件路径 目标路径(跟原文件同库,因为不允许跨库) -m "提交备注"
svn cp svn://192.168.0.130/imooc/ svn://192.168.0.130/imooc/trunk -m "set a trunk"
# 进入imooc中执行update更新工作副本
cd imooc/
svn up
# 可看到工作副本目录里增加了trunk目录,里边是原imooc中所有文件
# 创建branch分支版本
# 语法:svn cp svn://ip/主干版本文件路径 svn://ip/分支版本文件路径 -m "提交备注"
svn cp svn://192.168.0.130/imooc/trunk svn://192.168.0.130/imooc/branch -m "create a branch"
# 然后更新
svn up
注意:
一般在创建项目后,还未开始开发时就会创建出主干版本(trunk)、分支版本(branch)和版本备份(tag,用来对每个主干版本发布后的项目文件备份),这样互不干扰。
5. SVN高级应用
svn高级应用属管理员级别操作,需要暂停 SVN 服务。
1. hooks
钩子:当执行某些特定操作时触发执行预先设定好的任务。
例如:论坛用户进行登录、发帖、回帖等操作,会送金币。这些操作好比 特定操作,送金币好比 设定好的任务,特定操作像钩子一样钩住设定好的任务。
svn根目录下有hooks
文件夹,内部有很多以.tmpl
格式(template)的文件,本质是shell脚本。这些是钩子的模板文件,使这些钩子文件生效,只需复制一份,把.tmpl
后缀去掉就可以启用。
hooks目录下的.tmpl
文件:(三个时间点)
-
以
start
开头的文件:数据传输开始之前执行 -
以
pre
开头的文件:数据传输之后,写入版本库之前执行 -
以
post
开头的文件:写入版本库之后执行 -
文件名后半部分是执行的操作
commit
:提交lock
:锁定unlock
:解锁revprop-change
:版本属性变化
-
执行post-commit.tmpl文件:
# 复制该文件 cp -a post-commit.tmpl post-commit # 给post-commit文件增加可执行权限 chmod +x post-commit # 查看文件状态 ll # 可看到绿色的 post-commit* 表示已经有了可执行的权限
-
demo:编辑post-commit文件,每一次commit操作使svn版本更新后,把最新版本信息写入指定xml文件内,保存到某个服务器上,可以让用户使用浏览器访问查看
# 编辑post-commit文件
vi post-commit
# 该文件最后有三行非注释信息,删掉,自己编写
# 语法: svn info svn://ip/路径 --xml >> 目标路径
svn info svn://192.168.0.130/imooc --xml >> /var/www/repo.xml
# 保存退出
wq!
# 关闭svn服务
killall svnserve
# 启动svn服务
svnserve -d -r /svnroot/
# 修改某个文件(index.html)进行commit提交,然后使用浏览器访问
# 即可显示新生成的repo.xml
钩子应用例子:把svn架设到GitHub之上,使项目的版本控制更加智能化。
2. 版本库精简与丢弃
demo:假设某项目从r1版本更新迭代到了r100,现在想丢弃r1-r20版本,保留r21-r100版本
# 停止svn服务
killall svnserve
# 备份保留版本库
svnadmin dump 版本库文件系统路径 -r 起始版本号:终止版本号 > 保存目录
svnadmin dump /svnroot/imooc/ -r 21:100 > ~/imooc
- ~/imooc:`~` 指返回到home目录
# 创建空版本库用于存储备份的数据
svnadmin create /svnroot/newimooc
# 把刚才备份的数据加载到空版本库
svnadmin load svnroot/newimooc/ < ~/imooc.repo
# 通过加载运行的信息可得:原来的r21变成了现在的r1,原来的r100变成了现在的r80
# 把imooc版本库的配置文件也复制到新版本库中
cp -av /svnroot/imooc/conf/* /svnroot/newimooc/conf/
# 把旧imooc版本库删除
rm -rvf /svnroot/imooc
# 把SVN服务运行起来
svnserve -d -r /svnroot/
注意:
版本库精简后,当前的工作副本版本与版本库版本不匹配,需要删掉本地工作副本,重新checkout检出一份。
3. 版本库迁移与switch重定向
1. 版本库迁移
方法1:
版本库迁移本质上跟版本库精简一样,版本库精简操作,使用svnadmin dump
来备份版本库数据时,选定版本号范围从r1到最新版本,就等于把整个版本库完整的备份出来了,然后把生成的备份文件复制到新的服务器上,使用svnadmin load
加载到新版本库里。
方法2:
- killall svnserve
- 把 /svnroot/repo/ 压缩成 repo.zip
- 复制 repo.zip 到新服务器并解压
- 在新服务器上运行 repo 版本库
方法1和方法2区别:
- 版本库相当于鸟窝,版本库的外壳相当于树
- 方法1是把鸟窝从树a挪到了树b;方法2是把鸟跟树一块挪到了别的位置
2. 版本库switch重定向
命令:svn switch --relocate 旧url 新url
- switch 缩写 sw
重定向:工作副本会记录svn服务端的url,svn版本库迁移后,svn版本库的url发生改变,工作副本中的url就失效了,需要更新定位到新的url上
demo:压缩world
版本库,并解压到另外一个位置
# 停止svn访问
killall svnserve
# 切换到svn版本库目录
cd /svnroot/
# 复制world版本库(假设newworld是从别的服务器复制过来,然后解压得到的版本库)
mv world newworld
# 运行svn服务
svnserve -d -r /svnroot/
# 进入world使用svn up更新会报错
# 进行url的重定向
svn sw --relocate svn://192.168.0.130/world svn://192.168.0.130/newworld
# 此时再更新svn就可以了
svn up
6. 课程总结 - 常见坑与总结
1. 创建完版本库忘记配置svnserve.conf
导致:版本库可以运行,但无法登录、无法检出版本库,报:认证失败
2. 运行版本库的路径问题
检出版本库时要有目录名称,运行和检出互斥,目录名称在运行时写则检出时就不要写;检出时写了则运行时就不要写,否则报版本库不存在。
3. svnadmin dump/load 管道符号问题
备份dump: 大于号 >
加载load: 小于号 <
7. 学习总结
安装svn
系统 | 安装方式 |
---|---|
Ubuntu | apt-get install subversion |
CentOS | yum install subversion |
windows | 可视化软件:TortoiseSVN |
客户端命令
-
检出svn版本库,在本地创建一个工作副本
svn checkout svn://ip:port/path --username 版本库名 --password 密码
- checkout 缩写 co
- port 默认 3690
-
无版本控制的文件添加到版本控制
svn add 文件名
- 文件名是 * 则表示当前目录下的所有文件
- 参数:
--force
: 强制扫描已添加和未添加文件与文件夹夹下的所有文件,没有该参数不会递归操作所有文件夹--non-recursive
: 添加空文件夹到版本控制中
-
提交文件到版本库
svn commit -m "提交说明" 文件名
- commit 缩写 ci
- 文件名是
*
号表示提交当前目录下所有文件
-
更新工作副本
svn update
- update 缩写 up
- svn up * 默认只更新一次
- 参数:
-r 版本号
: 指定版本号
-
从版本库中删除文件或目录 (删除后记得提交)
svn delete 或 svn remove
- delete 缩写 del; remove 缩写 rm
-
比较版本差异
svn diff 文件名
- diff 缩写 di
- 参数:
-r 版本号
: 指定版本号-r 版本号1:版本号2
: 比较任意两个版本的差异
+
号开头:修改过的内容;-
号开头表示未修改- svn di 表示比较批量文件所有版本的差异(不推荐)
-
创建文件夹并添加到版本库中
svn mkdir 目录名
-
不检出工作副本直接查看指定文件 (可脱离工作副本执行)
svn cat svn://ip:port/文件名路径
-
工作副本还原,还原至最后一次更新得到的版本文件
svn revert 文件名
- 参数:
svn revert *
:恢复当前目录下所有的文件,当前目录有文件夹的话不会递归扫描文件夹下的文件--recursive
:恢复当前目录下所有文件与文件夹及其内部文件
- 参数:
-
使用命令的方式修改冲突文件
svn resolve 文件名
- 会弹出选项信息
- (mc): 保留我自己的版本
- (tc): 保留别人的版本
- ( p): 推迟提交(推荐)选择该选项,会提示冲突文件,svn会把冲突信息发送给与自己发生冲突的用户,不会影响线上,冲突只会存在于冲突用户的工作副本中
- (e): 编辑文件
修改完按 ctrl + x 退出 - (df): 比较差异
- 会弹出选项信息
-
冲突解决后告知服务端冲突已解决,否则服务端会一直记录该冲突
svn resolved 文件名
- 直接编辑冲突文件的话,处理完须执行该步骤
- 命令的方式(resolve)处理冲突,处理完不需要再执行该步骤
-
锁定文件,防止其他成员对文件进行提交
svn lock 文件名
- 优点:有效防止冲突
- 缺点:如果多个用户同时操作同一文件的不同行,有一个用户对其锁定,会影响团队开发效率
-
解锁文件
svn unlock 文件名
-
若用户锁定文件后编辑再commit,文件自动解锁,无需再执行解锁
-
若用户锁定文件,提交后不想该文件自动解锁,执行:
svn ci -m "" --no-unlock 文件名
-
-
列出当前目录下处于版本控制的所有文件(夹)
svn list
- list 缩写 ls
- 参数:
recursive
: 查看当前目录下所有文件和文件夹及内部所有文件,没有该参数,文件夹内文件不显示-v
: 查询当前目录所有文件的详细信息,类似于Linux中ll
命令
-
列出工作副本中的文件(夹)的状态
svn status
- status 缩写 st
- 状态:
?
: 无版本控制,未加到版本控制中D
: 已被标记从版本库中删除M
: 已被编辑过A
: 已被标记增加到版本控制中R
: 文件被替换(指文件用svn rm删除后创建了同名的文件并添加到版本控制中)C
: 文件存在冲突!
: 文件缺失(指本地删除但svn版本库中未删除)
svn update
执行后会出现U
标记,status里不包含
-
查看提交日志
svn log 文件名
-
查看工作副本及文件(夹)的详细信息
svn info 文件名
- 参数:
--xml
: 使用xml格式显示指定文件的信息
- 使用Linux管道保存xml格式显示出的指定文件的信息
svn info --xml >> info.xml
- 会在该目录下生成info.xml
- 参数:
-
copy复制功能(copy缩写cp)
-
工作副本 → 工作副本
svn cp 原文件名 新文件名
- 参数:
-r 版本号
指定版本
svn cp -r 版本号 原文件名 新文件名
- 复制批量文件到指定文件夹
# 创建文件夹 svn mkdir 指定文件夹 # 批量复制 svn cp file1 file2 ... 指定文件夹 ```
- 参数:
-
工作副本 → 版本库(不可跨库)
svn cp 原文件名 svn://ip:port/path/新文件名 -m "复制注释"
- 参数:
-r 版本号
指定版本
- 参数:
-
版本库 → 工作副本(可跨库)
svn cp svn://ip:port/path/旧文件名 新文件名
-
版本库 → 版本库(不可跨库)
svn cp svn://ip:port/原文件路径 svn://ip:port/新文件路径 -m "复制注释"
-
-
创建分支版本(创建项目后就创建主干版本、分支版本、版本备份)
# 把svn版本库根目录下的文件复制到文件夹 svn cp svn://ip:port/path svn://ip:port/path/arm_path -m "注释" # 进入arm_path中执行update更新工作副本 cd arm_path svn up # 创建分支版本branch svn cp svn://ip:port/path/arm_path svn://ip:port/path/branch -m "创建分支注释" # 最后更新 svn up
服务端命令
-
创建svn版本库
svnadmin create /path/repos
- 参数:
--fsfs-type
: 数据保存类型:fsfs和dbd,推荐fsfs
- 参数:
-
开启svn服务
svnserve -d -r /path
-
停止所有svn服务
killall svnserve
-
删除版本库
rm -rvf /path/repos
-
修改svn端口号
svnserve -d -r /path --listen-port 端口号
-
执行hooks钩子文件 (以post-commit.tmpl为例)
# 复制文件 cp -a post-commit.tmpl post-commit # 给post-commit文件增加可执行权限 chmod +x post-commit - hooks钩子文件自定义例子:每次commit操作后,把最新版本信息写入指定xml文件内,保存到某个服务器上,用户可通过浏览器访问查看 # 编辑post-commit文件 vi post-commit # 该文件最后三行非注释信息删掉,然后写入 svn info svn://ip:port/path --xml >> /目标路径/demo.xml # 保存退出 wq! # 关闭svn服务 killall svnserve # 启动svn服务 svnserve -d -r /path
知识点
svn配置信息
- svn配置信息位于
/path/repos/conf
- svn配置权限:
none
-无权限(为空);read
-允许更新代码;write
-允许提交代码 - svn配置信息:
- svnserver.conf:配置默认权限、权限配置文件及密码配置文件
- [general] : anon-access 未验证用户权限;auth-access 已验证用户权限;passwd-db 用户名密码配置文件路径;authz-db 权限分组配置文件路径
- passwd: 配置用户名密码
- [users] 用户名密码:username = password 用户名 = 密码
- authz: 配置用户组以及用户组权限
- [aliases] : 配置别名,可忽略
- [group] 用户组权限:group = username 组名 = 用户名1,用户名2,…
- [/] 版本库根目录:该权限适用于所有指向该配置文件的版本库,指定用户组权限时,组名前加@
- [版本库名:/] 指定特定版本库的权限,指定用户组权限时,组名前加@
- [repo:/xxx] 指定某个版本库下某个路径权限, * = r
- svnserver.conf:配置默认权限、权限配置文件及密码配置文件
配置svn自启动
/etc/rc.local 在 exit 0 之前添加下行代码
svnserve -d -r /path
checkout 和 export:
- 使用:
- 检出某个版本:svn checkout -r 2
- 导出某个版本:svn export -r 2
- 区别:
- checkout 检出的工作副本在版本控制范围内,有 .svn 文件夹
- export 导出的项目文件不在版本控制范围内,没有 .svn 文件夹
版本冲突
- 什么时候产生冲突:常出现于工作副本长时间未更新时
- 产生冲突原因:更新到的数据与工作副本的修改正好在同一地方
- 冲突分类:二进制冲突、树冲突
- 如何解决冲突:
- 方式1:
svn up
列出Select
选项,根据提示修改- 修改后执行
svn resolved 文件名
告诉svn服务器冲突已处理
- 修改后执行
- 方式2:使用命令的方式修改:
svn resolve 文件名
- 方式1:
多版本库解决方案
方案A:
一台SVN服务器上同时运行多个版本库,创建多个版本库,手动给每个版本库指定不同的端口号。
svnserve -d -r /path --listen-port 端口号 # 默认3690
说明:版本库可创建在任意位置;端口号容易混淆
方案B:
多个版本库创建在同一目录下,启动SVN服务,路径是SVN版本库的上一级目录,可只使用一个端口号运行多个版本库。
svn co svn://ip:port/path/版本库名 # port不用写,默认3690
说明:版本库必须创建在同一目录下;无需分配端口号
版本库精简与丢弃
假设某项目从r1更新迭代到r100,现想丢弃r1-r20保留r21-r100版本
# 停止svn服务
killall svnserve
# 备份保留版本库
# 语法:svnadmin dump 版本库文件系统路径 -r 起始版本号:终止版本号 > 保存路径
svnadmin dump /svnroot/isvn/ -r 21:100 > ~/isvn
# 创建空版本库用于存储备份的数据
svnadmin create /svnroot/newisvn
# 把刚才备份的数据加载到空版本库中(执行后原来的r21变成了现在的r1,原来的r100变成现在的r80)
svnadmin load svnroot/newisvn < ~/isvn.repo
# 把isvn版本库的配置信息也复制到新版本库中
cp -av /svnroot/isvn/conf/* svnroot/newisvn/conf/
# 把旧isvn版本库删除
rm -rvf /svnroot/isvn
# 把svn服务运行起来
svnserve -d -r /svnroot/
# 版本库精简后,当前工作副本版本与版本库版本不匹配,需要删掉本地工作副本,重新checkout一份
版本库迁移
方法1: 使用svnadmin dump
备份数据库时版本号范围从r1指定到最新版本,然后把生成的备份文件复制到新的服务器上,使用svnadmin load
加载到新版本库中。
方法2: 停掉svn服务,把svn下的repo压缩成repo.zip,将其复制到新服务器上并解压,然后在新服务器上运行repo版本库。
版本库switch重定向(switch缩写sw)
# 停止svn服务
killall svnserve
# 切换到svn版本库目录
cd /svnroot/
# 复制x版本库
mv isvn newisvn
# 运行svn服务
svnserve -d -r /path
# 进行url的重定向
# 语法:svn switch --relocate 旧url 新url
svn sw --relocate svn://192.168.0.130/isvn svn://192.168.0.131/newisvn
# 更新svn
svn up