
最近在公司里折腾了一个有点意思的事情让同一个前端项目同时被SVN和Gitee管着。听起来像两个版本控制系统的“左右互搏”但实际用起来这是一套很多团队都会碰到的组合——公司内部的代码规范、历史包袱和审批流程还牢牢绑在SVN上另一边领导又要代码推到Gitee上做自动化构建、做代码看板甚至某个组件要开放给外部开发者用。前端项目依赖多、构建产物杂、开发节奏快在两套版本系统之间来回摆渡代码如果不提前想清楚方案随便操作一下就能把两个仓库都搞乱。这篇文章把我整个折腾过程里的方案选型、配置细节、同步命令和踩过的坑都盘了一遍。适合三类人看一是公司同时有SVN和Gitee、被迫搞双仓库的人二是想把SVN项目往Git平台迁移但还没下决心的团队三是纯粹想搞清楚两套版本系统边界的新手。1. 为什么一个前端项目会同时需要SVN和Gitee1.1 先分清SVN和Git到底差别在哪不把底层模型讲清楚后面配置起来就是瞎撞。SVN是集中式版本控制所有历史版本都存在服务器上工作目录里的.svn文件夹记录的是当前文件与服务器版本的差异信息。你提交代码实际上是直接往中央仓库写写完之后服务器上就有了你的变更。Git是分布式版本控制每个人本地都有一个完整仓库git commit只是提交到本地git push才把本地提交推到远端.git目录里存的是整套对象数据库。说得直白点SVN像一个公司大办公室所有人改同一份共享文档谁改了什么服务器立刻知道Git像一个分发给每个人的笔记本你在自己本子上随便写写完再把整本笔记的内容同步给别人。前端项目文件多、依赖重、分支操作频繁Git在本地提交和分支切换上的速度优势非常明显但集中式的SVN在权限控制和管理审批上有它的历史优势很多公司的研发流程已经深绑在SVN上不是说拔就能拔的。1.2 项目里的真实需求场景组合我在实际项目里遇到的情况非常典型前端小组十几个人代码一直在公司内网的SVN服务器上管理审批流程、巡检规则、版本发布记录全部围绕SVN的trunk主干来做。但新来的技术总监要求所有前端项目必须能在Gitee上看到最新代码评审的时候直接在Gitee上看diff、留评论。还有一个组件库要做成开源项目挂到Gitee上供外部使用但公司内部代码库又不允许直接暴露。这就出现了“一个项目两套账”的局面SVN继续作为公司内部代码流转的“法务系统”Gitee作为展示、协作和自动构建的“外部窗口”。不少团队还面临另一个现实问题——代码查重、安全扫描、CI/CD流水线都已经接在Gitee上而SVN服务器上的钩子脚本又老又没人维护两套系统被迫并行。1.3 为什么不做彻底迁移很多人第一反应是干脆从SVN迁移到Git Gitee省得两边同步。我一开始也是这么想的但深入了解后发现真没那么简单。一是SVN仓库里积累了好几年的历史记录迁移过程中翻车风险很高而且公司内部的权限审批流程跟SVN用户组绑定迁移等于动整个研发基础设施。二是有些后端服务、设计稿、运维脚本这些配套资源还在SVN上前端项目单独迁走反而跟周边团队割裂。三是SVN服务器由运维统一管理前端组没有管理员权限没法说关就关。所以最终结论是“共存”不是最优解但在很多公司是唯一解。既然改变不了平台格局那就把两套系统的边界管理好。2. 三种落地方案选哪种不踩坑2.1 同目录双仓库共存最推荐的做法所谓同目录双仓库共存就是同一个项目目录里同时存在.svn和.git两个元数据文件夹SVN和Git各自把对方的关键目录加入忽略规则互不干扰。日常开发时你在SVN里正常提交保留公司流程同时定期把最新状态commit到Git、push到Gitee。反向操作也一样Gitee上的MR合入后把变更拉回本地再提交到SVN。这个方案最大的好处是开发人员的工作习惯几乎不用改还是在同一个目录里写代码不需要在多个目录之间来回搬运文件。我在实际操作中觉得最舒服的一点是你永远有一个“全量快照”在Gitee上哪怕公司SVN服务器挂了本地Git仓库和远程Gitee都还有一份完整代码抢救起来心里有底。2.2 git-svn桥接适合个人体验不适合团队协作git-svn是Git官方提供的一个桥接工具可以用Git命令操作SVN仓库核心命令是git svn clone、git svn dcommit、git svn rebase。它跟“同时使用两个平台”不太一样它只是把Git当成SVN的一个客户端外壳远端仓库还是SVN并没有真正把代码推到Gitee。这个方案最大的问题在并行操作时很容易乱。git-svn要求你的Git历史必须和SVN历史线性对应本地一旦用了git rebase改写过提交再 dcommit 到SVN就会产生各种诡异的冲突。而且它不支持多端同时操作团队里一个人用了git-svn其他人还是用TortoiseSVN两者很容易把SVN服务器的版本线搞乱。我自己的体会是git-svn拿来个人尝鲜可以千万别在团队里当正式方案用。2.3 服务器脚本自动同步重武器看运维资源进阶玩法是在SVN服务器上配置post-commit钩子每次有人提交SVN钩子脚本自动把变更同步到Git仓库再推送到Gitee。这个方案的自动化程度最高但门槛也最高——你需要运维配合服务器上要装Git环境、配置SSH key还要处理同步失败的重试、冲突停止、日志告警等问题。更麻烦的是自动同步通常只解决了SVN到Gitee的单向同步Gitee上的修改要自动反哺回SVN则很难做好因为两边都在改冲突处理靠脚本根本处理不明白。我的建议是自动同步适合那些“SVN是唯一主源、Gitee只读镜像”的场景如果两边都是活跃开发源就别指望全自动化人工摆渡反而更稳。2.4 三方案对比小结方案维护成本适用场景风险点同目录双仓库低个人即可团队并行使用两套系统忽略规则配置不当导致元数据混乱git-svn桥接中个人临时用Git操作SVN历史线性约束强多人协作易冲突服务器脚本自动同步高需运维配合SVN单主源、Gitee只读镜像双向同步困难失败重试麻烦3. 环境准备与基础配置先把不打架的底子打好3.1 环境安装和仓库初始化前端开发机上一般已经装了TortoiseSVN和TortoiseGit这块没什么特殊要求。重点说初始化顺序无论已有SVN检出目录还是想先在Gitee建仓库标准做法都是先让SVN作为“主工作区”在SVN检出目录里执行git init。千万不要反过来在Git仓库里做SVN checkout否则Git的元数据会被SVN的检出动作影响而且嵌套之后两个图形客户端都会把对方的状态扫描出来简直是一场灾难。仓库建好之后的核心动作是设置远端地址。用HTTPS的方式推送Gitee每次都输账号密码我强烈建议配置SSH key。在Git Bash里执行ssh-keygen -t ed25519 -C 你的邮箱然后把~/.ssh/id_ed25519.pub内容粘到Gitee个人设置里的SSH公钥页面。之后git remote add origin gitgitee.com:团队名/项目名.git就一劳永逸了。3.2 两套忽略规则必须对称设置这是整个方案里最容易被忽略、也最容易出大事故的一步。SVN用svn:ignore属性做忽略Git用.gitignore文件做忽略两者互相不认识。如果只设置了一边另一边的工具就会把对方该忽略的东西全追上。SVN的忽略设置用命令做最干净。在项目根目录执行svn propedit svn:ignore .在弹出的编辑器里写入node_modules dist .git然后执行svn propset svn:ignore --recursive把属性递归应用到子目录不同版本写法有差异也可以直接在TortoiseSVN的Add to ignore list里右键完成。注意.git目录如果不加进SVN忽略一旦有人用TortoiseSVN的“添加”按钮不小心把整个.git文件夹提交进去那提交量会直接爆炸。Git的忽略规则同样要面面俱到在.gitignore里写入.svn/ node_modules/ dist/ coverage/ *.log .env.local .DS_Store这里我额外说明一点node_modules和dist看着像常识但在双仓库场景下的危害比单仓库大得多。SVN提交 node_modules 会拉高服务器存储、拖慢所有同事的svn update而Git提交 node_modules 会把数万个文件写进对象库Gitee的仓库大小会失控。我在实际操作中见过同事把整个 node_modules 提交到SVN结果那次svn update跑了快半小时全组人一起骂娘。3.3 元数据目录管理别把.svn和.git提交到对方仓库踩过这个坑的人应该不少在Git仓库里执行git add -A眼睛一花把.svn目录也加进来了。结果就是每次SVN更新文件Git都会检测到大量变化因为.svn目录里的内部文件也在变整个Git历史里全是垃圾提交。一旦出现这种情况不要慌但处理速度要快。先用git rm -r --cached .svn把.svn从Git索引里移除然后把.svn写进.gitignore再提交一次清理掉历史里的引用。反过来也一样如果发现SVN要提交.git了先在SVN里执行删除再设置svn:ignore属性。我自己的判断标准很简单任何以点开头的目录默认不进版本库除非项目真正需要它比如.npmrc、.env.example这种配置文件。宁可多忽略一个真实文件也不要放进来一堆元数据炸弹。4. 双向同步实操手册4.1 从SVN检出并初始化Git仓库假设SVN仓库地址是http://192.168.1.100/svn/frontend-project完整初始化步骤# 第一步从SVN检出主分支代码 svn checkout http://192.168.1.100/svn/frontend-project/trunk frontend-project # 第二步进入目录初始化Git cd frontend-project git init # 第三步设置Gitee远程仓库 git remote add origin gitgitee.com:yourteam/frontend-project.git # 第四步先创建一份.gitignore把.svn和构建产物排除掉 echo -e .svn/\nnode_modules/\ndist/ .gitignore # 第五步把当前SVN工作区内容作为Git的首次提交 git add -A git commit -m chore: 初始化Git仓库镜像SVN当前代码 git push -u origin main这一步要特别注意SVN检出的文件里如果有换行符是CRLFGit首次提交时会在工作区自动转换或保留原样这会影响后续的diff表现。建议在git config core.autocrlf trueWindows环境或git config core.autocrlf inputMac/Linux环境先定下来避免后面每次同步都出现全文件变动的假象。4.2 正向同步SVN的提交推到Gitee这是最常见的操作路径开发者在SVN里提交了自己的代码然后要把最新代码同步到Gitee。我的标准流程是先拉SVN的更新再推Git# 1. 先保证本地与SVN服务器同步 svn update # 2. 解决冲突并确认SVN工作区是干净的 svn status # 3. 提交或更新SVN上所有改动 svn commit -m feat: 完成登录页重构 # 4. 拉取Gitee远端最新代码大多数时候没人动但保险起见 git pull --rebase origin main # 5. 把SVN产生的所有改动变成Git提交 git add -A git commit -m feat: 完成登录页重构 # 6. 推送到Gitee git push origin main如果git pull卡住常见原因是Gitee上有别人推的代码而本地也有未提交改动。我的处理方式是先git stash暂存本地改动pull完再git stash pop如果有冲突就在工作区里手工解决。记住一个原则所有冲突都要在SVN工作区解决干净之后再进行Git的提交不要让Git提交带着冲突标记不然代码看板上全是乱码。4.3 反向同步Gitee上的变更合并回SVN反向同步的核心变化是“Gitee不是主源”所以步骤要更谨慎。正常流程# 1. 先从Gitee把最新改动拉到本地 git pull --rebase origin main # 2. 确保本地没有未提交的SVN改动 svn status # 3. 先提交SVN上暂时未提交的本地改动如有 svn commit -m chore: 本地改动提交 # 4. 把Git工作区与SVN工作区的差异合并 # 此时Git pull改动的文件已经落在工作区SVN会识别为修改 svn add --force . svn commit -m feat: 合并Gitee上提交的改动 # 5. 最后再推一次Git确保Gitee上的记录也最新 git push origin main这里最容易出问题的是svn add --force .。Git pull 下来的新文件对SVN来说是“未版本控制”的直接svn commit不会带上它们必须先把新文件svn add进去。用svn add --force .可以把所有新文件一次性加进来它跟svn add的区别是遇到已版本控制的文件不会报错正好适合这种批量操作场景。4.4 同步命令速查表操作SVN命令Git命令拉取最新代码svn updategit pull --rebase origin main查看状态svn statusgit status添加新文件svn add 文件名git add -A提交svn commit -m 说明git commit -m 说明推送无需推送commit即提交git push origin main批量添加未版本控制文件svn add --force .同上git add -A组合记忆其实很简单SVN里 commit 就是一步到位Git里 commit 还要 push 才到远端。我们团队日常总结成一句话“先SVN后Git先更新后提交”只要按照这个顺序操作基本不会出乱子。5. 常见问题与排查实录5.1 覆盖图标消失怎么判断文件状态用TortoiseSVN的时候每个文件左下角都有绿色对勾或红色感叹号。同时装TortoiseGit之后你会发现有些文件图标被吞了一会显示SVN的图标一会显示Git的甚至什么都不显示。这是两个Shell扩展在抢Explorer的图标槽位。这不是文件出问题了只是显示优先级冲突。我的处理方式是把TortoiseGit的图标设置改成“仅当前文件夹”在TortoiseGit Settings的Icon Overlays里调整给SVN让出更多表现空间。更省事的办法是命令行看状态SVN用svn statusGit用git status不受Shell扩展影响永远准确。5.2 忽略规则漏配置仓库被垃圾文件灌满这个问题我在3.2里提到过但实际遇到的情景更恼人。有一次同事在Gitee上看到一个组件目录里出现了.svn/wc.db这个文件而SVN服务器上出现了dist/整个构建产物目录。两边仓库都被对方管理体系里的垃圾灌了一部分。排查思路是这样的先看哪边的仓库出现了不该出现的目录然后当场删掉并提交清理。真正要反思的不是删而是为什么会漏。SVN的svn:ignore属性是“目录级”的不是全局配置新人检出代码后在新目录里跑npm install生成的 node_modules 如果没被递归忽略照样会被提交。Git的.gitignore是文件跟着仓库走的相对可控。所以我的经验是尽量把忽略规则写成Git仓库内的.gitignore文件统一维护同时在SVN服务器根目录设置全局忽略清单覆盖所有项目。5.3 中文文件名和行尾符引发的幽灵差异前端项目里中文文件名太常见了比如首页.vue、用户模块.js。SVN和Git对这些文件名的编码处理不同有时候Git仓库里看到的是首页.vueSVN里显示是转义后的%E9%A6%96%E9%A1%B5.vue。这会导致一个问题Git diff 时中文文件名的变化被误判为“删除新增”代码评审里显得特别乱。解决方案是配置文件层面统一Git Bash里设置git config --global core.quotepath false让Git直接显示中文文件名不转义。行尾符问题更隐蔽Windows下编辑过的文件全是CRLFGit第一次提交后如果core.autocrlf没配好每次git status都显示一堆文件有改动实际上只是换行符变了。配好core.autocrlf true之后Git在提交时把CRLF转成LF检出时再转回CRLFSVN那头保持不变两边就都安静了。5.4 分支与标签的同步策略双仓库场景下分支管理是最容易失控的地方。SVN支持trunk、branches、tags三个目录而Git用git branch管理分支。两者不是一对一映射关系强行同步会把自己绕晕。我的实践经验是Gitee仓库只维护一个main主分支作为SVN trunk的镜像所有开发分支都只在SVN上管理不往Gitee推。需要做RFC或者评审的功能在本地Git仓库建个feature分支合并回main后推Gitee但SVN上只保留trunk一条线。这样就能避免两边分支网络互相污染。标签也一样SVN的tags目录是独立的版本快照Gitee上不打tag只依赖仓库的commit节点回溯。这件事最好写进团队规范里因为人是很容易在分支操作上“自由发挥”的。6. 团队协作规范和个人经验6.1 明确同步方向与责任人双仓库方案里同步方向一旦模糊就会出现“谁都不推、谁都在推”的局面。我们在团队里定了几条硬规矩SVN是公司正式代码源所有需求合入必须走SVN的trunkGitee是展示和评审平台由前端组长或每次迭代的负责人执行“SVN到Gitee”的同步其他人不在Gitee上直接改代码涉及到MR合入Gitee的变更必须由专人负责拉回SVN并提交。这几条规矩的执行效果很明显最直观的就是冲突变少了。之前大家自由同步的时候同一天内SVN和Gitee各改一个文件第二天两边的代码都对不上号排查半天发现是同步顺序错了。有了明确责任人整个流程固定下来出问题就知道找谁。6.2 提交信息与代码评审约定两套系统的提交信息最好保持统一。SVN的提交信息格式用feat: 说明、fix: 说明、chore: 说明Git的提交信息直接沿用SVN的写法不要两边各写一套。这样做的好处是追溯代码时在Gitee的commit历史里能看到和SVN提交记录一一对应的说明两边diff也能对上。代码评审这块我的建议是评审在Gitee上看diff、留评论但合入口径是“评审通过后代码先去SVN部再同步回Gitee”。不要反过来先在Gitee合MR再往SVN回传因为Gitee上的分支合并动作容易把commit历史搞复杂回传后SVN的线性历史会被破坏。6.3 我踩过的坑和现成脚本最后分享两个我踩过最深的坑。第一次是初始化Git时没把node_modules排除本地git add -A把几万个文件全部提交进了Git对象库Gitee仓库直接拉到十个G以上清理的时候只能重做仓库。第二次是同事在SVN上修改了一个文件名Git这边同步后出现了“删除旧文件新增新文件”的奇怪状态代码评审时评审人看不出来是改名只看到一个文件没了、一个文件多了最后只能靠提交信息“猜”业务意图。现在我们把同步操作封装成一个脚本放在项目根目录每次执行一条命令就能完成整套同步流程#!/usr/bin/env bash # 正向同步SVN - Gitee svn update || exit 1 svn status echo 检查上面状态确认没有未解决冲突 read -p 按回车继续... svn commit -m $1 || exit 1 git pull --rebase origin main || exit 1 git add -A git commit -m $1 || exit 1 git push origin main || exit 1脚本里的read -p是故意加的强制你在提交前确认一遍SVN状态防止带着冲突直接同步。自动化是好事但双仓库场景里还是保留一个人工确认的环节最安全。关于“前端项目同时使用SVN和Gitee管理代码”这件事我的总体感受是这确实是一种临时状态但它能让你在现有公司基础设施不动摇的前提下把代码展示、外部协作和新工具链逐步接起来。如果你也正被这个需求困扰先从同目录双仓库做起把忽略规则和同步顺序理清楚再让团队跟着规范走基本就能稳下来。后面真的觉得同步太繁琐、想要彻底摆脱SVN的时候你已经有了一套完整的Git仓库和Gitee远程仓库迁移的底气也攒足了。