【SVN 详细使用指南:从入门到团队协作】

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 会:

  1. 从服务器下载项目文件。
  2. 在本地创建工作副本。
  3. 建立本地目录和远程仓库之间的关联。

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 暂时不处理

注意

不要看到冲突后直接选择"全部使用自己的"或"全部使用服务器的"。

正确做法是:

  1. 理解双方修改目的。
  2. 比较差异。
  3. 合并业务逻辑。
  4. 编译和测试。
  5. 标记已解决。
  6. 再提交。

七、文件锁: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 目录创建后只读,不再直接修改

如果发现发布版本有问题,应该:

  1. 从标签创建维护分支。
  2. 在维护分支修复。
  3. 创建新的标签。

不要直接修改旧标签。


九、忽略文件

编译项目时,经常会产生不应该提交的文件:

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
  • 文件锁:团队协作用锁,使用 lockunlock

十二、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 完成后,原来的本地目录不会自动变成工作副本。

通常需要:

  1. 将项目导入服务器。
  2. 备份或删除原本地目录。
  3. 重新执行 checkout
  4. 在新的工作副本中继续开发。

十四、查看和恢复历史版本

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

如果发生冲突:

  1. 解决冲突。
  2. 编译测试。
  3. 再次提交。

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. 提交了错误文件

如果刚刚错误提交,通常不要尝试修改历史。

可以:

  1. 恢复正确内容。
  2. 再提交一个修复版本。

或者反向合并:

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 管理的团队项目。

相关推荐
ziguo11226 小时前
深入浅出 C/C++ 数据类型:从入门到踩坑
linux·c语言·c++·windows·visual studio
白色冰激凌6 小时前
[SECS/GEM研究] (三)SECS-I 串口上消息怎么分块和重传
c++·secs/gem
光头闪亮亮7 小时前
Fyne ( go跨平台GUI )项目实战-项目开发必备基础知识(中)
android·c++·go
光头闪亮亮7 小时前
Fyne ( go跨平台GUI )项目实战-项目开发必备基础知识(下)
android·c++·go
_wyt0017 小时前
洛谷 P7912 [CSP-J 2021] 小熊的果篮 题解
c++·队列
choumin8 小时前
创建型模式——原型模式
c++·设计模式·原型模式·创建型模式
code_pgf9 小时前
C/C++ 常用容器功能汇总
c语言·开发语言·c++
王维同学10 小时前
Credential Provider、Filter 与 PLAP 的 CLSID 枚举
c++·windows·安全·注册表
小保CPP10 小时前
OpenCV C++基于模糊数学的图像修复
c++·人工智能·opencv·计算机视觉