可通过subversion pre-commit钩子脚本禁止删除trunk、tags/release-*等受保护路径:解析svnlook changed输出,匹配d操作及保护路径模式,命中则报错退出。

可以通过 Subversion 的 pre-commit 钩子脚本,在提交前检查变更路径,对试图删除主线(如 trunk)或核心标签(如 tags/release-*)的操作直接拒绝,从而实现禁止删除。
明确受保护的路径模式
先确定哪些路径不允许被删除。常见需保护的路径包括:
-
trunk/(主线开发目录) -
tags/或特定标签前缀,如tags/release-、tags/v[0-9].* - 可选:
branches/support-*等长期维护分支
注意:SVN 中“删除”操作在提交日志中体现为 delete 类型的变更(可通过 svnlook changed -t $TXN $REPOS 获取),不是文件内容变化,而是路径状态变更。
编写 pre-commit 钩子拦截删除操作
钩子需解析本次提交的所有变更,识别出类型为 D(deleted)且路径匹配保护规则的条目。示例 Bash 脚本逻辑如下:
- 用
svnlook changed -t $TXN $REPOS获取变更列表 - 逐行提取操作类型(首列)和路径(第二列)
- 对每个
D操作,用case或正则判断路径是否匹配保护模式 - 一旦命中,输出错误信息并
exit 1中断提交
例如匹配 trunk/ 删除:[[ "$path" == "trunk" || "$path" == "trunk/" || "$path" == "trunk/*" ]] && { echo "ERROR: Deleting trunk is not allowed." >&2; exit 1; }
标签路径建议用 [[ $path =~ ^tags/release-[0-9]+\.[0-9]+\.?[0-9]*$ ]] 等更严谨的匹配。
注意路径匹配的边界与精度
SVN 的 changed 输出中,路径是相对于仓库根的相对路径,不带前导斜杠;且删除整个目录时,只列出该目录本身(如 D tags/release-1.2.0),不会递归列出子项。
- 避免写成
tags/release-*这种 shell 通配——应使用[[ $path = tags/release-* ]]或正则 - 区分
tags/release-1.2(目录)和tags/release-1.2/(带斜杠)——实际输出通常无尾部斜杠 - 若允许删除非保护标签(如
tags/temp-*),需在匹配逻辑中排除,而非一概禁止tags/
测试与部署要点
钩子脚本需赋予可执行权限(chmod +x pre-commit),放在仓库 hooks/ 目录下,并确保运行用户(通常是 svn 或 www-data)有权限读取仓库和执行脚本。
- 本地用
svn commit --no-auth-cache --username test --password xxx模拟提交测试 - 重点验证:删除
trunk、重命名trunk(本质是 delete+add)、删除单个 tag 目录 - 日志输出到
&2,确保错误信息能被客户端看到
不复杂但容易忽略细节。











