Subversion(SVN) 是一个开源的版本控制系統
SVN 的一些概念
- repository(源代码库):源代码统一存放的地方
- Checkout(提取):当你手上没有源代码的时候,你需要从repository checkout一份
- Commit(提交):当你已经修改了代码,你就需要Commit到repository
- Update (更新):当你已经Checkout了一份源代码, Update一下你就可以和Repository上的源代码同步,你手上的代码就会有最新的变更
快速开始
1 创建一个新仓库
Subversion 把所有的版本化数据都存放在一个中央仓库中
mkdir /var/svn
cd /var/svn
svnadmin create repos
ls repos
# conf/ dav/ db/ format hooks/ locks/ README.txt
注: 目录 /var/svn/repos 创建了一 个 Subversion 仓库, 如果目录 repos 事先不存在, svnadmin 将自动创建该目录。
2 准备好了可以被导入到新仓库中的 项目 (文件和目录的集合)
Subversion 并不要求仓库顶层目录下必须是 branches, tags 和 trunk 这 3 个子目录, 但这是最流行的仓库目录布局.
/tmp/
myproject/
branches/
tags/
trunk/
foo.c
bar.c
Makefile
…
3 导入到仓库
svn import /tmp/myproject file:///var/svn/repos/myproject
-m "initial import"
Adding myproject/branches
Adding myproject/tags
Adding myproject/trunk
Adding myproject/trunk/foo2.txt
Adding myproject/trunk/main.py
Adding myproject/trunk/test01.py
Committing transaction...
Committed revision 1.
4 要创建一个 “工作副本” (working copy)
它是用户的一个私有 工作空间。下面的命令请求 Subversion 为仓库中的目录 myproject/trunk “检出” (check out) 一个工作副本:
cd /tmp/project
svn checkout file:///var/svn/repos/myproject/trunk myproject
A myproject/foo2.txt
A myproject/main.py
A myproject/test01.py
Checked out revision 1.
# 查看文件
ls myproject/
foo2.txt main.py test01.py
5 修改文件
cat myproject/foo2.txt
www.xxx.com!
Very good!
# 编辑文件内容
vim myproject/foo2.txt
# 进入副本目录
cd myproject
# 查看修改的标准差异输出
svn diff
Index: foo2.txt
===================================================================
--- foo2.txt (revision 1)
+++ foo2.txt (working copy)
@@ -1,2 +1,3 @@
www.xxx.com!
+add a message.
Very good!
# 查看状态
svn status
M foo2.txt
# 提交更改:把修改后的文件提交到 仓库中.
svn commit -m "foo2.txt add a message"
Sending foo2.txt
Transmitting file data .done
Committing transaction...
Committed revision 2.
# 把工作副本 “更新” 到仓库的最新版本.
svn update
基本工作周期
典型的工作周期就像:
- 更新工作副本. 这会用到命令
svn update
. - 修改. 最常见的修改就是编辑已有文件的内容, 但有时还要添加, 删除, 复制和移动文件或目录 — 命令
svn add
,svn delete
,svn copy
和svn move
负责 处理工作副本的结构性调整. - 审查修改. 用命令
svn status
和svn diff
查看工作副本发生了哪些变化. - 修正错误. 人无完人, 在审查修改时用户可 能会发现某些修改是不正确的. 有时候修正错误最简单的方式是撤消所有的 修改, 重新开始. 命令
svn revert
可以把文件或目 录恢复到修改前的样子. - 解决冲突 (合并其他人的修改). 当一个用户 正在修改文件时, 其他人可能已经把自己的修改提交到了服务器上. 为了防 止 在提交修改时, 由于工作副本过旧导致提交失败, 用户需要把其他人的修改 更新到本地, 用到的命令是
svn update
. 如 果命令 的执行结果有冲突产生, 用户需要用命令svn resolve
解决冲突. - 发布 (提交) 修改. 命令
svn commit
把工作副本的修改提交到仓库中, 如果修改 被接受, 其他用户就可以看到这些修改.
更新工作副本
某个项目正在被多个工作副本修改, 用户就需要更新自己本地的 工作副本, 以获取其他人提交的修改。
Subversion 不允许用户向过时 的文件或目录提交修 改, 所以在开始修改前, 最好保证本地工作副本的内容 是最新的。
svn update
Updating '.':
U foo.c
U bar.c
Updated to revision 2.
# 字符代表含义
A Added
D Deleted
U Updated
C Conflict
G Merged
E Existed
R Replaced
修改
分为文件修改 (file changes) 和 目录修改 (tree changes).
文件修改:用户可以使用任意一种自己喜欢的工具来修改文件。Subversion 可以自动检测到哪些文件发生了 变化, 处理二进制文件和处理文本文件一样简单高效.
目录修改涉及到目录结构 的变化, 例如添加和删除文件, 重命名文件和目录, 复制文件和目录. 目录修改 要使用 Subversion 的命令完成.
5 个改变目录结构的 Subversion 子命令:
# 下一次提交时,会生效
# 1 增加
svn add FOO
#把文件, 目录或软链接 FOO 添加 到需要进行版本控制的名单中
#如果 FOO 是一个目录, 那么目录内的所有内容都会 被添加到仓库中.
#如果 只想添加 FOO 它自己, 就带上选项--depth=empty
# 2 删除
svn delete FOO
# 从工作副本中删除文件, 目录或符号链接 FOO
# 用户可以 从更早的版本中看到被删除的文件
# 3 复制
svn copy FOO BAR
# 从 FOO 复制出一个 BAR, 并把 BAR 添加到 需要进行版本控制的名单中
#BAR 被提交到仓库 后, Subversion 会记录它
# 是由 FOO 复制得到的. 除非带上选项 --parents, 否则 svn copy 不会创建父目录.
# 4 移动
svn move FOO BAR
# 等价于 svn copy FOO BAR; svn delete FOO
# 5 创建目录
svn mkdir FOO
#等价于 mkdir FOO; svn add FOO,
#是创建一个新目录 FOO, 并把它添加到仓库中
审查修改
用户可以使用命令 svn status
查看修改的整体概述, 用命令 svn diff
查看修改的细节.
svn status
? scratch.c
A stuff/loot
A stuff/loot/new.c
D stuff/old.c
M bar.c
#
#几种字符或状态是:
? item
文件, 目录或符号链接 item 不在版本 控制的名单中.
A item
文件, 目录或符号链接 item 是新增的, 在下一次提交时就会加入到仓库中.
C item
文件 item 有未解决的冲突, 意思是说从 服务器收到的更新和该文件的本地修改有所重叠, Subversion 在处理 这些重叠
的修改时发生了冲突. 用户必须解决掉冲突后才能向仓库 提交修改.
D item
文件, 目录或符号链接 item 已被删除, 在下一次提交时就会从仓库中删除 item.
M item
文件 item 的内容被修改.
如果给 svn status
传递一个路径名, 那么命 令只会输出和该路径相关的状态信息: $
svn status stuff/fish.c
D stuff/fish.c
svn status 支持选项 --verbose (-v), 带上该选项后, 命令会输出当前目录中每一项的 状态, 即使是未被修改的项目。
svn status 的 “长格式” (long form) 输出:第一列字符的含义不变, 第二列显示该项在工作副本 中的版本号, 第三和 第四列显示该项最后一次被修改的版本号和作者。
svn status -v
M 44 23 sally README
44 30 sally INSTALL
M 44 20 harry bar.c
44 18 ira stuff
44 35 harry stuff/trout.c
D 44 19 ira stuff/fish.c
44 21 sally stuff/things
A 0 ? ? stuff/things/bloo.h
44 36 harry stuff/things/gloo.c
用户可能想知道在上一次更新之后, 哪些 文件在仓库中又被更新了。svn status 带上选项 --show-updates (-u), 这样 Subversion 就会和仓库通信,
svn status -u -v
M * 44 23 sally README
M 44 20 harry bar.c
* 44 35 harry stuff/trout.c
D 44 19 ira stuff/fish.c
A 0 ? ? stuff/things/bloo.h
Status against revision: 46
注意带有星号的那 2 行, 如果此时执行 svn update, 就会从仓库收到 README 和 trout.c 的更新。我们还可以知 道, 在本地被修改的文件当中, 至少有一个在仓库中 也被更新了 (文件 README),用户必须在提交前把 仓库的更新同 步到本地, 否则仓库将会拒绝针对已过时文件的提交。
查看修改的细节
svn diff
, 它会输出文件 内容的变化。如果在工作副本的根目录不加任何参数地执行 svn diff, Subversion 就会输出工作副本中 可读的文件的变化。
每一行文本都加上一个单字符前缀: 空格表示该行没有 变化; 负号 (-) 表示该行被删除; 正号 (+) 表示该行是新增的
用户就可 以在不提交的情况下, 把工作副本的修改分享给其他 人, 创建补丁的方式是把 svn diff 的输出重定向到 补丁文件里:
svn diff > patchfile
如果用户想要其他格式的差异输出, 就用选 项 --diff-cmd 指定一个外部的差异比较程序, 如果需要 的话, 还可以用选项 --extensions 向差异比较程序 传递其 他额外的参数。
例如, 用户想用 GNU 的程序 diff 对文件 foo.c 进行差异比较, 还要求 diff 在比较时忽略大小写, 按照上下文 差异格式来 产生输出:
svn diff --diff-cmd /usr/bin/diff -x "-i" foo.c
修正错误
Subversion 提供了一种简便的方法来撤消工作副本中的 修改, 用到的命令是 svn revert
。
Subversion 利用缓存在基文本中的内容, 把文件 回滚到修改前的原始状态。
$ svn status README
M README
$ svn revert README
Reverted 'README'
$ svn status README
svn revert 会 撤消 任何 一个未提交的修改, 例如用户可能不 想往仓库中添加新文件:
$ svn status new-file.txt
? new-file.txt
$ svn add new-file.txt
A new-file.txt
$ svn revert new-file.txt
Reverted 'new-file.txt'
$ svn status new-file.txt
? new-file.txt
或者是用户错误地删除了一个本不该删除的文件:
$ svn status README
$ svn delete README
D README
$ svn revert README
Reverted 'README'
$ svn status README
解决冲突
提交修改
svn commit 把本地的所有修改发往仓库. 提交时 用户需要输入一段日志来描述本次修改, 日志被附加到新的版本号上. 如 果 日志比较简短, 可以用选项 --message (-m) 直接在命令行上输入日志:
$ svn commit -m "Corrected number of cheese slices."
Sending sandwich.txt
Transmitting file data .
Committed revision 3.
如果用户已经事先把日志写到了某个文本文件中, 希望 Subversion 在 提交时直接从该文件中读取日志, 这可以通过选项 --file (-F) 实现:
$ svn commit -F logmsg
Sending sandwich.txt
Transmitting file data .
Committed revision 4.
如果用户在编写日志时突然又不想提交了, 那就不保存地退出编辑 器; 如果已经保存过, 那就删除全部的提交 日志, 再保存一遍, 然后 退出编辑器:
$ svn commit
Waiting for Emacs...Done
Log message unchanged or not specified
(a)bort, (c)ontinue, (e)dit
a
# 就是不要保存任何日志信息
如果有人趁你不 注意时修改了同一文件,提交就会失败, 并打印 一条错误消息说其中某些文件过时了:
$ svn commit -m "Add another rule"
Sending rules.txt
Transmitting file data .
svn: E155011: Commit failed (details follow):
svn: E155011: File '/home/sally/svn-work/sandwich.txt' is out of date
…
检查历史
下面几个命令提供了检索历史数据的功能:
svn diff
从行的级别上查看修改的内容
svn log
和版本号绑定的日志消息, 及其日期, 作者, 以及受影响的文件 路径.
svn cat
根据给定的版本号, 输出文件在该版本下的内容.
svn annotate
根据给定的版本号, 查看该版本下的文件的每一行的最后一 次修改信息.
svn list
根据给定的版本号, 列出仓库在该版本下的文件与目录清单.
SVN 分支
创建一个分支
$ svn copy trunk/ branches/my_branch
# 提交分支到版本库
$ svn commit -m "add my_branch"
# 切换到 trunk,执行 svn update,然后将 my_branch 分支合并到 trunk 中
$ svn merge ../branches/my_branch/
# 将合并好的 trunk 提交到版本库中。
$ svn commit -m "add index.html"
SVN 标签(tag)
Tags 即标签主要用于项目开发中的里程碑,比如开发到一定阶段可以单独一个版本作为发布等,它往往代表一个可以固定的完整的版本。
我们在本地工作副本创建一个 tag。
$ svn copy trunk/ tags/v1.0
A tags/v1.0
上面的代码成功完成,新的目录将会被创建在 tags 目录下。
$ ls tags/
v1.0
$ ls tags/v1.0/
HelloWorld.html readme
查看状态。
$ ~/svn/runoob01# svn status
A + tags/v1.0
提交tag内容。
$ ~/svn/runoob01# svn commit -m "tags v1.0"
Adding tags/v1.0
Transmitting file data ..
Committed revision 14.