news 2026/10/24 12:22:49

银河麒麟内网SVN 1.8.14源码编译与svnserve配置实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
银河麒麟内网SVN 1.8.14源码编译与svnserve配置实战

简介:面向银河麒麟(国产 Linux)服务器运维人员与研发环境搭建者的实践文档,聚焦内网或离线场景下从源码编译安装 Subversion 及其依赖组件的完整流程,帮助读者解决系统软件源缺失、自带版本偏旧导致 SVN 难以直接部署的问题。资源为 docx 文档,压缩包内共 1 个文件,约 202KB,篇幅紧凑、按操作顺序编排,可直接对照执行。内容覆盖 apr、apr-util、sqlite-amalgamation 与 subversion 指定版本的获取途径及 configure、make 编译参数,/etc/profile 环境变量追加与 source 生效验证,版本库根目录规划与 svnadmin create 建库,以及 svnserve.conf、passwd、authz 三个配置文件的具体写法,并特别提示首行顶格等易被忽略的配置错误;此外还给出 svnserve 后台启动命令与写入 rc.local 实现开机自启的脚本做法。目前已有 2798 人学习下载,适合需要快速在麒麟系统上落地 SVN 服务、规避权限与路径问题的读者参考。

1. 内网机器上的版本库:为什么我坚持源码编 subversion-1.8.14

内网里那台银河麒麟服务器,长期被当成共享盘用,同事在文件名后缀里写_final_v3_改,改回滚只能靠翻聊天记录。银河麒麟 SVN 环境这件事,真正难的不是svnserve那几行命令,而是发行版自带源里的 subversion 常常缺胳膊少腿:svnadmin能跑,svnserve起来就报共享库找不到,或者版本对不上 sqlite。我一般走源码路线,把 apr-1.6.5、apr-util-1.6.1、subversion-1.8.14 和 sqlite-amalgamation-3071501 一起落到/usr/local,好处是版本可控、依赖不污染系统、出问题删目录就干净了。这套做法适合在内网替小团队搭版本库、又不想动系统包管理的运维和开发。

2. 依赖三板斧:apr、apr-util、sqlite 的编译顺序与参数

2.1 为什么 subversion 1.8 绕不开 apr 和 apr-util

Subversion 从诞生那天起就把 APR(Apache Portable Runtime)当成底座,svnserve的网络监听、内存池、文件路径处理全部走 APR 的接口;apr-util则在 APR 之上补了数据库抽象、XML 解析、Base64 编码这些能力,subversion 的 DAV 与认证模块会用到它。也就是说,你编出来的svnserve二进制和libapr-1.so、libaprutil-1.so是运行期绑定的,不是静态塞进去就完事。

那为什么不直接yum install apr apr-util subversion了事?两条血泪经验。第一,系统源的 apr 版本是跟着发行版冻结的,可能比 subversion 1.8 需要的还老,或者干脆被别的组件锁死,你动它就可能把系统上别的服务带崩。第二,多数组件编译时默认会去/usr找apr-1-config,一旦它和系统里已有的 apr 混用,编出来的 subversion 在链接期就出现符号冲突,报错信息还特别绕。所以我选择把依赖全部装到独立前缀下,用--with-apr、--with-apr-util精确点名,谁也不污染。这套组合的对应关系是这样的:

组件版本安装前缀在链路里的角色
apr1.6.5/usr/local/apr内存池、文件、网络抽象层
apr-util1.6.1/usr/local/apr-utilXML、编码、数据库抽象,依赖 apr
sqlite amalgamation3071501(3.7.15.1)编进 subversion 源码树版本库工作队列的本地库
subversion1.8.14/usr/local/svnsvnserve、svnadmin、svn 客户端

编译顺序有硬约束:apr → apr-util → subversion。apr-util 的configure要拿 apr 的头文件和apr-1-config脚本,subversion 又要同时拿两者的配置脚本,顺序错了就只能在报错里原地打转。

2.2 目录约定与解压:先把工作区定死

源码包从外部拷进内网机器之后,别急着解压到/usr/local或者家目录乱放。我习惯在一个目录里把所有源码铺开,编译完保留着,日后想换参数重编不用重新传包。原文里用的是/home/dmdba/svn/,这个约定挺好,照抄就行。

# 统一工作目录,所有源码包都放这里 mkdir -p /home/dmdba/svn cd /home/dmdba/svn # 四个包按顺序解压,解压后各自成目录 tar -xzf apr-1.6.5.tar.gz tar -xzf apr-util-1.6.1.tar.gz tar -xzf subversion-1.8.14.tar.gz unzip -q sqlite-amalgamation-3071501.zip # 确认目录都在,避免后面 cd 到不存在的路径 ls -d apr-1.6.5 apr-util-1.6.1 subversion-1.8.14 sqlite-amalgamation-3071501

这段没有技术含量,但省掉了后面一半的「路径写错」类翻车。tar -xzf里的z表示 gzip,unzip是因为 sqlite 的 amalgamation 包给的是 zip 而不是 tar.gz,这一点很多人第一次会顺手敲tar -xzf sqlite-amalgamation-3071501.zip,然后拿到一句 gzip: stdin: not in gzip format。全程用 root 操作,避免make install阶段因为目录权限半途失败、留下半套文件。

2.3 apr-1.6.5:--prefix是唯一必须想清楚的参数

cd /home/dmdba/svn/apr-1.6.5 # 装到独立前缀,不覆盖系统 /usr 下的 apr ./configure --prefix=/usr/local/apr # 并行编译加速,装完检查返回码 make -j"$(nproc)" && make install

--prefix=/usr/local/apr决定了三件事:头文件去/usr/local/apr/include/apr-1,库文件去/usr/local/apr/lib,配置脚本去/usr/local/apr/bin/apr-1-config。后面 apr-util 和 subversion 的--with-apr参数,指的就是这个前缀,不是bin目录也不是include目录。make -j$(nproc)用满核数,apr 本身不大,几秒就完;如果你在虚拟机上碰到virtual memory exhausted之类的报错,把-j降成-j2或者干脆去掉并行,别硬扛。

装完可以立刻验证一下前缀里到底落了什么,这一步比事后 debug 便宜得多:

/usr/local/apr/bin/apr-1-config --version # 应输出 1.6.5 ls /usr/local/apr/lib/libapr-1.so* # 应有 .so 和 .so.0 软链

apr-1-config --version能回出版本号,说明--prefix生效了,后面的组件就能靠这个脚本问出正确的头文件与库路径。

2.4 apr-util-1.6.1:--with-apr必须精确指向前缀

cd /home/dmdba/svn/apr-util-1.6.1 # --with-apr 指向刚装好的 apr 前缀,不能省 ./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr make -j"$(nproc)" && make install

--with-apr=/usr/local/apr是这一章最容易写错的一个参数。如果你省掉它,configure会自己去PATH里找apr-1-config,找到的极可能是系统/usr/bin/apr-1-config,于是 apr-util 一半头文件来自/usr/include、一半来自/usr/local/apr/include,编出来的.so里带着两套符号,等到 subversion 链接时才会以undefined reference to apr_pool_create_ex这类面目出现,排查成本极高。

编译 apr-util 时若报错说找不到 expat,属于常见情况:它的 XML 支持依赖 expat 开发包。常规做法是先把系统侧的头文件补齐再重跑configure:

# 麒麟系统一般自带 yum,新版可能是 dnf 的软链,两者都试一下 yum install -y expat-devel zlib-devel openssl-devel # 装完清掉上次的 configure 缓存重新来 cd /home/dmdba/svn/apr-util-1.6.1 && make clean ./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr make -j"$(nproc)" && make install

装完同样验一遍,/usr/local/apr-util/bin/apu-1-config --version要能回出版本,且ldd出来的 apr-util 库文件指向的是/usr/local/apr/lib/libapr-1.so.0而不是/usr/lib64下的同名文件。

2.5 sqlite amalgamation:唯一不需要 configure 的依赖

sqlite 的 amalgamation 包不是常规的 autotools 工程,解压出来只有一个sqlite3.c加一个sqlite3.h(老版本包里还有shell.c),没有configure也没有Makefile。它在 subversion 1.8 的构建体系里扮演的是「源码级依赖」的角色——subversion 自己的构建脚本会去找源码根目录下的sqlite-amalgamation子目录,把sqlite3.c直接编进libsvn_subr。

所以正确的落地方式不是单独编译安装,而是把它放进 subversion 源码树:

cd /home/dmdba/svn # 目录名必须是 sqlite-amalgamation,subversion 的构建脚本按这个约定找 mv sqlite-amalgamation-3071501 sqlite-amalgamation cp -r sqlite-amalgamation subversion-1.8.14/ # 确认关键文件在位 ls subversion-1.8.14/sqlite-amalgamation/sqlite3.c

目录名这一条是实打实的坑:你叫sqlite-amalgamation-3071501,configure 阶段不报错,make到了链接svnserve的时候才给你一句找不到sqlite3_open之类的符号。因为前面 configure 只是「没检测到自带 sqlite」,于是它转头去找系统里已安装的 sqlite3 库,系统的版本又可能不满足 1.8 分支的要求,报错就发生在很靠后的位置。改成约定的名字,等于把这条路走通。

3. 编 subversion-1.8.14:configure 参数与报错的对应关系

3.1 configure 之前先确认三件事

第一件是编译器与构建工具。银河麒麟桌面版和服务器版默认不一定装gcc,最小化安装的系统经常只带gcc-c++或干脆没有。

# 逐个确认,缺什么装什么 gcc --version | head -1 make --version | head -1 # 一次性补齐编译期依赖,避免 configure 反复中断 yum install -y gcc make zlib-devel expat-devel openssl-devel

第二件是/usr/local的写权限和磁盘空间。/usr/local单独挂载且配额很小的机器不是没见过,装到一半No space left on device,前面 apr、apr-util 全要重来。df -h /usr/local看一眼,几十兆就够,但心里有数。

第三件是系统里有没有装过 subversion。如果之前yum install subversion过,/usr/bin/svn和/usr/local/svn/bin/svn会同时存在,PATH里谁在前谁生效,日后运维时会莫名其妙调用到旧版。要么先卸掉系统包,要么在/etc/profile里把/usr/local/svn/bin放在PATH前面,别用PATH=$PATH:...的追加写法。

3.2 configure 参数逐项拆:每个--with都指向一个具体前缀

cd /home/dmdba/svn/subversion-1.8.14 ./configure \ --prefix=/usr/local/svn \ --with-apr=/usr/local/apr \ --with-apr-util=/usr/local/apr-util \ --without-serf

--prefix=/usr/local/svn决定最终的bin、lib、include落点,svnserve、svnadmin、svnlook、svn全部装到/usr/local/svn/bin。

--with-apr和--with-apr-util分别指向两个前缀,configure 会去<前缀>/bin下找apr-1-config、apu-1-config,问出头文件与库的准确路径。这两个参数写错一个字符,configure 就会退回系统默认路径,编出来的东西在运行期报共享库版本不匹配。

--without-serf这一项要看你的用途。serf 是 HTTP/DAV 协议的客户端库,svn走http://、https://访问远端仓库时才需要。本文这套环境只做svn://的 svnserve,加上它反而要多装一个依赖,直接关掉最省事。不写这个参数也不会编不过,configure 检测不到 serf 只是打一行警告然后禁用,但那行警告埋在几十行输出里,容易被忽略。

至于 sqlite,如果你已经按 2.5 把目录塞进源码树,configure 会自动接管,输出里能看到它采用内置的 sqlite3.c。个别版本识别不到时,可以显式指定源码目录:

# 备选:自动识别失败时显式指定 sqlite 源码目录 ./configure --prefix=/usr/local/svn \ --with-apr=/usr/local/apr \ --with-apr-util=/usr/local/apr-util \ --with-sqlite=/home/dmdba/svn/subversion-1.8.14/sqlite-amalgamation \ --without-serf

configure 输出最后会打印一份摘要,重点看三行:APR的版本与前缀、APR-UTIL的版本与前缀、SQLite的来源是internal还是系统路径。三行都对上你再敲 make,对不上现在改还来得及。

3.3 make 阶段:报错位置决定了排查方向

cd /home/dmdba/svn/subversion-1.8.14 # 并行编译,失败先看最后一个 error 而不是第一个 warning make -j"$(nproc)" && make install

subversion 的源码体量比 apr 大一个量级,make会跑上几分钟。中途报错时别从头翻,直接看最后一个error:。三类报错各有对应关系:出现cannot find -lsqlite3或undefined reference to sqlite3_*,说明内置 sqlite 没被识别,回 2.5 检查目录名;出现cannot find -lapr-1,说明链接期找不到 apr 的库目录,/usr/local/apr/lib可能没进ld的搜索路径;出现expat.h: No such file,是系统侧expat-devel没装,补装后make clean重来。

make install完成后不要急着建库,先确认二进制本身的依赖是干净的:

# 检查 svnserve 动态链接到哪个 apr,必须是 /usr/local/apr/lib 下的 ldd /usr/local/svn/bin/svnserve | grep -E 'apr|sqlite' # 若输出里指到 /usr/lib64/libapr-1.so.0,说明前缀没被 ld 找到

这个ldd是整套流程里最有价值的一条自检命令。它把「编译期正确」和「运行期正确」分开暴露——编译通过不代表运行期能找到库,找不到的那一刻通常发生在svnserve -d启动时,报error while loading shared libraries: libapr-1.so.0。

3.4 环境变量与库搜索路径:两处都要配

先解决库路径,再解决命令路径。库路径靠ldconfig的配置文件,比改LD_LIBRARY_PATH更可靠,因为它对 systemd 拉起的进程同样生效。

# 把两个前缀的 lib 目录登记进动态链接器 cat > /etc/ld.so.conf.d/svn-deps.conf <<'EOF' /usr/local/apr/lib /usr/local/apr-util/lib /usr/local/svn/lib EOF ldconfig

再配命令路径。原文用vim /etc/profile手工追加,我用 heredoc,好处是可重复执行不会写重复行,也避免 vim 里手滑删掉别的行。

# 用 heredoc 追加,PATH 前置保证 /usr/local/svn/bin 优先 cat >> /etc/profile <<'EOF' # subversion 1.8.14 源码安装 export PATH=/usr/local/svn/bin:$PATH EOF # 当前会话立即生效 source /etc/profile

PATH写在前面而不是$PATH:后面,是为了压过可能存在的/usr/bin/svn。改完执行source只是让当前 shell 生效,新开的 SSH 会话会自动读/etc/profile,这一点在排错时要记牢:你改了文件却没重登,报了command not found,别急着重装。

验证环节用三条命令交叉确认,比单跑--version靠谱:

命令期望输出说明
which svnserve/usr/local/svn/bin/svnserve确认 PATH 生效,不是系统旧版
svnserve --version版本号 1.8.14确认二进制能加载全部动态库
svnadmin --version版本号 1.8.14建库工具与 svnserve 同源

svnserve --version能出来,说明动态库、PATH、前缀三者全对,这套编译就算真正完成了。出不来就看报错是「找不到命令」还是「找不到共享库」——前者是 PATH 问题,后者是 3.4 上半段ldconfig的问题。

4. 建库与三件套配置:svnserve.conf、passwd、authz 的权限模型

4.1svnadmin create之后目录里到底是什么

# 版本库根目录,注意这里只是容器,不是仓库本身 mkdir -p /home/svn # 项目目录先建好,再对其执行 create mkdir -p /home/svn/project svnadmin create /home/svn/project # 看一下生成了什么 ls /home/svn/project

svnadmin create会在一秒内铺出一整套骨架,认清楚每个目录的职责,后面配置时才不会改错地方:

路径作用要不要动
conf/svnserve.conf、passwd、authz 三个配置文件必须改
db/版本库的真实数据,Berkeley DB 或 FSFS 存储只备份,不手改
hooks/提交前后触发的钩子脚本模板按需启用
locks/进程锁与数据库锁不动
format版本库存储格式的版本号不动
README.txt结构说明可读可不读

这里有个容易混淆的点:/home/svn是版本库的根目录(后面svnserve -d -r指向它),/home/svn/project才是一个真正的版本库。一个根目录下可以放多个版本库,svnserve -r /home/svn之后,客户端用svn://IP/project访问其中一个,用svn://IP/another访问另一个,互不干扰。

4.2 svnserve.conf:配置项必须顶格写

这个文件的格式极其挑剔:[general]段落下的键值对必须从行首开始,前面多一个空格,svnserve启动时就给你一句svnserve.conf:20: Option expected。原文特别强调「首行不可以留空,要顶行」,说的就是这件事——行首空白比空行更容易翻车。

[general] # 匿名用户无任何权限,必须登录 anon-access = none # 认证用户可读可写 auth-access = write # 密码文件,相对 conf 目录 password-db = passwd # 权限文件,相对 conf 目录 authz-db = authz # 认证域,客户端缓存凭据时按这个区分 realm = project

四个参数里,anon-access = none和auth-access = write决定认证前后的能力边界:把anon-access设成read,等于全网能读到你的代码,内网也一样别这么干。password-db和authz-db写相对路径时,基准是conf目录本身,不是当前工作目录,也不是版本库根目录;写绝对路径也能用,但日后整体搬迁版本库就要改配置,不如相对路径省心。realm是给客户端看的认证域名字,同一个realm下的多个仓库共用一份凭据缓存,不同realm会各弹一次登录框,多项目场景下按项目名区分更清晰。

改这个文件用vi就行,注意svnserve.conf里原有的注释行(以#开头)留着不碍事,只要把需要的项取消注释并顶格。改完别急着启动,先跑一次语法体检:

# 用 svnserve 自己做一次启动预演,报错会直接指出行号 svnserve -d -r /home/svn --foreground # 能正常阻塞在前台说明配置无误,Ctrl+C 退出

--foreground让进程留在前台,配置有错时立刻打印到终端,比后台启动再去翻日志快得多。这个参数不在原文里,但排查配置问题时省的时间最多。

4.3 passwd 与 authz:用户、群组、路径权限的优先级

passwd只做一件事:用户名对密码。格式简单到几乎没有出错空间,真正的风险在别处。

[users] admin = 123456

密码是明文存储的,所以文件权限要收紧:chmod 600 /home/svn/project/conf/passwd,属主保持运行 svnserve 的那个账号。生产环境别用123456这种,改成一个够长的随机串,多人协作就一人一行,别共用 admin。

authz才是权限模型的核心,它支持群组、路径、读写分离三层。

[groups] # 管理员组,成员 admin g_admin = admin # 版本库根目录的权限 [/] @g_admin = rw * = # 若只想给某个子目录更细的权限,路径写全 [/docs] @g_admin = rw * = r

三个语法点必须说清楚。[/]表示版本库根目录,不是某个叫 trunk 的目录,很多人被「trunk」这个词带偏,写成[/trunk]结果根目录反而没人有权限。@g_admin = rw里的@表示引用群组,去掉@就变成用户g_admin,而它根本不存在,权限自然不生效。* =等号后留空表示「无任何权限」,注意别写成* = r,那就成了全员可读。

优先级规则记两条就够用:路径越具体优先级越高,所以[/docs]的规则会覆盖[/]里的同名设置;同一路径下,针对单个用户的条目优先于群组条目。也就是说给admin单独写一行admin = rw,会盖过@g_admin的设定。改完 authz 不需要重启 svnserve,下一次客户端请求就会读到新配置,这一点比很多服务都友好。

4.4 启动与客户端验证:-d -r两个参数的含义

# -d 后台运行,-r 指定版本库根目录,路径到 /home/svn 为止 svnserve -d -r /home/svn # 确认进程在 ps -ef | grep svnserve | grep -v grep # 确认 3690 端口在监听 ss -lntp | grep 3690

-r的路径只到/home/svn,不要写成/home/svn/project。写成后者的话,客户端地址就变成svn://IP/而不是svn://IP/project,两个项目共用一个 svnserve 也就无从谈起。这是新手最常犯的一个配置错误,表现是「服务明明在跑,checkout 却报仓库不存在」。

客户端访问地址按svn://服务器地址/项目名拼,例如内网地址是192.168.10.20,就写:

# Linux 客户端验证,先看 info 再 checkout svn info svn://192.168.10.20/project svn checkout svn://192.168.10.20/project ./project --username admin

Windows 侧用任意 SVN 客户端填同一个地址即可,首次连接会弹认证框,输admin和对应密码。想快速确认权限是否按预期生效,用svn ls试读、用一个新提交试写,两步就能把 read 和 write 分开验证,比翻配置文件快。

5. 避坑与排查:五条踩过的坑,每条都有现场

5.1 首行留空或键前有空格,svnserve 直接拒绝启动

现象:svnserve -d -r /home/svn敲下去没反应,ps里也没有进程,前台跑会打印svnserve.conf:12: Option expected。

原因:svnserve.conf的解析器要求配置项顶格,行首空白会被当成非法续行;空行本身在多数版本里是容忍的,但行首空格一定会翻车。原文提醒的「首行不可以留空」,落到实操就是别让任何一行配置前面带缩进。

解决:grep -n '^[[:space:]]' conf/svnserve.conf把所有带前导空白的行列出来,逐行顶格。改完用svnserve -d -r /home/svn --foreground预演一次,能正常阻塞再放后台。

5.2 make 到链接阶段才报 sqlite 符号找不到

现象:configure一路绿灯,make跑到后半段突然undefined reference to sqlite3_open_v2。

原因:sqlite 的 amalgamation 目录名不是 subversion 构建脚本约定的sqlite-amalgamation,configure 判定为「无内置 sqlite」,转去找系统库,系统里又没有可链接的 sqlite3 开发文件,于是链接失败。

解决:回到源码树ls subversion-1.8.14/sqlite-amalgamation/sqlite3.c,目录名不对就改名,然后make clean重跑 configure。不要试图用--with-sqlite指向原始解压目录名,保持约定命名最省事。

5.3 编译通过、启动报找不到 libapr-1.so.0

现象:svnserve --version报error while loading shared libraries: libapr-1.so.0: cannot open shared object file。

原因:apr 装在/usr/local/apr/lib,这个路径没进动态链接器的搜索范围,编译期的-L只影响链接,不影响运行期加载。

解决:在/etc/ld.so.conf.d/下新建配置文件写入/usr/local/apr/lib和/usr/local/apr-util/lib,执行ldconfig。临时应急可以用LD_LIBRARY_PATH,但开机自启的脚本和 systemd 服务读不到你 shell 里的变量,所以别把它当长期方案。

5.4 客户端认证一直失败,密码明明是对的

现象:svn checkout反复弹认证框,输admin和密码始终提示认证失败,服务端没有任何日志。

原因:多数的锅在authz。[groups]里写了g_admin = admin,但权限段里漏了@,写成g_admin = rw,解析器认为你在给一个名叫g_admin的用户授权,而这个用户不存在,于是所有人被* =挡在门外。

解决:检查authz里群组引用是否带@;再把svnserve.conf里的realm写上项目名,避免客户端拿旧凭据反复重试。客户端侧清一下本地凭据缓存(删掉~/.subversion/auth)再试。

5.5 重启机器后 svnserve 不见了

现象:手工启动正常,重启服务器后ps -ef | grep svnserve空空如也。

原因:svnserve -d是一次性命令,没有注册成服务。原文用/etc/rc.d/rc.local挂脚本,前提是那个脚本本身有可执行权限,且脚本里用的是svnserve的绝对路径——开机时/etc/profile里的 PATH 往往还没被非登录 shell 加载。

解决:脚本里写/usr/local/svn/bin/svnserve -d -r /home/svn,chmod +x脚本本身,再确认rc.local有执行权限。更彻底的做法是写一个 systemd unit,见下一章。

6. 开机自启与备份:让这套环境能扛住下一次重启

6.1 两种自启写法,选一个就别混用

rc.local的路子最直白,适合不想碰 systemd 的老机器:

# 自启脚本,路径与参数都用绝对路径,别指望 PATH cat > /root/svn.sh <<'EOF' #!/bin/bash # 绝对路径启动,开机阶段环境变量尚未加载 /usr/local/svn/bin/svnserve -d -r /home/svn EOF chmod 755 /root/svn.sh # 挂到 rc.local 末尾,注意该文件本身要有执行权限 echo '/root/svn.sh' >> /etc/rc.d/rc.local chmod +x /etc/rc.d/rc.local

较新的发行版默认不执行rc.local,这时候写 unit 更靠谱:

# /etc/systemd/system/svnserve.service [Unit] Description=Subversion Protocol Daemon After=network.target [Service] Type=forking ExecStart=/usr/local/svn/bin/svnserve -d -r /home/svn Restart=on-failure [Install] WantedBy=multi-user.target
systemctl daemon-reload systemctl enable --now svnserve systemctl status svnserve --no-pager

Type=forking是因为svnserve -d会自己 fork 到后台,用simple会让 systemd 误判主进程已退出,反复重启。

6.2 用 hotcopy 做每日备份并验证

版本库最大的风险不是编译失败,是磁盘写满或误删。svnadmin hotcopy能在不停止服务的前提下拷出一份一致的副本,比cp -r安全得多。

# 每日增量保留 7 天,hotcopy 保证一致性 BACKUP=/home/svnbackup mkdir -p "$BACKUP/$(date +%F)" svnadmin hotcopy /home/svn/project "$BACKUP/$(date +%F)/project" # 备份完立刻验一遍,能 list 出来才算数 svnlook youngest "$BACKUP/$(date +%F)/project"

svnlook youngest输出的是当前最新版本号,这个数字和线上库一致,说明副本完整;报错则说明备份不可用,别等真出事才发现。把它写进 crontab,每天凌晨跑一次,顺手find "$BACKUP" -maxdepth 1 -mtime +7 -exec rm -rf {} \;清旧副本。

这套东西我是被一次磁盘写满教育出来的:当时只做了cp -r,拷到一半空间不足,副本里db/current和db/revs对不上,真要用的时候才发现那份备份根本读不出来。从那以后我每次配完 svnserve,都强制先把 hotcopy 加进 crontab、跑一次svnlook youngest验一遍,再交付给同事用。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/24 12:16:27

C语言课程设计实战:图书管理系统文件读写与链表操作详解

简介&#xff1a;基于C语言的图书管理系统课程设计论文报告&#xff0c;面向高校计算机相关专业学生&#xff0c;可作为课程设计、期末项目或实训报告的参考资料。内容围绕C语言文件操作与链表数据结构&#xff0c;完整呈现从需求分析、系统设计到编码实现的开发流程&#xff0…

作者头像 李华
网站建设 2026/10/24 12:05:10

树莓派双线寻迹实战:OpenCV Python与L298N差速转向

简介&#xff1a;这是一份基于树莓派3B四轮驱动小车、利用OpenCV与Python实现双线寻迹的完整项目设计报告&#xff0c;适合自动化、嵌入式视觉方向的学生与开发者参考学习。内容围绕双线寻迹任务&#xff0c;系统梳理了系统烧录与环境配置、L298N电机驱动转向控制、视觉处理参数…

作者头像 李华
网站建设 2026/10/24 12:00:46

Debian 13 上编译 RT 内核与 IgH EtherCAT 主站实战

1. 为什么要在 Debian 13 上折腾 RT 内核与 EtherCAT 主站工业现场总线这块&#xff0c;EtherCAT 算是这几年的热门选手。它不像传统以太网那样靠 TCP/IP 协议栈层层封装&#xff0c;而是直接在以太网帧上跑自己的协议&#xff0c;靠"飞读飞写"&#xff08;Processin…

作者头像 李华
网站建设 2026/10/24 11:24:12

六路互补PWM实验:死区、相位与刹车保护验证指南

六路互补PWM这六个字&#xff0c;凡是做过电机驱动、三相逆变或者开关电源的人&#xff0c;应该都不陌生。它本质上是给三相全桥或半桥电路的六个开关管生成驱动信号&#xff1a;上桥臂三路PWM&#xff0c;下桥臂三路PWM&#xff0c;上下桥臂一一互补&#xff0c;中间还必须隔出…

作者头像 李华
网站建设 2026/10/24 11:23:51

上下文窗口之外:DeepSeek本地知识库RAG检索链路与故障排查

简介&#xff1a;围绕DeepSeek构建个人与企业本地知识库的PDF文档&#xff0c;面向希望将私有资料接入大模型应用的开发者、企业人工智能建设者与技术选型人员&#xff0c;重点解决检索增强生成原理理解、技术方案比较和落地路径不清的问题。文档从上下文窗口不断扩大的背景切入…

作者头像 李华
网站建设 2026/10/24 11:16:03

基于RA-AF高斯混合模型的声发射裂纹模式识别与Matlab实现

简介&#xff1a;基于 RA-AF 特征的高斯混合聚类裂纹模式识别资料&#xff0c;面向材料力学、声发射检测与工程诊断人员&#xff0c;用于在无需人工划分分界线的前提下&#xff0c;自动区分拉伸裂纹与剪切裂纹。资源以 PDF 文档承载&#xff0c;内含完整 Matlab 实现代码、设计…

作者头像 李华