Apache Subversion 常用 CLI 命令与工具详解
汇总 Apache Subversion 1.14 常用 CLI 命令与工具,按 svn 客户端日常操作、分支合并、锁与凭据、svnadmin 管理备份、svnlook 检查、svnsync 热备、svndumpfilter 过滤整理,每组命令配真实输入输出回显、状态标记速查与生产注意事项,并附常见错误码排查,Ubuntu 22.04 环境实测。
Apache Subversion 常用 CLI 命令与工具详解
目标:整理 Apache Subversion 1.14 的常用命令行工具——svn 客户端、svnadmin、svnlook、svnsync、svndumpfilter 等——按场景分组给出命令、真实回显与注意事项,作为日常使用与运维速查。以下命令与回显均在 Ubuntu 22.04.5 + Subversion 1.14.1 环境实测。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS(x86_64)
- Apache Subversion:1.14.1-3ubuntu0.22.04.1(含 subversion-tools)
- 版本库:/srv/svn/repo1(FSFS),svnserve 服务于 svn://127.0.0.1/repo1,Apache dav_svn 服务于 http://127.0.0.1/svn/repo1
- 演示账号:admin,密码 q1w2e3r4
- 工作副本示例目录:/root/work 下的 wc-svn、wc-http、wc-trunk2 等
二、工具概览
apt 安装 subversion 与 subversion-tools 后,/usr/bin 下共 26 个可执行工具(实测 dpkg -L subversion subversion-tools | grep /usr/bin):
| 工具 | 类别 | 用途 |
|---|---|---|
| svn | 客户端 | 检出、提交、更新、合并等全部日常版本控制操作 |
| svnadmin | 服务端管理 | 建库、校验、dump/load 备份恢复、锁管理 |
| svnlook | 服务端检查 | 只读查看修订版信息(作者、日志、变更路径),hook 脚本标配 |
| svnsync | 服务端热备 | 全量+增量同步到镜像库 |
| svndumpfilter | 服务端 | 过滤 dump 流,剔除/保留指定路径 |
| svnrdump | 服务端 | 远程(URL 方式)dump/load,无需登录服务器磁盘 |
| svnserve | 服务端进程 | svn:// 协议守护进程 |
| svnauthz / svnauthz-validate | 服务端 | 校验与查询 authz 授权结果 |
| svnbench | 基准 | 压测导出/检出性能 |
| svnversion | 客户端 | 输出工作副本混合修订号(如 8:10) |
| svn-clean、svn-backup-dumps、svn-hot-backup | 运维脚本 | 工作副本清理、增量/热备份 |
| svnmucc | 客户端 | 不落工作副本直接执行多步 URL 操作 |
| svn-bisect、svn-mergeinfo-normalizer、svn-populate-node-origins-index、svnraisetreeconflict、svn-vendor、svn_apply_autoprops、svn_load_dirs、svnwrap、fsfs-access-map、fsfs-stats、svnfsfs | 辅助 | 二分定位、合并信息规范化、FSFS 统计等 |
svn 客户端子命令一览(实测 svn help,含括号内缩写):
Available subcommands:
add
auth
blame (praise, annotate, ann)
cat
changelist (cl)
checkout (co)
cleanup
commit (ci)
copy (cp)
delete (del, remove, rm)
diff (di)
export
help (?, h)
import
info
list (ls)
lock
log
merge
mergeinfo
mkdir
move (mv, rename, ren)
patch
propdel (pdel, pd)
propedit (pedit, pe)
propget (pget, pg)
proplist (plist, pl)
propset (pset, ps)
relocate
resolve
resolved
revert
status (stat, st)
switch (sw)
unlock
update (up)
upgrade
三、前置条件
- 已安装 subversion、subversion-tools(apt 方案 1.14.1)。
- 已有一个可访问的版本库:本地测试可用
svnadmin create /srv/svn/repo1;远程访问需 svnserve(svn://)或 Apache dav_svn(http://)已启动,账号 admin/q1w2e3r4。 - 命令中出现的 URL 与本机实测环境对应,替换为实际地址即可。
四、工具详解
4.1 svn 客户端:导入、检出、提交、更新
导入项目初版并检出:
# svn import -m "initial import" project-trunk svn://127.0.0.1/repo1/project-trunk --username admin --password q1w2e3r4 --non-interactive
Adding project-trunk/branches
Adding project-trunk/tags
Adding project-trunk/trunk
Adding project-trunk/trunk/README.md
Adding project-trunk/trunk/app.conf
Committing transaction...
Committed revision 1.
# svn checkout svn://127.0.0.1/repo1/project-trunk/trunk wc-svn --username admin --password q1w2e3r4 --non-interactive
A wc-svn/README.md
A wc-svn/app.conf
Checked out revision 1.
💡
--non-interactive避免脚本环境卡在交互输口令;交互终端直接去掉即可。file:// 协议同样可用:svn import -m "msg" 目录 file:///srv/svn/repo1/路径。
修改后查看状态、提交、更新:
# cd wc-svn
# echo "line2 added via svnserve" >> README.md
# echo "new file content" > build-notes.txt
# svn st
M README.md
? build-notes.txt
# svn add build-notes.txt
A build-notes.txt
# svn commit -m "modify README and add build-notes.txt" --username admin --password q1w2e3r4 --non-interactive
Sending README.md
Adding build-notes.txt
Transmitting file data ..done
Committing transaction...
Committed revision 14.
# svn update --username admin --password q1w2e3r4 --non-interactive
Updating '.':
At revision 14.
状态标记速查:M 已修改、A 已新增(待提交)、D 已删除、? 未纳入版本控制、C 冲突、! 丢失。
4.2 svn 客户端:日志、信息、列表、差异、追溯
# svn log --username admin --password q1w2e3r4 --non-interactive
------------------------------------------------------------------------
r2 | admin | 2026-10-12 00:48:02 +0000 (Mon, 12 Oct 2026) | 1 line
modify README via svn protocol
------------------------------------------------------------------------
r1 | admin | 2026-10-12 00:47:57 +0000 (Mon, 12 Oct 2026) | 1 line
initial import
------------------------------------------------------------------------
# svn log http://127.0.0.1/svn/repo1 -v -l 2 --username admin --password q1w2e3r4 --non-interactive
------------------------------------------------------------------------
r10 | admin | 2026-10-12 00:51:43 +0000 (Mon, 12 Oct 2026) | 1 line
Changed paths:
A /project-trunk/trunk/lock-demo.txt
add lock demo file
------------------------------------------------------------------------
r9 | admin | 2026-10-12 00:50:43 +0000 (Mon, 12 Oct 2026) | 1 line
Changed paths:
M /project-trunk/trunk
A /project-trunk/trunk/feature.txt (from /project-trunk/branches/feature-1/feature.txt:8)
merge feature-1 into trunk
------------------------------------------------------------------------
# svn info --username admin --password q1w2e3r4 --non-interactive
Path: .
Working Copy Root Path: /root/work/wc-svn
URL: svn://127.0.0.1/repo1/project-trunk/trunk
Relative URL: ^/project-trunk/trunk
Repository Root: svn://127.0.0.1/repo1
Repository UUID: 733533be-a0e7-445c-904e-d11967ae5c52
Revision: 1
Node Kind: directory
Schedule: normal
Last Changed Author: admin
Last Changed Rev: 1
Last Changed Date: 2026-10-12 00:47:57 +0000 (Mon, 12 Oct 2026)
# svn list http://127.0.0.1/svn/repo1/ --username admin --password q1w2e3r4 --non-interactive
project-trunk/
# svn diff -r 1:2 --username admin --password q1w2e3r4 --non-interactive
Index: README.md
===================================================================
--- README.md (revision 1)
+++ README.md (revision 2)
@@ -1 +1,2 @@
hello subversion
+line2 added via svnserve
# svn blame README.md --username admin --password q1w2e3r4 --non-interactive
1 admin hello subversion
2 admin line2 added via svnserve
3 admin line3 added via http webdav
4 admin hook test line
5 admin empty log test
💡 在工作副本目录内执行
svn log只能看到该路径当前修订号之前的记录,先svn update或直接对 URL 执行可拿到全量历史(上方 r9/r10 即对 URL 查询所得)。
4.3 svn 客户端:导出、取历史版本与属性
# svn cat -r 1 README.md --username admin --password q1w2e3r4 --non-interactive
hello subversion
# svn export -q http://127.0.0.1/svn/repo1/project-trunk/trunk /tmp/export-trunk --username admin --password q1w2e3r4 --non-interactive
# ls /tmp/export-trunk
README.md app.conf feature.txt
属性操作(svn:ignore 忽略规则实测):
# svn propset svn:ignore -F - . <<'EOF'
*.log
*.tmp
EOF
property 'svn:ignore' set on '.'
# svn propget svn:ignore .
*.log
*.tmp
# svn status
M .
# svn revert --recursive .
Reverted '.'.
# svn status
(无输出)
4.4 svn 客户端:分支、切换与合并
建分支(服务端 copy,工作副本之外即可完成):
# svn copy http://127.0.0.1/svn/repo1/project-trunk/trunk http://127.0.0.1/svn/repo1/project-trunk/branches/release-1.0 -m "create release branch" --username admin --password q1w2e3r4 --non-interactive
Committed revision 6.
# svn switch http://127.0.0.1/svn/repo1/project-trunk/branches/release-1.0 wc-http --username admin --password q1w2e3r4 --non-interactive
At revision 6.
# svn info wc-http | grep -E "URL|Relative"
URL: http://127.0.0.1/svn/repo1/project-trunk/branches/release-1.0
Relative URL: ^/project-trunk/branches/release-1.0
分支上开发后合并回主干(实测 feature-1 分支):
# svn copy http://127.0.0.1/svn/repo1/project-trunk/trunk http://127.0.0.1/svn/repo1/project-trunk/branches/feature-1 -m "create feature branch" --username admin --password q1w2e3r4 --non-interactive
Committed revision 7.
# svn checkout http://127.0.0.1/svn/repo1/project-trunk/branches/feature-1 wc-feature --username admin --password q1w2e3r4 --non-interactive
Checked out revision 7.
# echo "feature work" > wc-feature/feature.txt
# svn add wc-feature/feature.txt
A wc-feature/feature.txt
# cd wc-feature && svn commit -m "add feature.txt on feature branch" --username admin --password q1w2e3r4 --non-interactive
Adding feature.txt
Transmitting file data .done
Committing transaction...
Committed revision 8.
# svn checkout -q http://127.0.0.1/svn/repo1/project-trunk/trunk wc-trunk2 --username admin --password q1w2e3r4 --non-interactive
# svn merge http://127.0.0.1/svn/repo1/project-trunk/branches/feature-1 wc-trunk2 --username admin --password q1w2e3r4 --non-interactive
--- Merging r7 through r8 into 'wc-trunk2':
A wc-trunk2/feature.txt
--- Recording mergeinfo for merge of r7 through r8 into 'wc-trunk2':
U wc-trunk2
# svn status wc-trunk2
M wc-trunk2
A + wc-trunk2/feature.txt
# svn commit -m "merge feature-1 into trunk" wc-trunk2 --username admin --password q1w2e3r4 --non-interactive
Adding wc-trunk2/feature.txt
Transmitting file data .done
Committing transaction...
Committed revision 9.
💡 Subversion 的分支就是轻量目录 copy(服务端只存引用,近乎零成本);合并信息记录在 svn:mergeinfo 属性里,
svn merge自动写入,后续重复 merge 会自动跳过已合并区间。
4.5 svn 客户端:锁与凭据、工作副本修订号
# echo locktest > lock-demo.txt
# svn add lock-demo.txt
A lock-demo.txt
# svn commit -m "add lock demo file" --username admin --password q1w2e3r4 --non-interactive
Adding lock-demo.txt
Transmitting file data .done
Committing transaction...
Committed revision 10.
# svn lock lock-demo.txt -m "hold for release" --username admin --password q1w2e3r4 --non-interactive
'lock-demo.txt' locked by user 'admin'.
# svn unlock lock-demo.txt --force --username admin --password q1w2e3r4 --non-interactive
'lock-demo.txt' unlocked.
# svnversion
8:10
凭据缓存查看:
# svn auth --username admin --password q1w2e3r4 --non-interactive
------------------------------------------------------------------------
Credential kind: svn.simple
Authentication realm: <http://127.0.0.1:80> Subversion Repository
Username: admin
------------------------------------------------------------------------
Credential kind: svn.simple
Authentication realm: <svn://127.0.0.1:3690> repo1
Username: admin
4.6 svnadmin:建库、校验、备份与恢复
# svnadmin create /srv/svn/repo1
# svnadmin verify /srv/svn/repo1
* Verifying metadata at revision 0 ...
* Verifying repository metadata ...
* Verified revision 0.
* Verified revision 1.
* Verified revision 2.
* Verified revision 3.
* Verified revision 4.
* Verified revision 5.
dump 全量备份与 load 恢复(实测):
# svnadmin dump -q /srv/svn/repo1 > /tmp/repo1.dump
# ls -lh /tmp/repo1.dump
-rw-r--r-- 1 root root 3.4K Oct 12 00:50 /tmp/repo1.dump
# svnadmin dump /srv/svn/repo1 -r 1:2 | head -12
SVN-fs-dump-format-version: 2
UUID: 733533be-a0e7-445c-904e-d11967ae5c52
Revision-number: 1
Prop-content-length: 114
Content-length: 114
K 10
svn:author
V 5
admin
# svnadmin create /srv/svn/repo2
# svnadmin load /srv/svn/repo2 < /tmp/repo1.dump
<<< Started new transaction, based on original revision 1
* adding path : project-trunk ... done.
(中略)
------- Committed revision 4 >>>
<<< Started new transaction, based on original revision 5
* editing path : project-trunk/trunk/README.md ... done.
------- Committed revision 5 >>>
💡 增量备份用
svnadmin dump -r 上次:本次 --incremental;配套脚本 svn-backup-dumps、svn-hot-backup(subversion-tools 提供)可直接对运行中的库做滚动备份。
锁的查看:
# svnadmin lslocks /srv/svn/repo1
Path: /project-trunk/trunk/lock-demo.txt
UUID Token: opaquelocktoken:3db2bcea-5289-4826-b269-6fe0dfb77188
Owner: admin
Created: 2026-10-12 00:51:44 +0000 (Mon, 12 Oct 2026)
Expires:
Comment (1 line):
hold for release
4.7 svnlook:hook 脚本与只读检查
# svnlook tree /srv/svn/repo1
/
project-trunk/
branches/
feature-1/
README.md
app.conf
feature.txt
release-1.0/
README.md
app.conf
tags/
trunk/
README.md
app.conf
(其余略)
# svnlook info /srv/svn/repo1 -r 9
admin
2026-10-12 00:50:43 +0000 (Mon, 12 Oct 2026)
26
merge feature-1 into trunk
# svnlook changed /srv/svn/repo1 -r 9
_U project-trunk/trunk/
A project-trunk/trunk/feature.txt
svnlook info 输出四行依次为:作者、日期、日志字节数、日志内容。svnlook changed 标记:A 增、U 改、D 删,第二列 _/+ 表示属性变化。
典型 post-commit 钩子(把每次提交归档到日志):
#!/bin/bash
REPOS="$1"
REV="$2"
{
echo "==== $(date "+%F %T") commit r$REV ===="
echo "author: $(svnlook author $REPOS -r $REV)"
echo "log : $(svnlook log $REPOS -r $REV)"
echo "changed:"
svnlook changed $REPOS -r $REV
} >> /var/log/svn/post-commit.log 2>&1
chmod +x 后实测提交触发,/var/log/svn/post-commit.log 内容:
==== 2026-10-12 00:50:05 commit r4 ====
author: admin
log : commit to trigger post-commit hook
changed:
U project-trunk/trunk/README.md
4.8 svnsync:镜像库热备
前置:目标库必须存在 pre-revprop-change 钩子,否则初始化报错(实测):
# svnsync init file:///srv/svn/repo3 file:///srv/svn/repo1
svnsync: E165006: Repository has not been enabled to accept revision propchanges;
ask the administrator to create a pre-revprop-change hook
创建钩子(放行修订版属性修改):
cat > /srv/svn/repo3/hooks/pre-revprop-change <<'EOF'
#!/bin/bash
REPOS="$1"
REV="$2"
USER="$3"
PROPNAME="$4"
ACTION="$5"
exit 0
EOF
chmod +x /srv/svn/repo3/hooks/pre-revprop-change
初始化并执行同步(实测回显):
# svnsync init file:///srv/svn/repo3 file:///srv/svn/repo1
Copied properties for revision 0.
# svnsync sync file:///srv/svn/repo3
Transmitting file data .
Committed revision 10.
Copied properties for revision 10.
# svn list file:///srv/svn/repo3/project-trunk
branches/
tags/
trunk/
💡 后续增量同步重复执行
svnsync sync file:///srv/svn/repo3即可,可挂 cron 定时跑;镜像库只读,不要在镜像库上直接提交。
4.9 svndumpfilter 与 svnrdump
svndumpfilter 从 dump 流里剔除指定路径(可用于裁剪迁移):
# svnadmin dump -q /srv/svn/repo1 | svndumpfilter exclude /project-trunk/branches
Excluding prefixes:
'/project-trunk/branches'
SVN-fs-dump-format-version: 2
UUID: 733533be-a0e7-445c-904e-d11967ae5c52
svnrdump 直接对 URL 远程导出(无需登录库所在服务器磁盘):
# svnrdump dump file:///srv/svn/repo1 | head -4
SVN-fs-dump-format-version: 3
UUID: 733533be-a0e7-445c-904e-d11967ae5c52
授权结果查询(svnauthz):
# svnauthz accessof --username admin --path / /etc/svn/authz
rw
五、注意事项
- 提交必须带
-m说明或配置编辑器(SVN_EDITOR);空说明在生产环境通常被 pre-commit 钩子拦截。 --non-interactive与--username/--password一起用于脚本;交互环境凭据会按 /etc/subversion/config 的 store-auth-creds(默认 no)决定是否缓存。- 工作副本是混合修订版状态:
svn info显示的 Revision 是"该目录最后更新的修订号",不等于库内最新版本,需要最新视图先svn update。 - svnadmin dump/load 期间应停写(或用 --incremental 在低峰做增量),svnsync 则可对运行中的库做同步。
- 钩子脚本以服务运行用户执行(svnserve 为 svn,Apache 为 www-data),注意脚本可执行位与日志目录写权限。
- 26 个工具中 svn/svnadmin/svnlook/svnsync/svndumpfilter/svnrdump/svnversion/svnauthz 覆盖绝大多数运维场景,其余按需查阅
工具名 --help。
六、常见问题(FAQ)
Q1:svn: E170001: Can't get username or password?
服务端 anon-access = none 时未带凭据即报此错(svn:// 实测回显)。解决:命令加 --username admin --password q1w2e3r4,或服务端放开匿名读。
Q2:svn: E215004: No more credentials or we tried too many times. Authentication failed?
用户名或口令错误,客户端重试耗尽(http:// 与 svn:// 均实测出现该回显)。解决:核对账号,必要时重置 htpasswd/passwd 中的口令。
Q3:svn: E165001: Commit blocked by pre-commit hook (exit code 1) with output: Commit blocked: log message must not be empty?
pre-commit 钩子拒绝空说明,属服务端策略(实测拦截与补说明后正常入库)。解决:带有效 -m 重新提交。
Q4:svn: E165006: Repository has not been enabled to accept revision propchanges?
svnsync 初始化时目标库缺少 pre-revprop-change 钩子(实测回显见 4.8)。解决:按 4.8 创建并 chmod +x 后重试。
Q5:svn: E155007: '...' is not a working copy?
在非工作副本目录执行了需要本地副本的子命令(如不带 URL 的 svn diff/log)。解决:cd 到工作副本内,或改用完整 URL 形式。
Q6:svn add 报 svn: warning: W155010: '...' not found 与 svn: E200009: Could not add all targets because some targets don't exist?
目标文件不存在(实测回显):
# svn add ghost-file.txt
svn: warning: W155010: '/root/work/demo5/wc-demo/ghost-file.txt' not found
svn: E200009: Could not add all targets because some targets don't exist
svn: E200009: Illegal target for the requested operation
解决:先创建文件再 add,或核对路径拼写。另一种同名错误是目标已被版本控制(实测):
# svn add build-notes.txt
svn: warning: W150002: '/root/work/demo5/wc-demo/build-notes.txt' is already under version control
svn: E200009: Could not add all targets because some targets are already versioned
svn: E200009: Illegal target for the requested operation
此时文件已在版本控制中,无需 add,直接提交即可。
七、参考链接
- Apache Subversion 官方站点:http://subversion.apache.org/
- 官方文档(Version Control with Subversion,命令参考):http://svnbook.red-bean.com/
- svn 命令速查(子命令 help):
svn help <subcommand>、svnadmin help、svnlook help - subversion-tools 脚本说明:https://packages.ubuntu.com/jammy/subversion-tools