站内链接:

介绍和术语

介绍

Subversion(SVN)是一个开源的版本控制系統, 根据提交版本管理不断变化的数据, 这些数据都存储在 repository 中. 版本控制一开始来源于工程领域, 其是维护工程蓝图的标准做法, 能追踪工程蓝图从诞生一直到定案的过程, 以便将来查阅特定版本修订情况的系统. 基于 VSC 系统可以做到如下功能:

  • 将选定的文件回溯到之前的状态
  • 将整个项目都回退到过去某个时间点的状态, 在某些关键的时间点记录版本号信息, 极大的便捷版本发布流程
  • 比较文件的变化细节以查出最后谁修改了哪个地方, 进而找到问题所在, 最后记录问题解决的方法
  • 工程化的思维去管理项目文件, 避免文件管理混乱问题
  • 基于权限控制来确保文件的安全

目前, 大部分的公司都是用 git 版本控制系统进行代码管理, 虽然 SVN 在一些行业中仍然有其使用场景, 但这里仅仅做一些基本的介绍, 一些涉及到 SVN 的高级操作和工程化应用暂未介绍. 另一方面, 通过了解 cvs 历史, 了解 svn 的优缺点, 我们能够更好的了解 git 的优势, 大部分的开发知识架构都是类似, 通过了解历史的变迁, 能够更好的知晓市场会采用目前的方案和技术架构, 加深对当前技术框架细微处的理解.

术语

SVN 一些概念简要介绍:

  • 集中式仓库: 统一管理版本服务器, 只有服务器持有仓库的版本信息, 客户端仅仅持有某一份快照信息
  • repository: 仓库, 源代码统一存放的地方
  • checkout: 提取, 从集中版本库创建一个工作副本或者快照
  • status: 查看当前工作副本的变动信息
  • add: 向文件拷贝所在的文件夹中添加新的文件并做出标识
  • commit: 在执行变更(add)之后,进行检查和冲突解决之后提交更改
  • revert: 版本回滚(本地工作副本)
  • copy: 分支的创建, tags 的创建, 每一个分支都是一个独立的副本文件夹, git 中这些目录是隐藏的

工作流

svn 的分支管理远远不如 git, 但是我们可以仿照 git 的工作流实现 svn 的团队协作, 一般由管理员在创建 repository 的时候设置如下仓库目录结构:

1
2
➜  svn ls
branches readme.md tags trunk
  • branches分支为开发分支所在目录, 在其中存放功能开发分支
  • trunk作为项目的主分支, 只维护可发布的稳定代码, 所有发布都基于 trunk 代码进行;
  • tags标签, 只读, 存储阶段性版本
  • 另外还可以创建 feature-NAME, release-VERSION, issue-VERSION 等分支, 具体根据实际开发需求来决定

在默认配置下, 管理员拥有仓库的所有目录权限, 在拉取所有的分支信息之后可以看到所有分支的信息, 实际上每个分支都是 trunk 基础上的延伸, 这点完全不同于 git, git 的分支可以在本地随意创建并且有非常方便的使用方式. 对于普通用户, 其一般只拥有 branches 下某些分支的权限, 一般开发都是在某个分支下操作, 其 checkout 和管理员就有一些不同:

1
2
3
4
5
# 1. 管理员拉取代码到本地(一般不会做这种危险操作)
svn checkout svn://121.196.35.6/ --username=admin

# 2. 某个用户拉取自己的开发分支到本地
svn checkout svn://121.196.35.6/branches/develop_bifeng develop_bifeng --username=bifeng

关于 svn 的其他命令可以查看第三章内容

vcs

历史

版本控制工具有:

  • VCS, 诞生于 1990, 远古时代的主流源代码管理工具
  • SVN(subversion), 集中式版本控制王者, CVS 的接班人.
  • GIT, 分布式版本控制的顶级作品, 目前版本控制系统的主流
  • 其他

那么, 这些版本控制系统有哪些区别呢? 集中式版本控制和分布式版本控制有什么区别呢?

版本系统

首先, 让我们介绍一下本地文件版本系统, 集中式版本系统, 分布式版本系统的优劣. 在没有 vcs 系统之前, 我们在本地怎么保存不同的版本文件的呢? 比如, 毕业论文设计, 数据库 sql 文件, 日志记录文件, 此时我们都会通过对文件增加一定的后缀来同源文件区分开来, 流程类似 RCS 系统:

local_vcs

但是, 这种工作方式仅仅适用于个人, 对于团队协作该方式极易造成代码的覆盖,版本管理的混乱, 此时集中化的版本控制系统(Centralized Version Control Systems, CVCS)应运而生, 例如 cvs, subversion, perforce 等. 这些集中式版本控制系统实现了如下需求:

  • 单一集中管理的文件服务器
  • 保存所有文件的修订版本
  • multiple client 连接唯一的 server 进行数据的获取和数据的更新

svn_vcs

集中式版本控制系统客户端上并不维护和持有整个 repository 的所有信息, 仅仅持有单独的快照, 一旦中央服务器发生宕机, 则无法进行后续的协同工作. 分布式版本控制系统(Distributed Version Control System, DVCS)就是为了解决此类问题而被提出, 例如 git, Mercurial, Bazaar, Darcs 等, 此时客户端并不只提取最新版本的文件快照, 而是把代码仓库完整地镜像下来, 包括完整的历史记录. 一旦系统工作的服务器发生故障, 事后都可以用任何一个本地镜像的仓库进行恢复操作. 最后, 在配合模块化项目管理, 将项目分成多个微服务 repository, 即保证了代码的私密性也提高了团队协作.

另外, 在缺少网络的情况下 svn 服务器实际上无法进行基于本地的 commit 等逻辑操作, 这在大部分中小型公司是非常的不适用的, 但是如果使用 git, 每一个 client 自身就是一个仓库, 可以在工作区,缓存区,版本库进行离线操作, 在网络恢复的时候进行多端同步和问题冲突解决.

git-vcs

当然, git 能够逐渐替代 SVN 成为主流版本控制系统, 不仅仅是分布式控制系统, git 的分支管理能力也是其能够取胜的关键法宝.

使用

创建项目仓库

git 项目仓库的创建和 svn 的创建有一些细微的不同, 前者如果不依赖服务器进行多人协作和同步时可以在本地自行创建仓库和进行后续的其他操作, 但是 svn 则必须先在 server 创建仓库并分配权限信息.

1
2
3
4
5
# 1. git 离线创建仓库
mkdir myfirst
git init
echo "this is a test for create repository from local" > myfirst.md
git commit -m 'type: feat init'

当然, 如果希望基于 git 服务器进行团队协作, 则需要将本地仓库同远程服务器仓库进行关联, 注意确保此时没有冲突, 否则会refs失败.

1
2
3
# 2. 关联本地git仓库和远程仓库
git remote add origin 'git@gitlab.com:username/myfirst.git'
git push origin master

但是 svn 本地不是一个独立的代码仓库, 其必须依赖仓库管理员提前初始化仓库和分配相关权限才可以进行下一步操作

1
2
3
4
5
6
7
8
# a. svn仓库创建并进行用户, 组的配置
svnadmin create /var/svn/svnrepos

# b. 根据工作流的思路由超级管理员创建多个top目录并对用户分配权限
branches tags trunk

# c. 普通用户在本地拉取某个分支快照到本地
svn checkout svn://121.196.35.6/branches/develop_bifeng develop_bifeng --username=bifeng

关于 svn 服务器的部署见下面的参考文章.

同步代码

在 git 相关文章中有介绍过工作区, 缓存区, 版本区, 此时开发者对新增代码的 add, commit 等操作都是离线的, 这也是 git 由于 svn 的一大优势, 其中 git 更新代码的流程如下:

1
2
3
4
5
6
7
# a. 在工作区编辑代码, 并将当前工作区的某些希望提交的代码从工作到->缓存区
git add test.txt diff.txt
git diff --cached
git status

# b. 将staged去的改动提交到版本区
git commit -m 'type: feat create test filename'

相对的, svn 没有缓存区, 版本区的概念, 每次 commit 都是同版本控制服务器进行同步操作

1
2
3
4
5
6
# a. 编辑代码, 如果是新文件, 则需要先通过add命令添加到版本中并标识
git add new.txt

# b. 同步并更新
svn checkout svn://121.196.35.6/branches/develop_bifeng develop_bifeng --username=bifeng
svn commit -m 'type: feat 增加new.txt, 更新old.txt文件'

分支操作

按照前文的 git 工作流, 平常开发的时候需要拥有开发者自己的 feature 分支, 自己的 bugfix 分支, 管理员拥有 master 分支, develop 分支, tags 分支的权限:

  • a. feature_username在开发阶段进行功能开发, 在开发阶段需要确保及时同步 develop 分支上项目其他成员的代码
  • b. bugfix_username在预发布阶段进行 bug 的修复, 这是因为开发工作成一般都是预发布和下一个版本的开发并行执行
  • c. 开发者在自测阶段进行功能合并, 在 develop 分支进行 CICD 之后进行自测
  • d. 管理员在预发布阶段进行 tag, 并自动打提测包
  • e. 在最终阶段打正式版本号 tag, 进行完整的发布

不管是 git 和 svn 项目管理工具都是这些流程, 在这些流程下必然伴随着各种分支合并操作, git 的分支操作这里就先暂时不介绍了, 下面让我们看下 svn 的分支操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 1. 项目管理员, 从当前主分支创建某个分支, 注意, 这实际上不是git的开发分支
svn copy trunk branches/develop_bifeng
svn copy trunk issues/bugfix_bifeng
svn copy svn://121.196.35.6/branches/develop_remote svn://121.196.35.6/branches/develop_remote

# 2. 开发者拉取某个分支代码
git checkout svn://121.196.35.6/branches/develop_bifeng develop_bifeng --username=bifeng

# 3. 查看版本号和分支信息
svn log --stop-on-copy
svn info

# 4. 切换分支, develop_bifeng到bugfix_bifeng
svn sw svn://121.196.35.6/branches/bugfix_bifeng

# 5. 分支合并, target -> current source
svn merge -r {current_branch_latest_version}:HEAD svn://121.196.35.6/branches/{target branch} .
svn commit -m 'svn:git 合并bugfix到develop'

# 6. 版本回退到指定值
svn merge -r 20:10 filename
svn commit -m 'type: merge 合并分支'

参考: