如何编程设置SVN自定义属性实现RCS风格单文件自增版本号追踪
SVN单文件RCS风格版本号实现方案
实现逻辑说明
- 采用服务端
pre-commithook实现,比客户端hook可靠性高,强制生效不会被用户绕过,适合文档版本追溯的合规要求 - 新增SVN自定义属性
rcs-style-version存储单文件的RCS格式版本号,和SVN自带的全局仓库版本号完全独立,互不干扰 - 提交时自动遍历本次事务内的所有变更文件,按规则处理:
- 首次纳入追踪的纯文档文件:自动初始化版本号为
1.1 - 已存在版本记录的修改文件:拆分原有版本号,次版本号+1,例如
1.3自动升级为1.4 - 删除、移动、权限变更类操作不触发版本号更新
- 首次纳入追踪的纯文档文件:自动初始化版本号为
- 通过文件后缀白名单筛选需要追踪的纯文档文件,代码、配置类非文档文件不会被处理
Shell实现方案(无额外依赖)
该方案不需要安装任何额外环境,SVN服务端默认自带bash、svnlook、svnadmin工具即可运行,适合快速部署。
将以下代码保存到对应SVN仓库的hooks/pre-commit路径下,赋予可执行权限chmod 755 pre-commit即可:
#!/bin/bash REPOS="$1" TXN="$2" # 配置项:自定义属性名、需要追踪的文档后缀白名单 SVN_PROP_NAME="rcs-style-version" DOC_SUFFIX=("txt" "md" "rst" "doc" "docx" "pdf" "xls" "xlsx" "ppt" "pptx") svnlook changed -t "$TXN" "$REPOS" | while read -r status path; do # 跳过非新增/修改类操作 if [[ "$status" != "U" && "$status" != "A" ]]; then continue fi # 校验文件后缀是否在白名单内 suffix="${path##*.}" is_doc=0 for s in "${DOC_SUFFIX[@]}"; do if [[ "${s,,}" == "${suffix,,}" ]]; then is_doc=1 break fi done [[ $is_doc -eq 0 ]] && continue # 读取已有版本号 old_ver=$(svnlook propget -t "$TXN" "$REPOS" "$SVN_PROP_NAME" "$path" 2>/dev/null) new_ver="1.1" if [[ "$old_ver" =~ ^([0-9]+)\.([0-9]+)$ ]]; then new_ver="${BASH_REMATCH[1]}.$((BASH_REMATCH[2] + 1))" fi # 写入新版本号到事务 svnadmin pset -t "$TXN" "$REPOS" "$SVN_PROP_NAME" "$new_ver" "$path" >/dev/null 2>&1 if [[ $? -ne 0 ]]; then echo "Error: 为文件 $path 设置RCS版本号失败" >&2 exit 1 fi done exit 0
Perl实现方案(兼容性更强)
绝大多数SVN服务端默认预装Perl环境,不需要额外申请安装,对特殊字符、带空格路径的处理比Shell更稳定,适合对版本号校验要求更高的场景。
将以下代码保存到对应SVN仓库的hooks/pre-commit路径下,赋予可执行权限chmod 755 pre-commit即可:
#!/usr/bin/perl use strict; use warnings; my ($repos, $txn) = @ARGV; my $prop_name = 'rcs-style-version'; # 配置项:需要追踪的文档后缀白名单 my %doc_suffix = map { lc($_) => 1 } qw(txt md rst doc docx pdf xls xlsx ppt pptx); open(my $chg_fh, "-|", "svnlook", "changed", "-t", $txn, $repos) or die "无法获取提交变更列表: $!"; while (<$chg_fh>) { chomp; my ($status, $path) = split /\s+/, $_, 2; next unless $status =~ /^[AU]$/; my ($suffix) = $path =~ /\.([^.]+)$/; next unless $suffix && exists $doc_suffix{lc($suffix)}; # 读取已有版本号 my $old_ver = ''; if (open(my $prop_fh, "-|", "svnlook", "propget", "-t", $txn, $repos, $prop_name, $path)) { chomp($old_ver = <$prop_fh>); close($prop_fh); } my $new_ver = "1.1"; if ($old_ver =~ /^(\d+)\.(\d+)$/) { $new_ver = sprintf("%d.%d", $1, $2+1); } # 写入新版本号 system("svnadmin", "pset", "-t", $txn, $repos, $prop_name, $new_ver, $path); if ($? != 0) { print STDERR "Error: 为文件 $path 设置RCS版本号失败\n"; exit 1; } } close($chg_fh); exit 0;
部署与使用说明
- 两个脚本二选一即可,脚本内的文档后缀白名单可根据基金会实际使用的文档格式自行增删
- 版本号默认主版本固定为1,次版本随文件修改递增;如果需要手动升级主版本(例如大改版升级到2.1),只需手动给对应文件设置
rcs-style-version属性为2.0,后续提交会自动从2.1开始递增 - 历史存量文档补录初始版本,只需批量执行
svn propset rcs-style-version 1.1 文件路径提交即可,后续修改会自动递增 - 查询文件当前RCS版本号,直接执行
svn propget rcs-style-version 文件名即可,不需要特殊权限 - 所有逻辑在服务端强制执行,客户端不需要做任何配置,不会出现用户本地跳过规则导致版本号漏记的问题
内容的提问来源于stack exchange,提问作者gsl
相关产品推荐
相关产品推荐

