iOS 开发 SVN 版本控制器
更多技术交流请加群 iOS技术联盟 27512466
SVN是Subversion的简称,是一个开放源代码的版本控制系统,相较于RCS、CVS,它采用了分支管理系统,它的设计目标就是取代CVS。互联网上很多版本控制服务已从CVS迁移到Subversion。说得简单一点SVN就是用于多个人共同开发同一个项目,共用资源的目的。
- 运行方式: SVN服务器有2种运行方式:独立服务器和借助apache运行。两种方式各有利弊,用户可以自行选择。
- 数据储存: SVN存储版本数据也有2种方式:BDB(一种事务安全型表类型)和FSFS(一种不需要数据库的存储系统)。因为BDB方式在服务器中断时,有可能锁住数据,所以还是FSFS方式更安全一点。
- 点击查看详细介绍
[TOC]
在Windows环境中,我们一般使用TortoiseSVN来搭建svn环境。在Mac环境下,由于Mac自带了svn的服务器端和客户端功能,所以我们可以在不装任何第三方软件的前提下使用svn功能,不过还需做一下简单的配置。
Mac环境下搭建 SVN服务器端环境
搭建流程:
一、创建代码仓库,用来存储客户端所上传的代码
我先在/User/apple目录下新建一个svn目录,以后可以在svn目录下创建多个仓库目录
打开终端,创建一个mycode仓库,输入指令:svnadmin create /Users/apple/svn/mycode
指令执行成功后,会发现硬盘上多了个/Users/apple/svn/mycode目录,目录结构如下:
注:这地方出现路径的错误可以通过输入sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer 命令
password是你的登录密码。
二、配置svn的用户权限
主要是修改/svn/mycode/conf目录下的三个文件
1. 打开 svnserve.conf, 将下列配置项前面的#和空格都去掉
# anon-access = read
# auth-access = write
# password-db = passwd
# authz-bd = authz```
> anon-access = read代表匿名访问的时候是只读的,若改为anon-access = none代表禁止匿名访问,需要帐号密码才能访问
**2.** 打开 passwd, 在[users]下面添加账号和密码
```java[users]wenhang = 111//账号 = 密码say = 666//账号 = 密码```
**3.** 打开 authz, 配置用户组和权限我们可以将在passwd里添加的用户分配到不同的用户组里,以后的话,就可以对不同用户组设置不同的权限,没有必要对每个用户进行单独设置权限。在[groups]下面添加组名和用户名,多个用户之间用逗号 **,** 隔开
```java
[groups]topgroup=wenhang,say```
>**说明**: wenhang 和 say 都是属于 topgroup 这个组的,稍后再做权限配置
使用** [/] **代表SVN服务器中的所有资源库
```java
[/]
@topgroup = rw //某个组有读写权限```
>上面的配置说明 topgroup 这个组中的所有用户对资源库都有读写(rw)权限,组名前面要用@, 如果是用户名,不用加@, 比如wenhang 这个用户有读写权限
```java
[/]
wenhang = rw //某个用户有读写权限```
>至于其他具体的权限,可以参考 authz 文件中的其他内容
**4.** 启动 SVN 服务器
`前三步都是为第四步启动服务器做准备,接下来的第四步才是真正关键所在.`
在终端输入下列指令: svnserve -d -r /Users/apple/svn
`或者输入: svnserve -d -r /User/apple/svn/mycode`
**若没有任何提示,恭喜你启动成功了**
**5.** 关闭 SVN 服务器如果你想要关闭 SVN 服务器,最便捷的办法是打开其他里面的"活动监视器"
![Snip20161118_1.png](http://upload-images.jianshu.io/upload_images/1654839-fb414733c650e818.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
在活动监视器中`搜索svn`, 在列表中找到`进程svnserve`, 点击左上角的`强制退出进程`
![Snip20161118_7.png](http://upload-images.jianshu.io/upload_images/1654839-fa9f5573f069e38c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
>`注意: 首次配置完成,须先关闭 svn 服务器,再进行数据的上传和下载操作.`
完成以上5步,那就是成功搭建了 svn服务器环境
###使用 SVN (终端命令)
**1.** 从本地导入代码到服务器(第一次初始化导入)
- 在终端输入:
`svn import /Users/apple/Documents/workspace/wenhangtest svn://localhost/mycode/iOS/wenhangtest --username=wenhang --password=111 -m "初始化导入"`
> 详解指令: 将/Users/apple/Documents/workspace/wenhangtest中的所有内容,上传到服务器mycode仓库的iOS/wenhangtest目录下,后面双引号中的"初始化导入"是注释
**2.** 从服务器下载代码到客户端本地
- 方式一 在终端输入:
`svn checkout svn://localhost/mycode/iOS --username=wenhang --password=111 /Users/apple/Documents/code`
-----------
- 方式二
在终端中进入预先建好下载存放文档的目录文件夹
终端输入:
`svn checkout svn://localhost/mycode/iOS --username=wenhang --password=111`
>详解指令: 将服务器 mycode/iOS 仓库中的内容下载到/ User/apple/Documents/code 目录中
**3.** 提交更改过得代码到服务器
1. 首先更新服务器端的代码到客户端
`(为避免多人协作,svn出现冲突,此步骤须执行,且养成`先up, 再commit` 的好习惯)`如果是第一次提交,可不执行 up 步骤
2. 提交代码:
- 打开终端,先定位到/ Users/apple/Documents/code 目录中,
输入:` cd/Users/apple/Documents/code`
- 输入提交指令: `svn commit -m"测试修改 .main 文件"`
>这个指令会将/Users/apple/Documents/code下的所有修改都同步到服务器端,假如这次我只修改了main.文件,可以看到终端打印的信息.
```javaSending wenhang/zwy/main.mTransmitting data .Committed revision 2 .```
注:`recision 2 `中 数字 2 表示的是提交 svn 项目版本的标识数
**4.** 更新服务器端的代码到本地客户端
刚才在步骤3中其实已经提到过了,很简单的一步.
首先在终端定位到客户端代码目录后,然后再输入指令: `svn update` 缩写:(svn up)
**5.** 更多命令,可以在终端输入 svn help 查看
![Snip20161118_8.png](http://upload-images.jianshu.io/upload_images/1654839-6030439ad5209e59.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
> 注: 系统自带的 SVN 无法支持本地删除文件的更新,即当本地删除文件后去更新服务器的文件时,删除的文件又从服务器上拖拽到本地文件中, 但是其支持文件修改后的操作更新操作.
###svn 操作解析
**1、往版本库中添加新的文件**
`svn add file`
例如:svn add test.m(添加test.m)
svn add *.m(添加当前目录下所有的.m文件)
svn add xxx@2x.png 文件时, 正常命令 svn add xxx@2x.png 会报 xxx not found
需用 svn add xxx@2x.png@ 来添加,也就是图片名字后面再添加一个@ 符号,这是因为 svn 命令最后需要用@符号来指定一个版本导致的遇到 xxx@2x.png文件时,如果用svn命令行添加到 版本库的话,只能手动一个一个添加,不能批量添加**
2、加锁/解锁**
`svn lock -m “LockMessage“ [--force] PATH`
例如:`svn lock -m “lock test file“ test.m`svn unlock PATH
**3、更新到某个版本**
`svn update -r m path`
例如:svn update如果后面没有目录,默认将当前目录以及子目录下的所有文件都更新到最新版本。
`svn update -r 200 test.m`(将版本库中的文件test.m还原到版本200)
svn update test.m(更新,于版本库同步。如果在提交的时候提示过期的话,是因为冲突,需要先update,修改文件,然后清除svn resolved,最后再提交commit)
简写:svn up
**4、查看文件或者目录状态**
(如下状态在 Xcode 中会体现,相信大多数的 iOS 开发者都见过的)
![Snip20161118_9.png](http://upload-images.jianshu.io/upload_images/1654839-c1eecbf5f657c982.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
1)`svn status path`(目录下的文件和子目录的状态,正常状态不显示)
【?:不在svn的控制中;M:内容被修改;C:发生冲突;A:预定加入到版本库;K:被锁定】
2)`svn status -v path`(显示文件和子目录状态)
第一列保持相同,第二列显示工作版本号,第三和第四列显示最后一次修改的版本号和修改人。
>注:svn status、svn diff和 svn revert这三条命令在没有网络的情况下也可以执行的,原因是svn在本地的.svn中保留了本地版本的原始拷贝。
简写:svn st
**5、删除文件**
`svn delete path -m “delete test fle“`
例如:`svn delete svn://192.168.1.1/pro/domain/test.php -m “delete test file”
`或者直接`svn delete test.php` 然后再`svn ci -m ‘delete test file‘`,推荐使用这种
简写:svn (del, remove, rm)
**6、查看日志**
`svn log path`
例如:`svn log test.m`显示这个文件的所有修改记录,及其版本号的变化
**7、查看文件详细信息**
`svn info path`
例如:`svn info test.m`
**8、比较差异**
`svn diff path`(将修改的文件与基础版本比较)
例如:`svn diff test.m`
`svn diff -r m:n path`(对版本m和版本n比较差异)
例如:`svn diff -r 200:201 test.m`
简写:svn di
**9、将两个版本之间的差异合并到当前文件**
`svn merge -r m:n path`
例如:`svn merge -r 200:205 test.m`(将版本200与205之间的差异合并到当前文件,但是一般都会产生冲突,需要处理一下)
**10、版本库下的文件和目录列表**
`svn list path`显示path目录下的所有属于版本库的文件和目录
简写:svn ls
**11、创建纳入版本控制下的新目录**
`svn mkdir`: 创建纳入版本控制下的新目录。
用法:
1、`mkdir PATH…`
2、mkdir URL…创建版本控制的目录。
- 1)每一个以工作副本 PATH 指定的目录,都会创建在本地端,并且加入新增调度,以待下一次的提交。
- 2)每个以URL指定的目录,都会透过立即提交于仓库中创建。在这两个情况下,所有的中间目录都必须事先存在。
**12、恢复本地修改**
svn revert: 恢复原始未改变的工作副本文件 (恢复大部份的本地修改)。
revert:用法: revert PATH…
注意: 本子命令不会存取网络,并且会解除冲突的状况。但是它不会恢复被删除的目录
**13、代码库URL变更**
svn switch (sw): 更新工作副本至不同的URL。
用法:
1、switch URL [PATH]
2、switch –relocate FROM TO [PATH...]
- 1)更新你的工作副本,映射到一个新的URL,其行为跟“svn update”很像,也会将服务器上文件与本地文件合并。这是将工作副本对应到同一仓库中某个分支或者标记的方法。
- 2)改写工作副本的URL元数据,以反映单纯的URL上的改变。当仓库的根URL变动(比如方案名或是主机名称变动),但是工作副本仍旧对映到同一仓库的同一目录时使用这个命令更新工作副本与仓库的对应关系。
**14、解决冲突**
svn resolved: 移除工作副本的目录或文件的“冲突”状态。
用法: resolved PATH…
注意: 本子命令不会依语法来解决冲突或是移除冲突标记;它只是移除冲突的相关文件,然后让 PATH 可以再次提交。
**15、输出指定文件或URL的内容。**
svn cat 目标[@版本]…如果指定了版本,将从指定的版本开始查找。
svn cat -r PREV filename > filename (PREV 是上一版本,也可以写具体版本号,这样输出结果是可以提交的)
**16、配置忽略文件 vi ~/.subversion/config**
找到 global-ignores 一行,去掉注释,编辑成
global-ignores = build *~.nib *.so *.pbxuser *.mode *.perspective*
找到 enable-auto-props = yes 把注释去掉,在[auto-props] Section声明以下文本文件
*.mode* = svn:mime-type=text/X-xcode
*.pbxuser = svn:mime-type=text/X-xcode
*.perspective* = svn:mime-type=text/X-xcode
*.pbxproj = svn:mime-type=text/X-xcode
**17、清理工作拷贝/移除锁/完成未完成的操作/等等**
`svn cleanup path`
###svn 常见报错`(这才是整理了半天,真正的干货)
1.svn: Server sent unexpected return value (500 Internal Server Error) in response to OPTIONS request for 'http://svn.moon.ossxp.com/svn/test'
错误的用户名
检查登录的用户名是否输入错误
svn: 服务器发送了意外的返回值(500 Internal Server Error),在响应 “OPTIONS” 的请求 “http://svn.moon.ossxp.com/svn/test” 中
2.svn: OPTIONS of 'http://svn.moon.ossxp.com/svn/test': authorization failed: Could not authenticate to server: rejected Basic challenge (http://svn.moon.ossxp.com)
错误的口令
用正确的用户名/口令登录
svn: 方法 OPTIONS 失败于 “http://svn.moon.ossxp.com/svn/test”: 认证失败: Could not authenticate to server: rejected Basic challenge (http://svn.moon.ossxp.com)
3.svn: Server sent unexpected return value (403 Forbidden) in response to OPTIONS request for 'http://svn.moon.ossxp.com/svn/test'
用户无权限联系管理员,为用户分配权限
svn: 服务器发送了意外的返回值(403 Forbidden),在响应 “OPTIONS” 的请求 “http://svn.moon.ossxp.com/svn/test” 中
4.svn: OPTIONS of 'http://www.moon.ossxp.com/svn/test': 200 OK (http://www.moon.ossxp.com)
服务器地址错误,是普通Web页面,不支持SVN的 WebDAV 协议
确认输入正确的 SVN 服务地址。
可以在浏览器中输入该地址进行确认 svn: 方法 OPTIONS 失败于 “http://www.moon.ossxp.com/svn/test”: 200 OK (http://www.moon.ossxp.com)
5.The version of your subversion (client) is below 1.5.0, upgrade to 1.5.0 or above. SVN below 1.5.0 can not handle mergeinfo properly. It can mess up our automated merge tracking!
是由于客户端的软件版本低于1.5.0造成的。服务器端对客户端软件版本进行了限制,以免对合并跟踪破坏。
升级本地的Subversion客户端软件到1.5.0或以上版本。
6.svn: This client is too old to work with working copy '.'. You need to get a newer Subversion client, or to downgrade this working copy. See http://subversion.tigris.org/faq.html#working-copy-format-change for details.
安装了多个版本的SVN客户端(TSVN,Subclipse,...),且各个客户端的版本不一致。高版本的SVN客户端会自动更新本地工作目录中的 .svn 目录下的文件格式,导致旧版本的SVN客户端不能继续访问该本地工作目录
将本机安装的所有的SVN客户端都更新到同一个大版本,以避免本地工作目录的格式不一致-svn: 此客户端对于工作副本 . 太旧。你需要取得更新的 Subversion 客户端,或者降级工作副本。 参见 http://subversion.tigris.org/faq.html#working-copy-format-change 以获得更详细的信息。7. svn: Working cop-svn:
此客户端对于工作副本 “.” 太旧。你需要取得更新的 Subversion 客户端,或者降级工作副本。 参见 http://subversion.tigris.org/faq.html#working-copy-format-change 以获得更详细的信息。
7.svn: Working copy 'trunk/src' locked svn: run 'svn cleanup' to remove locks (type 'svn help cleanup' for details)
异常操作导致目录没有解锁。
一个简单的重现方法:在 .svn 目录下创建空的名为 lock 的文件
使用命令行 "svn cleanup" 或者类似的“清理”动作删除锁定
svn: 工作副本“trunk/src”已经锁定 svn: 运行“svn cleanup”删除锁定 (输入“svn help cleanup”得到用法)
8.日志中没有作者信息: ------------------------------------ r9 | (没有作者信息) | … ossxp.com
anonymous commit test
匿名提交导致没有作者信息
检查版本库权限控制,禁止匿名提交
9.正在发送 ... 传输文件数据.svn: 提交失败(细节如下): svn: Commit blocked by pre-commit hook (exit code 1) with output: 提交说明至少应包含 4 个字符, 或者太简单了。
这是由于用户提交的提交说明(commit log),太过简单了。在提交时需要输入有意义的 commit log。
写有意义的提交说明,或者请求管理员更改版本库插件
10.增加 Logger.c 传输文件数据.svn: 提交失败(细节如下):
svn: Commit blocked by pre-commit hook (exit code 1) with output: Wide character in print at /opt/svn/svnroot/myrepos/hooks/scripts/check-case-insensitive.pl line 259.
发现文件名大小写冲突: trunk/src/Logger.c 已经存在于 logger.c管理员设置了对新增文件是否重名(只有大小写不同)的文件进行检查。
文件名只有大小写不同,在Windows上进行检出会造成麻烦不要添加重名(仅大小写不同)文件增加 src/文件aBc.txt 传输文件数据.svn: 提交失败(细节如下):
svn: Commit blocked by pre-commit hook (exit code 1) with output: Clash: '/trunk/src/文件aBc.txt' '/trunk/src/文件abc.txt'
11.svn: While preparing '/home/jiangxin/tmp/svn.test/trunk/src/README.txt' for commit svn: Inconsistent line ending style
提交的文件已经设置了 svn:eol-style 属性,但是该文本内的换行符有DOS的换行符CRLF,也有Unix换行符LF,不一致!
统一该文本文件内的换行符。Linux 下可以用dos2unix, unix2dos, sed等命令。Windows下可用 UltraEdit 进行转换。 svn: 当为提交操作准备“/home/jiangxin/tmp/svn.test/trunk/src/README.txt”时 svn: 不一致的行结束样式
12.svn: Failed to add file 'Makefile': an unversioned file of the same name already exists
执行更新(svn up)时报错。因为其他人新增一个文件到服务器,而本地却存在一个同名文件(未版本控制)
先将本地重名文件改名,再执行 "svn up",之后再比较、合并文件。或者执行 "svn up --force"-svn: 增加文件 'Makefile' 失败: 同名未版本控制的文件已存在 13. Adding src/Makefile svn: Commit failed (details follow): svn: File '/svn/test/trunk/src/Makefile' already exists 添加新文件,提交时报错。
-svn: 增加文件 'Makefile' 失败: 同名未版本控制的文件已存在
13.Adding src/Makefile svn: Commit failed (details follow): svn: File '/svn/test/trunk/src/Makefile' already exists
添加新文件,提交时报错。因为其他人已经先于我增加了该文件。
先执行更新操作("svn up"),再根据提示进行操作:合并/提交...增加 src/Makefile svn: 提交失败(细节如下): svn: 文件“/svn/test/trunk/src/Makefile”已存在
14.$ svn up Conflict discovered in 'Makefile'. Select: (p) postpone, (df) diff-full, (e) edit, (mc) mine-conflict, (tc) theirs-conflict, (s) show all options: p C Makefile Updated to revision 5. Summary of conflicts: Text conflicts: 1
多人同时编辑同一个文件时,可能会遇到冲突。别人先于我提交,则当我提交时要先更新。更新可能遇到不能自动解决的冲突使用工具进行冲突解决
$ svn up 在 “Makefile” 中发现冲突。 选择: (p) 推迟,(df) 显示全部差异,(e) 编辑, (mc) 我的版本, (tc) 他人的版本, (s) 显示全部选项: p C Makefile 更新到版本 5。 冲突概要: 正文冲突:1
15.svn: Commit failed (details follow): svn: File 'Makefile' is out of date svn: File not found: transaction '6-d', path '/trunk/src/Makefile'
提交的文件已被他人删除
先执行更新操作("svn up"),再根据提示解决该树冲突:删除文件或继续添加...
svn: 提交失败(细节如下): svn: 文件 “Makefile” 已经过时 svn: File not found: transaction '6-c', path '/trunk/src/Makefile'16.svn: Commit failed (details follow): svn: File or directory '/trunk/XXX' is out of date; try updating svn: resource out of date; try updating
基于旧版本修改是不允许的先更新("svn update"),再提交 svn: 提交失败(细节如下): svn: 文件或目录 “/trunk/XXX” 已经过时;请先更新 svn: resource out of date; try updating
17.svn: DAV request failed; it's possible that the repository's pre-revprop-change hook either failed or is non-existent svn: At least one property change failed; repository is unchanged svn: Error setting property 'log': Repository has not been enabled to accept revision propchanges; ask the administrator to create a pre-revprop-change hook
修改提交说明等操作属于高风险操作,因为该操作没有被版本控制,属于不可恢复的操作。缺省禁止。
请联系管理员,启用该版本的相关钩子,允许修改“版本属性”。参见 管理员钩子设置
svn: DAV 请求失败;可能是版本库的 pre-revprop-change 钩子执行失败或者不存在 svn: 至少有一个属性变更失败;版本库未改变 svn: 设置属性 “log” 出错: Repository has not been enabled to accept revision propchanges; ask the administrator to create a pre-revprop-change hook
>更多技术交流请加群 iOS技术联盟 27512466
```java
深信积累的力量,时间就是你的朋友,否则,他就是你的敌人 ```