svn 1.7+ 工作副本元数据统一存放在 .svn/wc.db(sqlite3 数据库),1.6 及更早版本则使用分散的 .svn/entries 文本文件;当前主流为 wc.db,其结构包含 nodes、work_queue 等关键表,官方不保证 schema 向后兼容。

SVN工作副本元数据存放在哪里
SVN 1.7+ 的工作副本元数据统一存放在 .svn/wc.db,这是一个 SQLite3 数据库文件;1.6 及更早版本则用分散的 .svn/entries 文本文件(XML 格式)。现在绝大多数项目都已是 1.7+,所以重点处理 wc.db。
直接读取该文件是可行的,但要注意:SVN 进程运行时会加锁(通过 .svn/wc.lock),若文件被占用,SQLite open 会失败或返回 SQLITE_BUSY;另外,wc.db 是内部格式,官方不承诺向后兼容——不同 SVN 版本的 schema 可能变化(比如 1.8、1.9、1.10 各有字段增减)。
常见错误现象:unable to open database file(路径错或权限不足)、database is locked(svn process 正在操作)、no such table: wcroot(用旧版代码连新版 wc.db)。
用 C++ 读取 wc.db 的最小可行方案
推荐用 SQLite C API(轻量、无依赖、C++ 兼容好),不要用 ORM 或封装层——wc.db 表结构简单,手动 query 更可控。
关键步骤:
- 检查
.svn/wc.lock是否存在且为空(非空说明 SVN 正在操作,应跳过或重试) - 用
sqlite3_open_v2(path, &db, SQLITE_OPEN_READONLY, nullptr)打开,**必须指定SQLITE_OPEN_READONLY**,写入会破坏工作副本 - 查询前先确认 schema 版本:
SELECT value FROM config WHERE name = 'format'(对应 wc.db 的 config 表),或查PRAGMA user_version - 核心表是
nodes(含 URL、revision、depth、kind)和wcroot(工作副本根路径映射);常用字段包括local_relpath、repos_id、revision、presence
示例:获取当前目录下所有已版本控制的文件及其修订号
SELECT local_relpath, revision FROM nodes
WHERE presence IN ('normal', 'incomplete')
AND kind = 'file'
AND local_relpath != '';
为什么不该自己解析 .svn/entries(1.6 风格)
虽然 .svn/entries 是纯文本 XML,看似容易 parse,但它已被 SVN 官方弃用多年,且存在严重缺陷:
- 嵌套结构混乱,同一文件可能在多个 entries 块中重复出现(尤其涉及 externals 或切换分支后)
- revision 字段语义模糊:有时是提交修订,有时是检出时的 BASE 修订,不区分 WC-NG 的 BASE/WORKING 层
- 不包含现代 SVN 的关键信息,如:changelist、conflict data、move source/destination
- UTF-8 编码无 BOM,但某些 SVN 实现写入时用本地编码(Windows 上可能是 GBK),导致 C++ std::ifstream 读取乱码
如果你必须支持老旧工作副本,优先尝试升级 svn client 并执行 svn upgrade,而不是写两套解析逻辑。
绕过 wc.db 直接调用 libsvn 的风险与替代思路
有人想链接 libsvn_wc,用 svn_wc_read_kind2()、svn_wc__node_get_baseinfo() 等函数——这理论上最准确,但实际非常危险:
- libsvn 是 ABI 不稳定库,不同 SVN 版本的 so/dll 二进制接口不兼容,C++ 代码链接后极易 crash
- libsvn 内部重度依赖 APR(Apache Portable Runtime),需同步编译并管理内存池(
apr_pool_t*),C++ RAII 很难安全包裹 - 多数 Linux 发行版不提供 libsvn 开发包,Windows 上几乎只能自己编译整个 Subversion 源码
真正稳健的做法是:把解析逻辑下沉为独立进程(如用 Python + pysvn 或 svn CLI 调用 svn info --show-item),C++ 通过 pipe 或临时文件通信。这样既隔离了 SVN 版本差异,又避免了 ABI 和内存模型冲突。
最常被忽略的一点:wc.db 中的 local_relpath 是 POSIX 风格路径(用 / 分隔),即使在 Windows 上也是斜杠,不是反斜杠——别用 _splitpath 或 std::filesystem::path 默认构造去解析它,否则路径拼接会出错。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











