SVN 教程
SVN 教程
SVN(Subversion)是一款集中式版本控制系统,由 Apache 基金会维护,广泛用于软件开发中的代码版本管理。虽然 Git 已成为主流,但 SVN 在企业存量项目中仍有大量应用。
SVN 核心概念
- 仓库(Repository):集中存放所有版本数据的服务器
- 工作副本(Working Copy):本地检出的代码目录
- 检出(Checkout):从仓库获取代码到本地
- 提交(Commit):把本地修改上传到仓库
- 更新(Update):把仓库最新代码同步到本地
- 版本(Revision):每次提交生成唯一版本号
集中式 vs 分布式
| 特性 | SVN(集中式) | Git(分布式) |
|---|---|---|
| 仓库位置 | 唯一中央仓库 | 每台机器完整副本 |
| 离线提交 | 不可以 | 可以 |
| 分支成本 | 较高 | 低 |
| 适用场景 | 企业内网、传统项目 | 开源、分布式协作 |
基本工作流
svn checkout url # 检出 # 修改文件... svn add 新文件 # 添加新文件 svn commit -m "说明" # 提交 svn update # 更新(拉取他人修改)
SVN 简介
SVN 简介
1. 历史
Subversion 由 CollabNet 于 2000 年发起,旨在替代老旧的 CVS。2009 年成为 Apache 基金会顶级项目,是目前最流行的集中式版本控制系统。
2. 核心特性
- 集中管理:所有版本历史存于中央仓库,权限统一控制
- 原子提交:一次提交要么全部成功要么全部失败
- 目录版本化:目录本身也是版本化对象,支持移动/复制/删除
- 二进制支持:可管理图片、文档等二进制文件
- 廉价复制:分支与标签通过复制实现,成本低
3. 目录结构
SVN 仓库通常遵循标准目录结构:
仓库根/ ├── trunk/ 主开发线(主干) ├── branches/ 分支(功能/发布/修复) └── tags/ 标签(发布快照)
4. 常见客户端
- TortoiseSVN:Windows 资源管理器集成,最流行
- 命令行 svn:跨平台,脚本友好
- IDEA/Eclipse 插件:IDE 内置
- Cornerstone:macOS 图形客户端
5. 与其他工具集成
- Bug 追踪系统(Jira、Redmine)
- CI/CD(Jenkins、GitLab CI 支持 SVN)
- 代码评审工具
SVN 安装
SVN 安装
1. 服务器端安装
# Ubuntu/Debian sudo apt install subversion # CentOS sudo yum install subversion # 验证 svn --version # Windows 服务器 # 下载 VisualSVN Server(集成界面)或 CollabNet
2. 创建仓库
# 创建仓库目录 svnadmin create /opt/svn/repos # 创建标准结构 svn mkdir -m "创建标准目录" file:///opt/svn/repos/trunk file:///opt/svn/repos/branches file:///opt/svn/repos/tags
3. 启动服务
# 方式一:svnserve(独立守护进程) svnserve -d -r /opt/svn # 访问: svn://host/repos # 方式二:Apache 集成(支持 HTTP/HTTPS) # 安装 mod_dav_svn 并配置 # 方式三:SSH 隧道 svn+ssh://user@host/opt/svn/repos
4. 客户端安装
# Linux/macOS sudo apt install subversion # Ubuntu brew install subversion # macOS # Windows # 命令行:下载 SlikSVN 或 VisualSVN # 图形:安装 TortoiseSVN # 验证 svn --version
5. 配置访问控制
# 编辑 conf/svnserve.conf [general] anon-access = none # 匿名禁止 auth-access = write # 认证可写 password-db = passwd # 用户密码文件 authz-db = authz # 权限文件 # conf/passwd 添加用户 [users] zhangsan = password123 lisi = password456 # conf/authz 配置权限 [/] zhangsan = rw lisi = r * =
SVN 生命周期
SVN 生命周期
理解 SVN 的工作流程,是使用好版本控制的关键。
1. 核心状态
仓库(Repository) 中央数据存储 检出(Checkout) 创建工作副本 更新(Update) 同步仓库最新状态 修改(Edit) 本地编辑文件 添加/删除(Add/Delete) 变更文件集合 提交(Commit) 变更写入仓库 回退(Revert) 撤销本地修改
2. 创建与检出
# 创建仓库 svnadmin create repos # 检出到工作目录 svn checkout svn://localhost/repos/trunk myproject # 或 svn co svn://host/repos/trunk myproject
3. 日常修改循环
# 1. 更新到最新 svn update # 2. 修改代码、添加新文件 svn add newfile.py svn add *.txt # 3. 查看状态与差异 svn status svn diff # 4. 提交 svn commit -m "实现登录功能" # 或简写 svn ci -m "说明"
4. 冲突处理
# 提交前先更新,发现冲突 svn update # 输出: C file.txt(冲突) # 查看冲突文件 svn resolve file.txt --accept mine-conflict # 或手动编辑后标记解决 svn resolve file.txt # 提交解决后的文件 svn commit -m "解决冲突"
5. 生命周期最佳实践
- 每次提交前先 svn update
- 提交信息写清楚改动内容
- 小步提交,避免一次性大量变更
- 不要提交编译产物和临时文件
- 设置 svn:ignore 忽略无用文件
SVN 启动模式
SVN 启动模式
SVN 服务可以通过多种方式启动,适应不同的网络环境。
1. svnserve 模式(独立服务)
# 启动守护进程,默认端口 3690 svnserve -d -r /opt/svn # 参数说明 -d 后台守护进程模式 -r 指定仓库根目录 --listen-port 3690 指定端口 --listen-host 0.0.0.0 绑定地址 # 访问方式 svn://host/repos svn://host/repos/trunk
2. Apache HTTP 模式
# 安装模块
sudo apt install libapache2-mod-svn
# 配置 /etc/apache2/mods-available/dav_svn.conf
<Location /svn>
DAV svn
SVNParentPath /opt/svn
AuthType Basic
AuthName "SVN Repository"
AuthUserFile /etc/apache2/dav_svn.passwd
Require valid-user
</Location>
# 创建用户
htpasswd -c /etc/apache2/dav_svn.passwd zhangsan
# 重启 Apache
sudo systemctl restart apache2
# 访问方式(支持 Web 浏览)
http://host/svn/repos
https://host/svn/repos
3. SSH 隧道模式
# 通过 SSH 访问 svn+ssh://user@host/opt/svn/repos # 配置 ssh 免密(可选) ssh-keygen ssh-copy-id user@host
4. 模式对比
| 模式 | 端口 | 安全 | 适用 |
|---|---|---|---|
| svnserve | 3690 | 明文,可配 SSL | 内网小团队 |
| Apache | 80/443 | HTTPS 加密 | 跨网络、需 Web 浏览 |
| SSH | 22 | SSH 加密 | 已有 SSH 环境 |
5. 防火墙与安全
# 开放端口 sudo ufw allow 3690/tcp # svnserve sudo ufw allow 443/tcp # HTTPS # 备份仓库 svnadmin hotcopy /opt/svn/repos /backup/repos-$(date +%F) # 定期备份 + 增量备份
SVN 创建版本库
SVN 创建版本库
1. 创建仓库
# 创建目录 mkdir -p /opt/svn cd /opt/svn # 创建版本库 svnadmin create repos # 查看结构 ls repos # conf db format hooks locks README.txt
2. 初始化标准结构
# 通过文件协议创建标准目录 svn mkdir -m "初始化" file:///opt/svn/repos/trunk file:///opt/svn/repos/branches file:///opt/svn/repos/tags # 或用导入方式 mkdir -p /tmp/project/trunk echo "hello" > /tmp/project/trunk/readme.txt svn import /tmp/project file:///opt/svn/repos -m "导入项目"
3. 配置文件
# repos/conf/svnserve.conf [general] anon-access = none auth-access = write password-db = passwd authz-db = authz realm = MyRepository # repos/conf/passwd [users] admin = admin123 dev1 = dev123 dev2 = dev456 # repos/conf/authz(示例) [groups] devteam = dev1, dev2 [/] admin = rw [repos:/trunk] @devteam = rw [repos:/branches] dev1 = rw * = r
4. 启动与验证
# 启动服务 svnserve -d -r /opt/svn # 客户端验证 svn list svn://localhost/repos # 检出测试 svn co svn://localhost/repos/trunk test-wc
5. 仓库维护
# 查看仓库信息 svnadmin info /opt/svn/repos # 校验完整性 svnadmin verify /opt/svn/repos # 备份 svnadmin dump /opt/svn/repos > repos.dump # 恢复 svnadmin load /opt/svn/newrepos < repos.dump # 热拷贝备份(推荐,不停服) svnadmin hotcopy /opt/svn/repos /backup/repos # 升级格式 svnadmin upgrade /opt/svn/repos
SVN 检出操作
SVN 检出操作
1. 基本检出
# 检出整个 trunk svn checkout svn://host/repos/trunk myproject # 简写 co svn co svn://host/repos/trunk # 检出到指定目录 svn co svn://host/repos/trunk /home/user/project # 检出指定版本 svn co svn://host/repos/trunk -r 100 project # 检出到当前目录(加 .) svn co svn://host/repos/trunk .
2. 检出指定目录
# 只检出 src 子目录(稀疏检出) svn co svn://host/repos/trunk/src src # 浅检出(不拉取历史) svn co --depth empty svn://host/repos/trunk svn update --set-depth infinity # 之后补全
3. 工作副本状态
# 查看状态 svn status # 输出解读: # A 新增 M 修改 D 删除 # C 冲突 ? 未纳入 ! 缺失 # 查看文件详情 svn info svn info file.txt # URL、Revision、Last Changed 等 # 查看仓库目录 svn list svn://host/repos/trunk svn ls svn://host/repos
4. 更新操作
# 更新工作副本到最新 svn update # 更新到指定版本 svn update -r 50 # 更新单个文件 svn update file.txt # 更新时忽略冲突提示 svn update --accept theirs-full
5. 检出问题排查
# 认证失败 # 检查用户名密码,或添加 --username --password # 权限不足 # 检查 authz 配置 # 网络不通 svn ls svn://host/repos # 测试连通 # 清缓存重试 rm -rf ~/.subversion/auth
SVN 解决冲突
SVN 解决冲突
多人同时修改同一文件时会产生冲突,需要手动解决。
1. 冲突的产生
# 场景: # 你和同事都修改了 file.txt 的同一行 # 你先提交,同事 update 时产生冲突 # 冲突输出 C file.txt # 冲突标记: C 表示冲突(Conflicted)
2. 冲突文件
# 冲突后生成三个文件 file.txt # 冲突合并版本(需手动解决) file.txt.mine # 你的版本 file.txt.r100 # 冲突前的仓库版本(100) file.txt.r102 # 最新仓库版本(102) # 冲突标记内容 <<<<<<< .mine 我的修改内容 ======= 别人的修改内容 >>>>>>> .r102
3. 解决方式
# 方式一:保留我的版本 svn resolve file.txt --accept mine-full # 或 mine-conflict(仅冲突处用我的) # 方式二:保留对方版本 svn resolve file.txt --accept theirs-full # 方式三:手动编辑后标记解决 # 编辑 file.txt 保留期望内容 svn resolve file.txt --accept working # 简写标记已解决 svn resolved file.txt
4. 冲突预防
# 1. 提交前先更新 svn update # 2. 及时提交,减少冲突窗口 # 3. 避免同时修改同一模块 # 4. 用锁定(Lock)保护关键文件 svn lock file.txt # 加锁 svn unlock file.txt # 解锁 # 加锁后他人提交会失败,适合二进制文件
5. 冲突处理流程
1. svn update 发现冲突 2. 查看冲突文件内容 3. 与同事沟通合并策略 4. 编辑文件保留最终内容 5. svn resolve --accept working 6. 测试后提交 7. 提交信息注明冲突解决
SVN 提交操作
SVN 提交操作
1. 基本提交
# 提交所有修改 svn commit -m "修复登录 Bug" # 提交指定文件 svn commit file1.py file2.py -m "修改配置" # 简写 ci svn ci -m "提交说明" # 不带 -m 会打开编辑器(默认 vim) svn commit
2. 提交前检查
# 查看修改内容 svn status # 文件状态 svn diff # 具体差异 svn diff file.py # 单文件差异 # 撤销本地修改(不想要了) svn revert file.py # 单文件 svn revert -R . # 递归全部 # 添加新文件 svn add newfile.txt svn add *.py # 删除文件 svn delete old.py # 或直接 svn rm old.py
3. 提交信息规范
# 好的提交信息 svn ci -m "修复:用户登录时密码加密传输" svn ci -m "新增:导出 Excel 报表功能" svn ci -m "重构:抽取数据库连接工具类" # 不好的信息 svn ci -m "改了一下" svn ci -m "aaa" # 建议格式:类型 + 简述 # fix: / feat: / docs: / refactor: / test:
4. 提交后操作
# 查看提交日志 svn log svn log -l 10 # 最近 10 条 svn log file.py # 文件历史 svn log -v # 详细(含变更文件) svn log -r 100:110 # 版本区间 # 查看版本详情 svn info svn info -r 105
5. 提交最佳实践
- 提交前 update,先解决冲突
- 小步提交,逻辑完整即可提交
- 不要提交编译产物(.class、node_modules、__pycache__)
- 设置 svn:ignore 忽略无用文件
- 提交信息描述"为什么"而非"改了什么"
SVN 版本回退
SVN 版本回退
1. 查看历史版本
# 查看提交日志 svn log svn log -r 100:105 # 查看某版本的文件内容 svn cat -r 100 file.txt # 查看文件版本差异 svn diff -r 100:105 file.txt # 查看仓库目录在指定版本的结构 svn list -r 100 svn://host/repos/trunk
2. 更新到旧版本(查看)
# 整个工作副本回到旧版本 svn update -r 100 # 单个文件回到旧版本 svn update -r 100 file.txt # 注意:这会"倒退"你的工作副本 # 之后提交需谨慎
3. 回退提交(reverse-merge)
# 撤销某次提交(推荐方式) # 例如撤销版本 105 的修改 svn merge -c -105 . svn commit -m "回退 105 的修改" # 撤销一段版本区间 svn merge -r 110:105 . # 撤销 105-110 的提交 svn commit -m "回退 105 到 110" # 先看将要产生的变化 svn merge -c -105 --dry-run .
4. 恢复误删文件
# 误删文件后从仓库恢复 svn copy svn://host/repos/trunk/file.txt file.txt svn commit -m "恢复误删的 file.txt" # 或者: svn revert file.txt # 未提交的删除可还原 svn update file.txt # 已提交的删除,update 可拉回?
5. 回退注意事项
- 用 merge 回退而非直接 update -r(会丢失工作副本)
- 回退前备份工作副本
- 回退本身也是一次提交,写好说明
- 回退后通知团队同步更新
SVN 查看历史信息
SVN 查看历史信息
1. svn log 日志
# 基本日志
svn log
# 限制条数
svn log -l 20
# 指定版本区间
svn log -r 90:100
# 详细日志(显示变更文件)
svn log -v
# 显示差异
svn log -d
# 单文件历史
svn log file.txt
# 指定时间范围
svn log -r {2026-01-01}:{2026-08-18}
2. svn diff 差异
# 本地未提交修改 svn diff # 单文件 svn diff file.py # 与指定版本对比 svn diff -r 100 file.py # 两个版本间对比 svn diff -r 100:110 # 仓库版本对比 svn diff -r 100 svn://host/repos/trunk/file.py
3. svn blame 追溯
# 逐行显示最后修改人和版本 svn blame file.py # 输出: 105 zhangsan 登录逻辑 # 108 lisi bug修复 # 别名 annotate / praise svn annotate file.py # 指定版本 svn blame -r 100 file.py
4. svn info 信息
svn info # Path、URL、Repository Root、Revision # Last Changed Rev/Date/Author svn info file.txt svn info -r 100
5. 历史分析场景
# 找某行是谁改的
svn blame file.py | grep "关键代码"
# 看某功能何时引入
svn log -v | grep -B5 "feature"
# 对比发布版本差异
svn diff -r {tag_v1.0}:{tag_v2.0} --summarize
# 统计提交量
svn log | grep -c "^r"
SVN 分支
SVN 分支
分支用于并行开发互不干扰的功能,完成后再合并回主干。
1. 创建分支
# 从 trunk 复制创建分支(推荐用 svn copy) svn copy svn://host/repos/trunk svn://host/repos/branches/feature-login -m "创建登录功能分支" # 或者基于指定版本 svn copy svn://host/repos/trunk@100 svn://host/repos/branches/release-2.0 -m "基于 r100 创建 2.0 发布分支"
2. 切换到分支
# 检出分支(新工作副本) svn co svn://host/repos/branches/feature-login # 已有工作副本切换分支 svn switch svn://host/repos/branches/feature-login # 切换回主干 svn switch svn://host/repos/trunk # 查看当前分支 svn info | grep URL
3. 合并分支回主干
# 1. 切到主干 svn switch svn://host/repos/trunk # 2. 更新到最新 svn update # 3. 合并分支(计算从创建点以来的所有变更) svn merge svn://host/repos/branches/feature-login # 4. 解决冲突(如有) svn status # 手动解决冲突后 svn resolve --accept working conflicted-file # 5. 测试后提交 svn commit -m "合并登录功能分支到主干"
4. 合并指定区间
# 合并分支的 110-120 版本 svn merge -r 110:120 svn://host/repos/branches/feature-login # 查看合并预览 svn merge --dry-run -r 110:120 svn://host/repos/branches/feature-login svn diff
5. 分支管理最佳实践
- 标准结构:trunk 主干 + branches 功能分支 + tags 标签
- 功能分支命名:feature-xxx / bugfix-xxx
- 发布分支:release-x.y
- 分支合并前先同步主干到分支(svn merge trunk)
- 定期合并,避免分支过老
SVN 标签
SVN 标签
标签(tag)是某一时刻代码的快照,通常用于标记发布版本,创建后不再修改。
1. 创建标签
# 从主干创建标签 svn copy svn://host/repos/trunk svn://host/repos/tags/v2.0.0 -m "发布 v2.0.0" # 从指定版本创建 svn copy svn://host/repos/trunk@150 svn://host/repos/tags/v1.5.0 -m "基于 r150 打标签" # 从分支创建 svn copy svn://host/repos/branches/release-2.0 svn://host/repos/tags/v2.0.1 -m "发布补丁版本"
2. 查看与切换标签
# 查看所有标签 svn list svn://host/repos/tags # 检出某个标签(只读) svn co svn://host/repos/tags/v2.0.0 release-2.0.0 # 查看标签内容 svn ls svn://host/repos/tags/v2.0.0
3. 标签规范
# 语义化版本号 v1.0.0 v1.1.0 v2.0.0 # 版本号规则 主版本.次版本.补丁 v2.0.0-alpha 预发布 v2.0.0-rc1 候选发布 # 命名建议 release-1.0.0 v1.0.0 2016-08-18(日期式,不推荐)
4. 基于标签修复
# 1. 从标签建修复分支 svn copy svn://host/repos/tags/v2.0.0 svn://host/repos/branches/hotfix-2.0.1 -m "2.0.1 修复分支" # 2. 在分支修复并提交 svn co svn://host/repos/branches/hotfix-2.0.1 # 修改文件... svn commit -m "修复紧急 Bug" # 3. 重新打标签 svn copy svn://host/repos/branches/hotfix-2.0.1 svn://host/repos/tags/v2.0.1 -m "发布 v2.0.1" # 4. 合并修复回主干 svn switch svn://host/repos/trunk svn merge svn://host/repos/branches/hotfix-2.0.1 svn commit -m "合并 2.0.1 修复"
5. 标签最佳实践
- 标签一旦创建不再修改(如需修改则建新标签)
- 发布版本必须打标签,便于回溯
- 标签目录保持整洁,语义清晰
- CI/CD 可从标签构建发布
TortoiseSVN 使用教程
TortoiseSVN 使用教程
TortoiseSVN 是 Windows 上最流行的 SVN 图形客户端,集成在资源管理器中,右键即可完成所有操作。
1. 安装
# 从 tortoisesvn.net 下载安装包 # 安装时选择语言包(中文) # 安装后右键菜单出现 SVN 相关选项
2. 检出(Checkout)
1. 新建文件夹,进入 2. 右键 → SVN Checkout... 3. URL of repository: 填入 svn://host/repos/trunk 4. Checkout directory: 自动填当前目录 5. 点击 OK # 图标说明 绿色对勾: 与仓库一致 红色感叹号: 有本地修改 黄色警告: 有冲突 蓝色加号: 新文件未添加
3. 提交(Commit)
1. 修改文件后,在文件夹右键 → SVN Commit... 2. 勾选要提交的文件 3. 填写提交信息(Message) 4. 点击 OK # 右键单文件也可直接提交
4. 更新(Update)
# 右键 → SVN Update # 获取最新代码 # 更新到指定版本 # 右键 → TortoiseSVN → Update to Revision...
5. 常用操作
# 查看修改 右键 → SVN Show log # 提交历史 右键 → TortoiseSVN → Check for modifications # 本地修改 右键 → TortoiseSVN → Diff # 查看差异 # 添加/删除 右键 → TortoiseSVN → Add # 添加新文件 右键 → TortoiseSVN → Delete # 删除 # 分支与标签 右键 → TortoiseSVN → Branch/Tag # 复制到 branches/xxx 或 tags/v1.0 # 合并 右键 → TortoiseSVN → Merge...
6. 冲突解决界面
# 冲突时 TortoiseSVN 提供图形化合并工具 # Edit Conflicts 打开 3 窗口对比 # 可逐块选择"使用我的"或"使用对方的" # 或者右键 → TortoiseSVN → Edit conflicts # 完成后 → Mark as resolved
7. 常用设置
# 右键 → TortoiseSVN → Settings # Global ignore pattern: 忽略文件模式 # *.class *.log node_modules/ __pycache__/ # 自动添加 svn:ignore # 右键 → TortoiseSVN → Properties # 添加 svn:ignore 属性 # 认证缓存 # 首次连接保存用户名密码
第 1 / 14 节