ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

SVN版本管理服务器搭建全攻略:从安装到权限配置的完整实践

SVN版本管理服务器搭建全攻略:从安装到权限配置的完整实践 最近接了个小团队的项目要把几台Windows开发机和一台Linux服务器统一做版本管理。本来想图省事直接上Git但有个同事是非技术岗Git那套概念对他来说实在太痛苦。后来我干脆在一台HoRain云服务器上把SVN完整搭了一套从服务端安装、仓库创建、权限配置再到客户端TortoiseSVN、IDEA、VSCode全流程都捋了一遍踩了不少坑也总结了不少经验。这篇就把整个安装过程、配置思路和实操中的坑都写下来给需要在云服务器上部署SVN的朋友一个完整参考。SVN虽然年纪不小但在目录级权限控制、锁定机制、非技术同事上手速度这些场景下依然比Git有优势。尤其是那种谁改过哪个目录一目了然按目录给不同人开权限的传统协作模式SVN的表达最直接。这篇攻略会覆盖完整流程适合刚接触SVN的小白也适合准备从零搭建的运维或开发同学当作操作手册来用。1. 整体设计与部署思路1.1 为什么这种场景下仍选择SVN很多人一听版本管理第一反应就是Git但SVN并没有过时。如果你们团队是这种形态开发、测试、产品、运营混在一起甚至还有外包人员——每个人的技术基础参差不齐协作模式又以按目录认领为主SVN往往比Git更划算。我这边选择SVN的核心原因有三点第一目录级的权限控制非常直观。仓库里建好trunk、branches、tags不同角色对不同目录给只读或读写权限一条authz规则就搞定了不需要像Git平台那样建一堆group和project。对于不想把代码权限管得特别细、但又不能全放开的场景SVN的粗粒度反而刚刚好。第二文件锁机制对非技术同事非常友好。SVN的锁是排他锁一个人锁了文件别人就只能只读根本不存在冲突这回事。做文档、素材、配置文件协作时这种机制能让完全不懂版本管理的人避免陷入conflict的泥潭。第三小团队、小项目用SVN维护成本几乎为零。服务端一个svnserve进程就完事不像GitLab那样要吃好几个G内存。HoRain云服务器配置不用太高1核2G跑SVN绰绰有余一年下来成本低得可以忽略。注意我这里不是说Git不好。Git的本地分支、分布式提交在复杂开发流程里确实强大。但工具服务于团队这个原则比工具本身是否流行重要得多。如果团队规模、协作习惯更适合SVN那就果断用没必要为了技术时髦硬迁。1.2 部署方案选型svnserve还是Apachemod_dav_svnSVN在Linux服务端有两种主流部署方式一种是独立的svnserve服务默认监听3690端口另一种是挂在Apache HTTP Server下走http/https协议。这两种我都用过说下我的判断。独立sdsvnserve的方案最大的优点是配置简单、依赖少。装好subversion包svnadmin create建仓库改三个配置文件启动服务完事。客户端连接时用svn://IP/仓库名这种地址清爽直接。缺点是默认的密码认证方式不够安全密码在passwd文件里是明文存的走网络也不加密。适合内网或小团队信任环境。Apache方案则复杂不少要装httpd、mod_dav_svn、mod_authz_svn还要折腾SSL证书但换来的是https加密传输、可以和LDAP/AD集成做统一认证、可以用浏览器直接浏览仓库目录权限模型也更灵活。适合对安全要求高、需要和公司统一账号体系打通的企业场景。我最终选的是sdsvnserve。原因很实际团队人少服务器上跑的东西也少没必要为了一个版本管理工具引入Apache这么重的依赖。如果后续真需要走https或者对接LDAP随时可以迁移仓库数据是通用的换个访问通道而已。1.3 仓库目录结构规划在创建仓库之前先把目录结构想清楚后面能省很多事。SVN社区的标准做法是这样一个三段式结构trunk主干目录日常开发的主战场所有功能最终都要合到这里。branches分支目录放功能分支、发布分支、个人分支。tags标签目录存放每个发布版本的快照打tag后就不允许再改。我见过不少团队把SVN用成了共享网盘所有文件一股脑塞在根目录版本是有了但管理和回溯一塌糊涂。建议从建库第一天就把这个结构建好然后在authz里把根目录默认设成只读只允许trunk和对应分支读写从机制上逼着大家遵守规范。2. 核心细节解析与实操要点2.1 SVN的核心机制理解这些才能排错SVN和Git最大的区别在于集中式三个字。所有历史记录、版本号都集中在服务器仓库里本地工作副本只保留一份当前版本的快照。操作流程是update把服务器最新代码拉到本地改完commit提交到服务器。版本号是全局递增的r1、r2、r3……历史是一条直线没有Git那种分支分叉和DAG的概念。理解了这个模型很多坑就很好解释。比如SVN在commit之前必须先update因为服务器版本比你本地新的时候SVN会拒绝提交逼你先合并别人的改动。这个机制看起来死板但对新手来说反而是保护——它强制要求你每次提交前都同步一次从源头上减少冲突发生的概率。仓库的存储格式我建议就用默认的FSFS。以前还有个BDB后端并发访问不稳定容易锁库现在基本被淘汰了。FSFS是纯文件存储每个版本以文件形式保存在磁盘上备份恢复都很方便。2.2 权限模型与配置文件关系svnserve方案下权限相关的配置集中在仓库目录下的conf文件夹里一共三个文件svnserve.conf服务端主配置控制匿名访问、认证方式、权限配置文件的路径。passwd存用户名和密码。格式是用户名 密码一行为一个账号。authz存授权规则。负责给不同用户或用户组配置目录级别的读写权限。这三个文件的关系一定要理清。svnserve.conf是总开关它决定SVN服务器是否要求认证、读取哪份passwd和authz。passwd解决的是你是谁的问题authz解决的是你能干什么的问题。很多新手配置半天连不上要么是总开关没开认证要么是authz里没给用户任何权限客户端虽然能连上服务器但一访问仓库就报Access denied。注意一点svnserve.conf里的配置项前面不能有空格等号两边倒是可以有空格。这个特性坑过不少人从网上复制配置时尤其容易带出隐藏空格导致服务启动正常但权限全部失效。2.3 权限规则里容易被忽略的几个细节authz的语法看起来简单写起来坑不少。最基本的结构是这样[groups] dev alice, bob qa carol [repo:/] dev rw qa r * [repo:/branches/release1.0] qa rw这里有几个细节容易被忽略。第一个细节是* 这表示其他所有人都没有权限注意等号后面是空的。如果你不写这一行默认其他用户是有读权限的这在某些场景下等于权限泄露。我习惯在根目录写上* 然后逐级放权。第二个细节是权限的就近原则。SVN在判断用户对某个路径的权限时会从被访问路径开始逐级向上找找到匹配规则就用不再向上合并。也就是说子目录的规则会覆盖父目录的规则但覆盖的方向是找到最近一条就停。比如根目录给了dev rw某个子目录你想单独限制某人只读就要在该子目录下单独配一条规则。第三个细节是[repo:/]这种带仓库名的写法。如果你的svnserve用-r参数指定了仓库根目录客户端访问的是svn://IP/仓库名/trunk那么authz里的路径必须以仓库名:/开头而不是直接[/]。这个坑我踩过差一个仓库名整条规则就静默失效。3. 实操过程与核心环节实现3.1 服务器环境准备与安装Subversion我用的这台HoRain云服务器是CentOS 7.x系统2核4G配置跑SVN完全是杀鸡用牛刀但考虑到后续可能还要跑其他服务留点余量没坏处。系统装好后第一步先把系统包更新到最新yum update -y然后安装SVN服务端。CentOS的源里自带subversion不用额外加仓库yum install -y subversion安装完成后验证一下版本svnserve --version如果输出类似svnserve, version 1.7.14 (r1542130)这样的信息说明装好了。Ubuntu/Debian系系统的话安装命令是apt install -y subversion其他步骤完全一样。实操心得这里不要图省事用yum install -y subversion的旧版本就不管了。SVN早期版本有比较严重的安全漏洞就是热词里提到的.svn漏洞新版已经修复。装完后务必确认版本在1.8以上如果发行版自带版本太老建议去官网下载新版本源码编译安装或者找第三方源更新。安全这关不能省。3.2 创建仓库与初始化目录结构我的习惯是统一把SVN数据放在/data/svn目录下这样备份、迁移、权限管理都集中在同一个地方mkdir -p /data/svn cd /data/svn svnadmin create myreposvnadmin create执行后会生成一个myrepo目录里面有conf、db、hooks、locks等子目录。db是真正的版本数据存储目录后面做备份就是要备份整个仓库目录。conf是配置文件目录hooks是钩子脚本目录可以放一些提交后自动同步、自动发邮件的脚本。仓库建好后第一时间把trunk、branches、tags目录结构创建出来。这里有两种方式我推荐先本地建目录再一次性导入mkdir -p /tmp/svn-init/trunk /tmp/svn-init/branches /tmp/svn-init/tags svn import /tmp/svn-init/ file:///data/svn/myrepo -m 初始化目录结构执行完后仓库里就有这三个基础目录了。如果图省事想直接在服务器上建目录也可以svn mkdir file:///data/svn/myrepo/trunk -m 创建trunk但多个目录还是用import一次性完成更方便。3.3 修改三个核心配置文件创建仓库时conf目录下会自动生成svnserve.conf、passwd、authz三个文件的模板。但默认配置基本不能用要逐一修改。先说svnserve.conf最小可用配置是这样的[general] anon-access none auth-access write password-db passwd authz-db authz realm myrepo这里anon-access none表示不允许匿名访问auth-access write表示通过认证的用户有读写权限。password-db和authz-db指定了认证和授权文件。realm是个认证领域名客户端连接时会显示多个仓库共存时建议改成不同的名字方便区分。注意[general]下面每行配置项前面不要加空格。这一点在SVN官方文档里提了很多次但因为配置文件是Python风格解析缩进容易引起误解实际踩坑的人还是很多。如果你改了配置后客户端行为没变化优先检查这里。然后编辑passwd文件添加用户[users] alice 123456 bob 654321密码是明文存储的。如果对安全有要求建议用系统级的SASL认证来加密密码存储。但小团队场景下明文密码配合防火墙和强密码策略也能接受。我自己是在HoRain云安全组里把3690端口限制到只允许办公室IP访问相当于加了一层网络层面的保护。再编辑authz文件配置权限。我这里的典型配置是开发组对trunk有读写权限测试组对tags只读组长对全部目录有完全控制权[groups] admin charlie dev alice, bob qa carol [myrepo:/] admin rw * [myrepo:/trunk] dev rw qa r [myrepo:/branches] dev rw qa r [myrepo:/tags] admin rw dev r qa r这里注意[myrepo:/]前面的仓库名。因为我后面启动svnserve时会用-r /data/svn指定数据根目录客户端访问地址是svn://IP/myrepo/trunk所以authz里必须带myrepo:前缀。如果你把-r指定到仓库一级比如-r /data/svn/myrepo那authz里就用[/]因为客户端看到的根就是仓库本身。这两种风格我建议统一用前者因为多仓库共存时管理最清晰。3.4 启动服务与开机自启配置写好后试启动一下svnserve -d -r /data/svn-d表示以守护进程方式运行-r指定仓库根目录。启动后检查一下进程和端口ps aux | grep svnserve netstat -tlnp | grep 3690如果3690端口已经在监听服务就起来了。但这样启动有个问题服务器一重启svnserve就没了还得手动拉起来。我建议写一个systemd服务开机自动启动vi /etc/systemd/system/svnserve.service内容如下[Unit] DescriptionSubversion Server Afternetwork.target [Service] Typeforking ExecStart/usr/bin/svnserve -d -r /data/svn ExecReload/bin/kill -HUP $MAINPID PIDFile/run/svnserve.pid Restartalways [Install] WantedBymulti-user.target然后执行systemctl daemon-reload systemctl enable svnserve.service systemctl start svnserve.service注意ExecStart里svnserve的路径建议用绝对路径可以先执行which svnserve确认。Typeforking是因为svnserve -d启动后父进程会退出子进程继续运行所以systemd要按forking方式跟踪。3.5 防火墙、安全组与客户端连通性验证服务端起来后客户端能不能连上取决于两件事服务器防火墙是否放行3690端口云平台的安全组是否放行了这个端口。先看服务器防火墙。CentOS 7默认用的firewalldfirewall-cmd --permanent --add-port3690/tcp firewall-cmd --reload然后去HoRain云控制台找到这台服务器所在的安全组添加入方向规则协议TCP端口3690源地址按需填写。我的做法是只允许公司固定IP段访问这样即使svnserve本身密码强度不够外部也扫不到这个端口。放行端口后在本地电脑上试一下连通性。Windows下可以直接在命令行跑telnet 服务器IP 3690如果能看到一个类似svnserve的欢迎信息说明TCP通道已经通了。接下来在本地任意目录执行一次checkout验证完整链路svn co svn://服务器IP/myrepo/trunk会提示输入用户名和密码输入alice账号后如果能看到trunk目录内容整套服务端就彻底OK了。4. 客户端配置与日常使用4.1 TortoiseSVN小乌龟安装与中文语言包Windows下最主流的SVN客户端就是TortoiseSVN因为图标是个小乌龟大家习惯叫小乌龟。下载时一定去官网tortoisesvn.org不要随便在第三方下载站下那些站点捆绑的一堆垃圾软件能折腾死你。安装过程一路Next就行唯一要注意的是安装完成后建议同时装一个同版本的中文语言包。语言包其实是个独立的exe装完后在小乌龟的Settings - Language里选择中文重启资源管理器就生效了。实操心得小乌龟安装时可以选择集成到资源管理器的哪些位置默认全选就行。但如果你装了360之类的软件它会拦截小乌龟的右键菜单注册导致桌面右键看不到SVN选项。碰到这种情况在资源管理器地址栏敲%APPDATA%\TortoiseSVN看看有没有缓存目录有的话手动重启explorer.exe就能恢复。安装完小乌龟后在桌面任意目录右键 - SVN Checkout输入svn://服务器IP/myrepo/trunk签出到本地目录就能看到绿勾图标了。本地文件修改后图标变成红叹号提交后恢复绿勾这套视觉反馈机制对新人来说非常直观。4.2 IDEA中配置并使用SVNIDEA自带SVN支持但首次使用要配一下。打开IDEASetting - Version Control - Subversion把Use command line client指向svn.exe的路径。这个svn.exe是小乌龟安装目录里自带的命令行工具装了TortoiseSVN后一般不需要单独装另一个客户端。这里有个常见的坑如果在IDEA里一直提示Subversion executable not found说明IDEA没有找到svn.exe。去小乌龟安装目录一般是C:\Program Files\TortoiseSVN\bin确认一下svn.exe是否存在。小乌龟在安装时可以勾选command line client tools如果当时没勾重装时补上就行。配置好之后从IDEA里Checkout代码VCS - Checkout from Version Control - Subversion输入仓库URL选好本地目录就能把项目导进来了。日常使用就三件事Update Project把服务器最新代码拉下来等同于命令行svn up。Commit提交本地改动右键文件或整个项目直接提交。Integrate Directory合并分支这个对应svn merge后面细说。IDEA对SVN的文件状态显示也很直观文件在编辑后有蓝色或绿色的标记能和Git插件区分开。团队里有从Git转过来的同学重点是提醒他们SVN没有本地提交每次提交都会直接进服务器所以提交前一定要先update。4.3 VSCode中使用SVN标记文件状态VSCode是很多前端同事的主力编辑器要在VSCode里看到SVN的文件状态装个插件就行。最常用的是svn这个扩展装好后左侧资源管理器会自动给修改过的文件打上M、A、D这类标记和GitLens的体验类似。不过这个插件有个老问题它依赖VSCode集成的终端在文件很多的大仓库里刷新状态偶尔会卡顿。我的经验是如果项目特别大可以在VSCode设置里把svn.path直接指到小乌龟的svn.exe减少一层终端调用的开销状态刷新会流畅不少。4.4 日常操作流程update、commit、merge与冲突解决SVN的日常操作流程我总结成了四句话先update再修改改完commit要写清说明分支合并前先对比遇到冲突别慌找三方的。先说update和commit的顺序问题。很多新手直接从Git的习惯里带过来改完代码就点commit结果SVN直接弹窗提示Please update your working copy。这是因为SVN要求工作副本必须保持最新可用状态如果你改文件期间别人也改了同一文件并提交你的本地版本已经过期必须先update把别人的改动合进来才能commit。这个设计虽然不是最灵活的但避免了Git里那种提交了半天才发现有冲突的尴尬。再说merge。SVN的merge命令没有Git那么智能它本质上是把两棵目录树的差异应用到当前目录svn merge svn://服务器IP/myrepo/branches/feature-a svn://服务器IP/myrepo/trunk但平时在IDEA或小乌龟里操作更直观。小乌龟右键 - TortoiseSVN - Merge选好来源和目标的URL它会先模拟一次merge把即将发生的变更列表展示给你确认没问题再真正执行。这里强烈建议每次merge之前先做一次dry run试运行看看会有哪些文件被修改避免merge上去一堆意料之外的冲突。最后说冲突。SVN的冲突发生在update或merge时你改了文件A的第5行别人也改了文件A的第5行并提交了系统没法自动决定谁对。Git的做法是三方合并后在文件里标注冲突区域SVN也是类似出现冲突的文件会生成额外的.mine、.r新版本号文件。处理方式是打开冲突文件手工决定保留哪份改动然后右键标记为已解决。如果是小乌龟冲突解决对话框里会并排显示三个版本我的、别人的、合并后的逐行选完点保存就行。5. 常见问题与排查技巧实录5.1 认证失败与权限不足问题SVN认证失败是最常见的问题报错通常是Authentication failed或Access denied。前者说明用户名或密码不对后者说明账号验证通过但没权限访问目标路径。排查思路按顺序来。先确认passwd里账号是否存在、密码是否正确注意passwd文件里的注释行会被忽略但账号行必须是用户名 密码的格式等号两边可以有空格。再确认svnserve.conf里password-db passwd这一行没被注释掉很多模板里默认是注释状态不打开就永远走的是匿名访问。最后确认authz里给这个用户配了对应路径的权限有时候用户能连上服务但访问/trunk时报Access denied而访问其他目录正常几乎可以断定是authz缺规则。如果上面都查了还不行把服务端的日志打开。svnserve默认日志输出到终端如果用了-d守护进程模式日志输出到/var/log/svnserve.log之类的地方。看日志是排查一切认证问题的金钥匙。5.2 SVN certificate validation failed这个报错通常出现在用svnssh://或https://协议访问仓库时服务端的SSL证书不被客户端信任。比如用Apache mod_dav_svn配了自签名证书客户端第一次连接时会报证书验证失败。如果这是自己搭的内网服务最省事的做法是在客户端接受该证书。命令行模式下SVN会提示是否接受证书输入p即可永久接受。小乌龟则会在弹窗里让用户选择接受并保存。如果不想每次连接都折腾证书可以把这个服务器的证书导入到Windows证书管理器里操作路径是运行certmgr.msc在受信任的根证书颁发机构里导入服务器的自签名证书。需要提醒的是如果是公网服务器建议还是用正规CA签发的证书不要图省事直接用自签名。特别是在云环境里域名和数据安全都值得认真对待。5.3 客户端无法连接服务器ping通但连不上3690这是一个非常典型的网络症状服务器ping得通但SVN客户端连接一直超时或拒连。排查顺序是先本地确认svnserve进程在跑、3690端口在监听再检查服务器防火墙最后检查云安全组。防火墙的排查命令firewall-cmd --list-ports如果列表里没有3690/tcp按前面说的加上。安全组这个环节特别容易漏因为防火墙关掉后本地测试可能通了但从外部连的时候还是不行——这就是安全组压根没放行。去HoRain云控制台看一下服务器的安全组规则确认入口方向有TCP 3690的放行规则。还有一个容易忽略的点如果服务器上装了fail2ban或类似的安全工具它们可能会在检测到多次认证失败后临时封禁客户端IP。我就是在这个坑里耗了大半天最后在fail2ban的日志里看到自己办公室出口IP被封了。5.4 .svn漏洞与版本安全热词里有一条.svn漏洞这里说清楚来龙去脉。SVN客户端在检出代码后会在工作副本的每个目录下生成一个.svn隐藏文件夹里面存的是这个目录的管理元数据。早期SVN版本1.6及之前把一些敏感信息存放在.svn/entries或.svn/wc.db里如果网站上线时把这些.svn目录一起发布到Web服务器攻击者可以通过访问/.svn/entries等路径拿到源码文件列表、版本号、甚至部分未提交的代码内容。这就是所谓的.svn漏洞。新版的SVN1.7把多级目录的.svn统一合并到工作副本根目录的一个wc.db中风险大幅降低但依然不建议把包含.svn目录的文件夹直接发布到Web根目录。如果是从旧项目里接手部署上线前一定要检查Web目录下有没有残留的.svn目录有的话顺手删掉或者直接用rsync排除rsync -av --exclude.svn ./ /var/www/html/这属于部署卫生层面的问题但真的见过不少团队因为这个问题泄露过源码有必要单独拎出来说。5.5 核验码不一致与本地缓存问题有同学反馈SVN操作时报核验码不一致或用小乌龟提交时提示类似校验错误这个问题的根源一般是本地工作副本的元数据损坏或客户端缓存出了幺蛾子。常规处理流程是三步。第一步在报错的目录上执行小乌龟的Clean up它会清理中断操作留下的锁和临时信息。第二步把svn:ignore之类的属性检查一下确认不是权限或属性设置异常导致的报错。第三步如果Clean up无效最粗暴的办法是把该目录删掉重新Checkout一份。这个问题的底层原因大部分情况下是本地工作副本文件被外部程序比如网盘同步工具、杀毒软件做了不该做的修改导致本地元数据和服务器对不上。我遇到的最奇葩的一次是同事把SVN工作目录放到了坚果云同步文件夹里坚果云一直在后台修改文件时间戳SVN以为所有文件都被外部改动了。所以这里有个非常重要的实操建议SVN工作副本目录千万不要放进任何网盘同步目录里OneDrive、坚果云、百度网盘都不行这几乎必然导致各种莫名其妙的问题。最后再分享一点个人经验这套SVN服务我目前在HoRain云上跑了大半年整体非常稳定期间只因为一次服务器迁移重启过systemd服务拉起后一切恢复正常仓库数据完好无损。回顾整个搭建过程最大的感受是SVN的安装和配置本身并不复杂真正的复杂度来自规范二字。目录结构规范、权限分级规范、提交信息规范、分支合并规范把这些定好SVN能帮你省下大把团队协作的精力。如果后续团队迁移到Gitsvn2git这样的工具可以把仓库历史完整迁移过去版本号、提交时间、作者信息都能保留。但如果团队规模一直不大SVN这套体系再战几年完全没问题。最后再补一句记得定期备份/data/svn目录我用crontab每天凌晨打包一次加上云平台的快照双保险哪天误删了仓库也不慌。
返回列表