SVN 详细使用指南:从入门到团队协作
本文面向刚接触 SVN 的开发者,系统介绍 SVN 的基本概念、常用命令、日常开发流程、冲突处理、分支与标签、文件锁、常见问题以及团队使用规范。
一、SVN 是什么
SVN 的全称是 Apache Subversion,是一种集中式版本控制系统。
版本控制系统主要用来解决以下问题:
- 保存代码的历史版本。
- 查看某个文件由谁修改、何时修改。
- 多人同时开发同一个项目。
- 撤销错误修改。
- 对比不同版本之间的差异。
- 创建分支,开发不同功能。
- 保存正式发布版本。
- 在出现问题时回退到历史版本。
SVN 采用集中式结构:
text
SVN 中央仓库
│
┌────────────┼────────────┐
│ │ │
开发者 A 开发者 B 开发者 C
工作副本 工作副本 工作副本
代码的正式版本保存在中央 SVN 服务器中。开发者把代码从服务器下载到本地,在本地修改后,再提交回服务器。
二、SVN 的核心概念
1. Repository:版本库
Repository 通常称为"仓库"或"版本库"。
它保存在 SVN 服务器中,包含:
- 当前代码。
- 历史代码。
- 每次提交记录。
- 版本号。
- 提交人。
- 提交时间。
- 提交说明。
例如:
text
https://svn.example.com/svn/MyProject
这就是一个 SVN 仓库地址。
2. Working Copy:工作副本
使用 checkout 把项目下载到本地后,本地目录叫作"工作副本"。
例如:
text
D:\Code\MyProject
工作副本中既有项目文件,也有 SVN 自己的管理信息。
在 SVN 1.7 及更高版本中,通常会在工作副本根目录看到一个隐藏的 .svn 目录。
不要手动修改或删除 .svn 目录,否则可能导致工作副本损坏。
3. Revision:版本号
SVN 每次成功提交后,整个仓库都会产生一个新的全局版本号。
例如:
text
r100
r101
r102
假设开发者修改了三个文件,然后一次性提交,这三个文件会共同属于同一个新版本号,例如 r103。
SVN 的版本号是仓库级别的,不是单个文件单独计算。
4. Trunk、Branches 和 Tags
SVN 项目通常采用以下目录结构:
text
MyProject/
├── trunk/
├── branches/
└── tags/
含义如下:
trunk:主干代码,通常保存主要开发版本。branches:分支,用于新功能、版本维护或实验开发。tags:标签,用于保存正式发布版本。
例如:
text
MyProject/
├── trunk/
├── branches/
│ ├── feature-login/
│ └── release-2.0/
└── tags/
├── v1.0.0/
└── v1.1.0/
三、安装 SVN 客户端
Windows 下常见的 SVN 客户端有:
1. TortoiseSVN
TortoiseSVN 集成到 Windows 资源管理器右键菜单中,适合初学者和日常开发。
安装后,在文件夹中右键通常可以看到:
text
SVN Checkout
SVN Update
SVN Commit
TortoiseSVN
TortoiseSVN 还会通过图标覆盖显示文件状态,例如:
- 绿色对勾:文件正常,没有本地修改。
- 红色感叹号:文件已修改。
- 蓝色加号:文件准备添加。
- 黄色感叹号:可能存在冲突或异常。
- 灰色减号:文件被忽略。
- 锁图标:文件已加锁。
2. SVN 命令行客户端
安装 Apache Subversion 或 TortoiseSVN 命令行组件后,可以使用:
bash
svn --version
查看是否安装成功。
本文主要使用命令行说明,TortoiseSVN 中通常都能找到对应的图形操作。
四、SVN 最常用操作
1. Checkout:第一次检出项目
第一次从 SVN 服务器下载项目时,使用 checkout:
bash
svn checkout 仓库地址 本地目录
例如:
bash
svn checkout https://svn.example.com/svn/MyProject/trunk D:\Code\MyProject
简写:
bash
svn co https://svn.example.com/svn/MyProject/trunk D:\Code\MyProject
执行后,SVN 会:
- 从服务器下载项目文件。
- 在本地创建工作副本。
- 建立本地目录和远程仓库之间的关联。
Checkout 和 Update 的区别
checkout 用于第一次下载项目:
text
服务器上有项目,本地还没有工作副本
update 用于已经检出项目后获取最新代码:
text
本地已经有工作副本,需要同步其他人的修改
不要每天重新 checkout,日常同步使用 update。
2. Update:更新代码
获取服务器上的最新修改:
bash
svn update
简写:
bash
svn up
更新某个文件:
bash
svn update main.cpp
更新到指定历史版本:
bash
svn update -r 100
恢复到最新版本:
bash
svn update -r HEAD
其中:
HEAD表示服务器上的最新版本。r100表示版本 100。
Update 可能出现的结果
text
U main.cpp
A new_file.cpp
D old_file.cpp
G config.cpp
C user.cpp
含义如下:
| 标记 | 含义 |
|---|---|
U |
文件已更新 |
A |
新文件已下载 |
D |
文件已删除 |
G |
服务器修改与本地修改成功合并 |
C |
发生冲突 |
推荐做法
每天开始开发前执行:
bash
svn update
提交代码前再执行一次:
bash
svn update
这样可以尽早发现冲突,避免在提交时才发现代码已经过时。
3. Status:查看工作副本状态
查看本地文件状态:
bash
svn status
简写:
bash
svn st
常见结果:
text
M main.cpp
A dialog.cpp
D old.cpp
? test.log
! missing.cpp
C config.cpp
状态说明:
| 标记 | 含义 |
|---|---|
M |
文件已修改 |
A |
文件已添加,等待提交 |
D |
文件已删除,等待提交 |
? |
文件未加入 SVN 管理 |
! |
SVN 管理的文件在本地丢失 |
C |
文件存在冲突 |
R |
文件被替换 |
I |
文件被忽略 |
L |
工作副本被锁定 |
~ |
文件类型发生变化 |
查看服务器上是否有新版本:
bash
svn status -u
输出中如果出现 *,说明服务器上存在更新版本:
text
M * main.cpp
表示:
- 本地修改了
main.cpp。 - 服务器上的
main.cpp也已经变化。 - 更新时可能发生冲突。
4. Diff:查看修改内容
查看本地修改:
bash
svn diff
查看某个文件:
bash
svn diff main.cpp
查看两个版本之间的差异:
bash
svn diff -r 100:105
查看某个文件在两个版本之间的差异:
bash
svn diff -r 100:105 main.cpp
diff 的常见格式:
diff
- int count = 10;
+ int count = 20;
其中:
-表示旧内容。+表示新内容。
提交前应该检查:
bash
svn status
svn diff
这样可以避免:
- 提交调试代码。
- 提交临时打印。
- 提交密码或密钥。
- 提交不相关修改。
- 误删代码。
- 提交格式化产生的大量无意义变化。
5. Add:添加新文件
新建文件后,SVN 不会自动管理它。
先查看状态:
bash
svn status
可能看到:
text
? network.cpp
? network.h
添加文件:
bash
svn add network.cpp
svn add network.h
添加整个目录:
bash
svn add network
递归添加目录中的文件:
bash
svn add new_module
然后提交:
bash
svn commit -m "新增网络模块"
简写:
bash
svn ci -m "新增网络模块"
需要注意:
text
svn add
只是把文件标记为"等待加入版本控制",并没有上传到服务器。
必须执行 commit 后,文件才真正进入仓库。
6. Delete:删除文件
删除 SVN 管理的文件:
bash
svn delete old.cpp
简写:
bash
svn del old.cpp
然后提交:
bash
svn commit -m "删除废弃文件"
也可以删除目录:
bash
svn delete old_module
不建议直接在资源管理器中删除
如果直接删除,执行:
bash
svn status
会看到:
text
! old.cpp
表示 SVN 认为这个文件应该存在,但本地已经丢失。
此时可以执行:
bash
svn delete old.cpp
把这个删除动作纳入 SVN 管理。
7. Move 和 Rename:移动或重命名
重命名文件:
bash
svn move old_name.cpp new_name.cpp
简写:
bash
svn mv old_name.cpp new_name.cpp
移动文件:
bash
svn move main.cpp src/main.cpp
然后提交:
bash
svn commit -m "调整源代码目录"
SVN 的移动操作通常可以理解为:
text
复制到新位置 + 删除旧位置
建议使用 svn move,不要手动复制后再删除,否则历史记录可能不够清晰。
8. Commit:提交修改
把本地修改提交到中央仓库:
bash
svn commit -m "修复登录失败问题"
简写:
bash
svn ci -m "修复登录失败问题"
只提交指定文件:
bash
svn commit main.cpp login.cpp -m "修复登录逻辑"
提交前建议执行:
bash
svn update
svn status
svn diff
svn commit -m "清晰的提交说明"
SVN 提交的特点
SVN 的 commit 会直接提交到中央服务器。
这与 Git 不同:
text
Git commit:通常只提交到本地仓库
Git push:再上传到远程仓库
SVN commit:直接提交到中央仓库
好的提交说明
推荐:
text
修复 U 盘重新插入后按钮位置错乱问题
新增用户登录超时处理
优化启动阶段文件读取逻辑
删除已废弃的配置接口
不推荐:
text
修改
提交
update
修复 bug
测试
提交说明应该能让其他开发者快速了解:
- 为什么修改。
- 修改了什么。
- 影响哪个模块。
9. Revert:撤销本地修改
撤销某个文件尚未提交的修改:
bash
svn revert main.cpp
递归撤销整个目录:
bash
svn revert -R .
撤销准备添加的文件:
bash
svn revert new_file.cpp
撤销准备删除的文件:
bash
svn revert deleted_file.cpp
Revert 的注意事项
revert 会丢弃未提交修改,通常很难恢复。
执行前建议先查看:
bash
svn diff
或者先手动备份文件。
Revert 与 Update 的区别
revert:
text
丢弃本地修改,恢复到工作副本原来的基准版本
update:
text
获取服务器上的最新版本,并尝试与本地修改合并
10. Log:查看提交历史
查看当前目录的提交记录:
bash
svn log
查看某个文件的历史:
bash
svn log main.cpp
只看最近 10 条:
bash
svn log -l 10
查看指定版本范围:
bash
svn log -r 100:120
查看某个版本的详细修改:
bash
svn log -v -r 105
常见输出:
text
------------------------------------------------------------------------
r105 | zhangsan | 2026-07-23 10:20:00 | 1 line
修复登录超时问题
------------------------------------------------------------------------
可以看到:
- 版本号。
- 提交人。
- 提交时间。
- 提交说明。
11. Info:查看工作副本信息
查看当前工作副本信息:
bash
svn info
可能输出:
text
Working Copy Root Path: D:\Code\MyProject
URL: https://svn.example.com/svn/MyProject/trunk
Repository Root: https://svn.example.com/svn/MyProject
Revision: 105
Last Changed Author: zhangsan
Last Changed Rev: 104
可以用来确认:
- 当前目录是否是 SVN 工作副本。
- 当前连接的是哪个仓库。
- 当前位于主干还是分支。
- 当前工作副本版本。
- 最近一次修改人。
12. List:查看仓库目录
查看远程仓库目录:
bash
svn list https://svn.example.com/svn/MyProject
简写:
bash
svn ls https://svn.example.com/svn/MyProject
查看详细信息:
bash
svn list -v https://svn.example.com/svn/MyProject
适合在没有完整检出项目时查看仓库结构。
13. Cat:查看历史文件内容
查看服务器上某个文件的内容:
bash
svn cat https://svn.example.com/svn/MyProject/trunk/main.cpp
查看指定版本:
bash
svn cat -r 100 main.cpp
将历史版本保存为新文件:
bash
svn cat -r 100 main.cpp > main_r100.cpp
这样不会修改当前工作副本。
14. Blame:查看每一行是谁修改的
bash
svn blame main.cpp
也可以使用:
bash
svn annotate main.cpp
简写:
bash
svn ann main.cpp
输出示例:
text
100 zhangsan #include <iostream>
102 lisi int main()
102 lisi {
105 wangwu return 0;
102 lisi }
可以查看每一行:
- 最后修改版本。
- 最后修改人。
- 具体内容。
它适合排查:
- 某段代码是谁引入的。
- 为什么这样写。
- 应该向谁确认需求。
- 某个问题从哪个版本开始出现。
不要把 blame 理解为"追责工具",它本质上是代码历史分析工具。
五、标准日常开发流程
一个较规范的 SVN 开发流程如下:
第一步:更新代码
bash
svn update
确保本地基于较新的代码进行开发。
第二步:修改代码
完成需求或修复问题。
第三步:检查修改状态
bash
svn status
确认:
- 修改了哪些文件。
- 是否有未加入版本控制的新文件。
- 是否误删文件。
- 是否存在冲突。
第四步:查看差异
bash
svn diff
检查实际修改内容。
第五步:再次更新
bash
svn update
获取其他开发者在你开发期间提交的代码。
如果没有冲突,继续下一步。
如果有冲突,先解决冲突。
第六步:编译和测试
必须确认:
- 工程可以编译。
- 基本功能正常。
- 没有引入明显回归问题。
- 没有提交临时调试文件。
第七步:提交
bash
svn commit -m "修复设备重新插入后按钮位置异常"
完整流程:
text
svn update
↓
修改代码
↓
svn status
↓
svn diff
↓
svn update
↓
解决冲突
↓
编译测试
↓
svn commit
六、SVN 冲突处理
1. 冲突是怎么产生的
假设服务器上的代码是:
cpp
int count = 10;
开发者 A 修改为:
cpp
int count = 20;
开发者 B 修改为:
cpp
int count = 30;
A 先提交。
B 再执行 svn update 时,SVN 发现同一位置被两个人修改,无法自动判断应该保留哪个值,于是产生冲突。
状态中会出现:
text
C main.cpp
2. 冲突文件中的标记
文本冲突可能显示为:
cpp
<<<<<<< .mine
int count = 30;
=======
int count = 20;
>>>>>>> .r105
含义:
text
<<<<<<< .mine
下面是自己的本地修改。
text
=======
是本地版本与服务器版本的分界线。
text
>>>>>>> .r105
上面是服务器版本的内容。
需要人工决定最终保留什么,例如:
cpp
int count = 20;
或者根据实际业务重新编写:
cpp
int count = GetDefaultCount();
3. 冲突时常见的附加文件
旧版 SVN 或部分客户端可能生成:
text
main.cpp.mine
main.cpp.r100
main.cpp.r105
含义大致如下:
main.cpp.mine:自己的修改。main.cpp.r100:修改前的基础版本。main.cpp.r105:服务器上的新版本。
这些文件用于辅助比较。
4. 标记冲突已解决
人工修改好文件后:
bash
svn resolve --accept working main.cpp
或者旧命令:
bash
svn resolved main.cpp
然后检查:
bash
svn status
确认 C 状态已经消失,再编译测试并提交。
5. resolve 的常见选项
接受自己的版本:
bash
svn resolve --accept mine-full main.cpp
接受服务器版本:
bash
svn resolve --accept theirs-full main.cpp
接受当前人工编辑后的文件:
bash
svn resolve --accept working main.cpp
常见含义:
| 选项 | 含义 |
|---|---|
working |
使用当前工作文件,通常表示已人工合并 |
mine-full |
完整保留自己的版本 |
theirs-full |
完整采用服务器版本 |
base |
使用双方修改前的基础版本 |
postpone |
暂时不处理 |
注意
不要看到冲突后直接选择"全部使用自己的"或"全部使用服务器的"。
正确做法是:
- 理解双方修改目的。
- 比较差异。
- 合并业务逻辑。
- 编译和测试。
- 标记已解决。
- 再提交。
七、文件锁:Lock 和 Unlock
1. 为什么需要锁
文本代码通常可以合并,但以下文件通常难以合并:
- 图片。
- Word 文档。
- Excel 文件。
- PSD 文件。
- 数据库文件。
- 二进制配置文件。
- 设计器生成的二进制资源。
- 某些大型工程文件。
对于这些文件,可以使用文件锁。
2. Lock:锁定文件
bash
svn lock design.psd -m "修改登录页面设计"
加锁后,其他开发者通常不能提交该文件。
查看锁信息:
bash
svn info design.psd
3. Unlock:解锁文件
bash
svn unlock design.psd
如果提交后仍然保留锁,可以根据客户端配置选择是否解锁。
使用锁的流程
text
svn update
↓
svn lock 文件
↓
修改文件
↓
svn commit
↓
svn unlock 文件
注意
锁不是普通源代码协作的首选方式。
对 .cpp、.h 等文本文件,一般应允许多人修改,通过合并和冲突处理协作。
锁更适合不能有效合并的二进制文件。
八、分支、标签和合并
1. SVN 如何创建分支
SVN 没有独立的 branch 命令。
分支本质上是服务器端复制:
bash
svn copy \
https://svn.example.com/svn/MyProject/trunk \
https://svn.example.com/svn/MyProject/branches/feature-login \
-m "创建登录功能分支"
SVN 的仓库复制通常是"廉价复制",不会立即完整复制所有物理数据。
2. Switch:切换分支
把当前工作副本从主干切换到分支:
bash
svn switch https://svn.example.com/svn/MyProject/branches/feature-login
简写:
bash
svn sw https://svn.example.com/svn/MyProject/branches/feature-login
切回主干:
bash
svn switch https://svn.example.com/svn/MyProject/trunk
切换后建议执行:
bash
svn info
确认当前 URL 是否正确。
3. Merge:合并分支
切换到目标工作副本后,合并来源分支:
bash
svn merge https://svn.example.com/svn/MyProject/branches/feature-login
合并后只是修改了本地工作副本,还需要:
bash
svn status
svn diff
确认内容,解决冲突,测试后提交:
bash
svn commit -m "合并登录功能分支"
4. 合并指定版本
只合并某一次提交:
bash
svn merge -c 105 https://svn.example.com/svn/MyProject/trunk
合并多个连续版本:
bash
svn merge -r 100:105 https://svn.example.com/svn/MyProject/trunk
反向合并某个版本,用于撤销某次提交:
bash
svn merge -c -105 .
然后检查、测试并提交:
bash
svn commit -m "撤销 r105 引入的修改"
5. 创建 Tag
标签同样通过复制创建:
bash
svn copy \
https://svn.example.com/svn/MyProject/trunk \
https://svn.example.com/svn/MyProject/tags/v1.0.0 \
-m "发布 v1.0.0"
标签通常用于保存:
- 正式发布版本。
- 测试版本。
- 里程碑版本。
- 交付客户的版本。
团队一般规定:
text
tags 目录创建后只读,不再直接修改
如果发现发布版本有问题,应该:
- 从标签创建维护分支。
- 在维护分支修复。
- 创建新的标签。
不要直接修改旧标签。
九、忽略文件
编译项目时,经常会产生不应该提交的文件:
text
Debug/
Release/
build/
*.obj
*.pdb
*.user
*.log
*.tmp
.vs/
可以通过 svn:ignore 属性忽略。
例如忽略当前目录中的:
text
Debug
Release
*.user
*.log
命令行可以先准备一个文件 ignore.txt:
text
Debug
Release
*.user
*.log
然后执行:
bash
svn propset svn:ignore -F ignore.txt .
查看属性:
bash
svn propget svn:ignore .
修改后需要提交目录属性:
bash
svn commit -m "配置编译产物忽略规则"
已经被 SVN 管理的文件不会因为 ignore 自动取消管理
如果文件已经提交过,需要先从版本控制中删除,再设置忽略。
例如希望保留本地配置但不再提交:
bash
svn delete --keep-local config.local
然后设置忽略规则并提交。
十、SVN 属性
SVN 支持给文件和目录设置属性。
查看属性:
bash
svn proplist
查看详细属性:
bash
svn proplist -v
设置属性:
bash
svn propset 属性名 属性值 文件
删除属性:
bash
svn propdel 属性名 文件
常见属性包括:
| 属性 | 作用 |
|---|---|
svn:ignore |
忽略文件 |
svn:needs-lock |
文件修改前需要加锁 |
svn:eol-style |
控制文本换行格式 |
svn:executable |
标记文件可执行 |
svn:mime-type |
设置文件 MIME 类型 |
svn:externals |
引用外部仓库内容 |
例如设置文件需要锁:
bash
svn propset svn:needs-lock "*" design.psd
svn commit -m "设置设计文件修改前必须加锁"
十一、Cleanup:清理工作副本
在以下情况下可能需要 cleanup:
- 更新过程中程序崩溃。
- SVN 操作被强制中断。
- 电脑突然断电。
- 工作副本提示被锁定。
- TortoiseSVN 操作长时间卡住后被结束。
执行:
bash
svn cleanup
对指定目录:
bash
svn cleanup D:\Code\MyProject
cleanup 的作用通常包括:
- 清理未完成的 SVN 操作。
- 解除工作副本内部锁。
- 恢复工作副本元数据状态。
注意:
text
svn cleanup 不是删除文件,也不是撤销代码修改。
不要把工作副本内部锁与 svn lock 文件锁混淆:
- 工作副本内部锁:SVN 操作状态锁,异常时用
cleanup。 - 文件锁:团队协作用锁,使用
lock和unlock。
十二、Export:导出干净代码
导出不带 .svn 管理信息的项目:
bash
svn export https://svn.example.com/svn/MyProject/trunk D:\Release\MyProject
导出当前工作副本:
bash
svn export . D:\Release\MyProject
导出指定版本:
bash
svn export -r 105 \
https://svn.example.com/svn/MyProject/trunk \
D:\Release\MyProject-r105
适合用于:
- 发布源码。
- 软件打包。
- 交付客户。
- 生成干净构建目录。
- 临时查看某个版本。
Export 与 Checkout 的区别
| 操作 | 包含 .svn |
能否 Update | 能否 Commit |
|---|---|---|---|
| Checkout | 是 | 可以 | 可以 |
| Export | 否 | 不可以 | 不可以 |
十三、Import:首次导入项目
如果本地已经有一个未纳入版本控制的项目,可以导入仓库:
bash
svn import D:\Project \
https://svn.example.com/svn/MyProject/trunk \
-m "首次导入项目"
注意:
text
import 完成后,原来的本地目录不会自动变成工作副本。
通常需要:
- 将项目导入服务器。
- 备份或删除原本地目录。
- 重新执行
checkout。 - 在新的工作副本中继续开发。
十四、查看和恢复历史版本
1. 查看某个历史版本
bash
svn update -r 100
这会把工作副本更新到版本 100。
查看完后恢复最新版本:
bash
svn update -r HEAD
2. 获取旧文件但不修改当前文件
bash
svn cat -r 100 main.cpp > main_r100.cpp
这是更安全的查看方式。
3. 撤销某次已经提交的修改
SVN 中已经提交的历史一般不会直接删除。
通常通过反向合并撤销:
bash
svn merge -c -105 .
检查修改:
bash
svn diff
测试后提交:
bash
svn commit -m "撤销 r105 的错误修改"
这样会产生一个新的版本,例如 r110,用于抵消 r105 的修改。
历史记录仍然完整保留。
十五、Relocate:仓库地址变化
如果 SVN 服务器域名或地址变化,但仓库内容和身份不变,可以重新定位:
bash
svn relocate \
https://old.example.com/svn/MyProject \
https://new.example.com/svn/MyProject
使用 TortoiseSVN 时,可以选择:
text
TortoiseSVN → Relocate
不要使用 switch 代替 relocate:
switch:切换同一仓库中的分支或路径。relocate:仓库服务器地址整体发生变化。
十六、SVN 常见错误与处理
1. Working copy locked
错误类似:
text
Working copy is locked
处理:
bash
svn cleanup
如果仍然失败,先确认:
- 是否有其他 SVN 操作正在执行。
- 是否有编辑器或客户端占用文件。
- 当前用户是否有目录权限。
不要直接删除 .svn 目录。
2. Out of date
提交时报错:
text
File or directory is out of date
原因是服务器上已有更新版本。
处理:
bash
svn update
如果发生冲突:
- 解决冲突。
- 编译测试。
- 再次提交。
3. Tree conflict
树冲突常见于:
- 一个人修改文件,另一个人删除文件。
- 一个人移动目录,另一个人修改目录内部文件。
- 双方对同一个文件进行了不同的重命名。
- 一个分支删除文件,另一个分支继续修改。
查看状态:
bash
svn status
可能看到:
text
C old_module
> local edit, incoming delete upon update
树冲突必须结合业务决定:
- 保留本地文件。
- 接受服务器删除。
- 把内容移动到新位置。
- 恢复文件后重新提交。
处理完成后执行:
bash
svn resolve --accept working 路径
4. 文件显示 ?
例如:
text
? test.cpp
表示文件未加入版本控制。
需要提交时:
bash
svn add test.cpp
如果是编译产物或临时文件,则应该配置忽略规则。
5. 文件显示 !
例如:
text
! main.cpp
表示 SVN 记录中有这个文件,但本地找不到。
如果是误删,恢复:
bash
svn revert main.cpp
如果确实要删除:
bash
svn delete main.cpp
6. 提交了错误文件
如果刚刚错误提交,通常不要尝试修改历史。
可以:
- 恢复正确内容。
- 再提交一个修复版本。
或者反向合并:
bash
svn merge -c -错误版本号 .
svn commit -m "撤销错误提交"
如果提交了密码、私钥或敏感信息,仅仅后续删除并不能清除历史版本中的内容,需要立即联系仓库管理员进行安全处理,同时更换已经泄露的凭据。
7. 中文路径或文件名乱码
检查:
- 操作系统区域设置。
- SVN 客户端版本。
- 命令行终端编码。
- 仓库服务端配置。
- 脚本是否按 UTF-8 处理。
Windows 下使用 TortoiseSVN 通常能减少终端编码问题。
十七、TortoiseSVN 常用操作对应关系
| TortoiseSVN 菜单 | 命令行 |
|---|---|
| SVN Checkout | svn checkout |
| SVN Update | svn update |
| SVN Commit | svn commit |
| Add | svn add |
| Delete | svn delete |
| Revert | svn revert |
| Show log | svn log |
| Check for modifications | svn status |
| Diff | svn diff |
| Repo-browser | svn list |
| Branch/tag | svn copy |
| Switch | svn switch |
| Merge | svn merge |
| Resolve | svn resolve |
| Lock | svn lock |
| Release lock | svn unlock |
| Cleanup | svn cleanup |
| Export | svn export |
| Relocate | svn relocate |
十八、SVN 与 Git 的常见操作对比
| SVN | Git | 说明 |
|---|---|---|
svn checkout |
git clone |
第一次下载仓库 |
svn update |
git pull |
获取远程更新 |
svn add |
git add |
添加新文件 |
svn commit |
git commit + git push |
SVN 提交直接进入中央仓库 |
svn status |
git status |
查看状态 |
svn diff |
git diff |
查看差异 |
svn revert |
git restore |
撤销本地修改 |
svn log |
git log |
查看历史 |
svn copy |
git branch / git tag |
创建分支或标签 |
svn switch |
git switch |
切换分支 |
svn merge |
git merge |
合并分支 |
svn resolve |
解决冲突后 git add |
标记冲突已处理 |
svn export |
无完全相同操作 | 导出不带版本信息的代码 |
需要特别注意:
text
SVN commit = 直接提交中央仓库
Git commit = 通常只提交本地仓库
十九、团队开发规范建议
1. 提交前必须更新
推荐:
bash
svn update
避免基于过时版本直接提交。
2. 一次提交只完成一件事
推荐:
text
修复登录超时
不要把以下内容混在一次提交中:
text
修复登录 + 重构网络模块 + 修改界面 + 格式化整个项目
单一目的的提交更容易:
- 审查。
- 回退。
- 定位问题。
- 合并到其他分支。
3. 不提交无法编译的代码
提交前至少确认:
- 编译通过。
- 基本功能通过。
- 没有明显崩溃。
- 没有缺少新文件。
- 没有误提交本地路径。
4. 不提交编译产物
通常不应提交:
text
Debug/
Release/
build/
*.obj
*.pdb
*.ilk
*.log
*.tmp
*.user
.vs/
但具体规则以项目要求为准。
5. 不提交敏感信息
禁止提交:
- 密码。
- Token。
- 私钥。
- 数据库账号。
- 生产环境密钥。
- 个人隐私数据。
- 内部服务器固定凭据。
应该使用:
- 环境变量。
- 本地配置文件。
- 密钥管理系统。
- 配置模板。
- 受控部署系统。
6. 提交说明要清晰
推荐格式:
text
[模块] 修改内容
例如:
text
[登录] 修复 Token 过期后无法重新登录
[设备管理] 修复重新插入 U 盘后按钮错位
[升级] 增加安装包签名校验
[性能] 减少启动阶段重复读取配置文件
7. 大改动前创建分支
以下情况建议创建分支:
- 新功能开发周期较长。
- 架构重构。
- 大版本升级。
- 风险较高的实验。
- 需要维护多个客户版本。
- 主干必须保持稳定。
8. 及时提交,但不要提交半成品
提交太少会导致:
- 修改范围过大。
- 冲突增加。
- 难以回退。
- 难以审查。
提交太频繁且没有完整意义也不好。
合理的提交应该满足:
text
功能逻辑相对完整 + 可以说明目的 + 可以单独审查
二十、常用命令速查表
基础操作
bash
svn checkout URL PATH
svn update
svn status
svn diff
svn add FILE
svn delete FILE
svn move OLD NEW
svn commit -m "说明"
svn revert FILE
历史查看
bash
svn log
svn log -l 10
svn info
svn blame FILE
svn cat -r REV FILE
svn diff -r REV1:REV2
分支与合并
bash
svn copy SOURCE_URL TARGET_URL -m "创建分支"
svn switch BRANCH_URL
svn merge BRANCH_URL
svn merge -c REV URL
svn merge -c -REV .
冲突处理
bash
svn status
svn resolve --accept working FILE
svn resolve --accept mine-full FILE
svn resolve --accept theirs-full FILE
锁操作
bash
svn lock FILE -m "说明"
svn unlock FILE
其他操作
bash
svn cleanup
svn export URL PATH
svn import PATH URL -m "首次导入"
svn list URL
svn relocate OLD_URL NEW_URL
二十一、推荐的 SVN 实战流程
假设你需要修改 LoginService.cpp。
1. 更新项目
bash
svn update
2. 修改代码
完成登录超时问题修复。
3. 检查文件状态
bash
svn status
输出:
text
M src/LoginService.cpp
? src/test.log
发现 test.log 是调试日志,不应该提交。
4. 查看差异
bash
svn diff src/LoginService.cpp
确认修改正确。
5. 再次更新
bash
svn update
如果输出:
text
G src/LoginService.cpp
表示 SVN 已自动合并。
如果输出:
text
C src/LoginService.cpp
则需要人工解决冲突。
6. 编译测试
确认工程正常。
7. 提交指定文件
bash
svn commit src/LoginService.cpp -m "[登录] 修复请求超时后未重新认证的问题"
8. 确认状态
bash
svn status
如果没有输出,通常说明工作副本没有未提交修改。
二十二、总结
学习 SVN,最重要的是先掌握以下操作:
text
checkout:第一次下载项目
update:获取服务器最新代码
status:查看本地状态
diff:查看具体修改
add:添加新文件
delete:删除文件
commit:提交修改
revert:撤销未提交修改
log:查看提交记录
resolve:解决冲突
日常开发应形成固定流程:
text
先 update
→ 再修改
→ 查看 status
→ 检查 diff
→ 再次 update
→ 解决冲突
→ 编译测试
→ 最后 commit
涉及多人协作时,还需要理解:
text
trunk:主干
branches:分支
tags:发布标签
merge:合并修改
lock/unlock:管理不可合并文件
cleanup:修复工作副本异常
SVN 本身并不复杂,真正重要的是养成规范的版本管理习惯:
- 提交前更新。
- 提交前检查。
- 一次提交只做一件事。
- 提交说明清晰。
- 不提交垃圾文件和敏感信息。
- 冲突解决后必须重新测试。
- 正式版本使用标签保存。
- 高风险修改使用分支开发。
掌握这些内容后,就可以比较规范地参与使用 SVN 管理的团队项目。