一、搬家前的准备:为什么搬?以及搬家的核心思路
首先,我们得统一思想:为什么要从SVN迁到Git? 这不是赶时髦。SVN是集中式版本控制,像一个中央文件柜,大家排队取放。而Git是分布式版本控制,每个开发者电脑上都有一个完整的仓库副本,这让分支创建、合并、离线工作变得极其高效。对于现代敏捷开发和DevOps流程,Git的优势非常明显。
那么,搬家的核心目标是什么?
- 完整保留历史:包括每一次提交、谁提交的、什么时候提交的、提交信息是什么,一个都不能少。
- 平滑转移权限:SVN的目录级权限需要映射到Git的仓库级或分支级保护策略上。
- 最小化团队影响:让开发者能快速适应新流程,最好能“无感”切换。
实现这个目标,我们主要依靠一个强大的工具:git svn。它是Git自带的一个组件,专门用来和SVN仓库“对话”,并能把SVN的历史完美地“翻译”成Git能理解的样子。
技术栈声明:本文所有命令行操作均在 Linux / macOS 的 Bash 环境或 Windows 的 Git Bash 环境中完成,核心工具为 git-svn。
二、核心搬迁步骤:用 git-svn 克隆历史
这是最关键的一步,我们要把SVN仓库“克隆”成一个本地的Git仓库。但SVN的布局(Trunk, Branches, Tags)和Git不同,我们需要告诉 git svn 如何映射。
假设我们有一个典型的SVN仓库,结构如下:
https://svn.company.com/repos/myproject/
├── trunk/
├── branches/
│ ├── feature-login
│ └── hotfix-20240101
└── tags/
├── v1.0.0
└── v1.1.0
我们需要创建一个“作者映射文件”,因为SVN的用户名(如 zhangsan)需要转换成Git标准的 姓名 <邮箱> 格式。
步骤1:创建作者映射文件 authors.txt
# 文件内容示例,格式为:svn用户名 = Git姓名 <Git邮箱>
zhangsan = 张三 <zhangsan@company.com>
lisi = 李四 <lisi@company.com>
admin = 系统管理员 <admin@company.com>
# 对于未知用户,可以统一映射
(no author) = 未知贡献者 <unknown@company.com>
你可以从SVN日志中提取所有用户来生成这个文件,可以用这个命令(需要先安装svn命令行工具):
svn log --quiet https://svn.company.com/repos/myproject | grep -E "^r[0-9]+ \| " | awk -F '|' '{print $2}' | sort | uniq | sed 's/^ *//;s/ *$//' > users.txt
然后手动将 users.txt 中的名字编辑成 authors.txt 的格式。
步骤2:执行完整的 git svn clone 这是完整的克隆命令,它会遵循SVN的标准布局。
git svn clone https://svn.company.com/repos/myproject \
--stdlayout \ # 告诉git-svn使用trunk, branches, tags的标准结构
--authors-file=authors.txt \ # 指定作者映射文件
--no-metadata \ # 不在提交信息中添加冗余的git-svn元数据,让历史更干净
myproject-git # 克隆到本地的目录名
这个命令会运行一段时间,时间长短取决于SVN仓库的历史提交数量。它会把:
trunk映射为 Git 的默认分支(通常是master或main)。branches/下的每一个目录映射为一个 Git 远程分支。tags/下的每一个目录映射为一个 Git 标签(但会是“轻量标签”,我们需要稍后处理)。
执行完成后,你就得到了一个完整的本地Git仓库 myproject-git,所有的SVN提交都变成了Git提交。
三、搬迁后的整理与优化:让新家更符合Git习惯
克隆下来的仓库还有些“SVN痕迹”,我们需要做一些整理,让它变成一个纯粹的、好用的Git仓库。
步骤3:将SVN标签转换为Git的“附注标签”
Git有两种标签:轻量标签(只是个引用)和附注标签(是一个完整的对象,包含打标签者、日期和信息)。git svn 创建的是轻量标签,我们最好将其转为附注标签。
# 进入克隆好的仓库目录
cd myproject-git
# 这个命令会列出所有由git-svn创建的远程标签引用(格式为tags/*)
git for-each-ref refs/remotes/origin/tags | cut -d / -f 5- |
while read ref; do
# 获取标签对应的提交ID
git tag -a "$ref" "origin/tags/$ref" -m "从SVN标签 $ref 迁移"
# 删除旧的远程标签引用
git branch -rd "origin/tags/$ref"
done
步骤4:清理和重命名远程分支
git svn 会把远程分支放在 refs/remotes/origin/ 下。我们需要把它们变成真正的本地分支,并清理掉 origin 这个远程(因为它指向的是SVN服务器,我们之后要指向新的Git服务器)。
# 将 origin/ 开头的远程分支(除了tags)创建为本地分支
git for-each-ref refs/remotes/origin | cut -d / -f 4- |
grep -v '^tags/' | # 排除标签
while read branch; do
# 例如,将 origin/feature-login 创建为本地分支 feature-login
git branch "$branch" "refs/remotes/origin/$branch"
done
# 查看所有分支,确认转换成功
git branch -a
# 删除指向SVN的远程 origin
git remote rm origin
现在,你的本地仓库已经是一个“纯净”的Git仓库了,包含了所有历史、分支和标签。
四、在新家安顿:推送到Git服务器并设置权限
仓库整理好了,现在要把它推送到新的Git服务器(如 GitLab、GitHub、Gitee 等)。
步骤5:关联新的Git远程仓库并推送
首先在Git服务器上创建一个新的空白项目(例如,在GitLab上创建 myproject)。
# 添加新的Git远程仓库地址,这里用GitLab示例
git remote add origin https://gitlab.company.com/group/myproject.git
# 推送所有分支到新的远程仓库
# -u 参数设置上游分支,以后可以直接用 git push/pull
git push -u origin --all
# 推送所有标签到新的远程仓库
git push -u origin --tags
至此,代码历史已经完全迁移到了新的Git仓库中。
步骤6:权限与协作模式的迁移(重点) 这是和SVN差异最大的一块。SVN是路径级权限,而Git是仓库级。我们需要在Git服务器上用新的方式管理。
- 仓库权限:在GitLab/GitHub中,通过设置“成员(Members)”来分配整个仓库的访问权限(所有者、维护者、开发者、访客)。
- 分支保护:这是替代SVN目录权限的核心。例如:
main/master(对应SVN的trunk):设置为“受保护分支”,只有维护者能直接推送,开发者需要通过合并请求(Merge Request/Pull Request)来合并代码。release-*分支:同样设置为受保护分支,确保发布版本的稳定。feature-*或hotfix-*分支:可以允许开发者创建和推送,鼓励频繁提交。
- 合并请求:推广使用合并请求来代替SVN的“提交即入库”。这是进行代码评审、自动化CI/CD检查的最佳实践。
你需要根据团队旧的SVN权限表,在Git服务器的项目设置中,仔细配置这些分支保护规则和成员角色。
五、后续工作与团队切换
步骤7:通知团队并更新本地仓库
- 正式公告,并给出一个明确的代码提交“冻结窗口期”。
- 为团队提供清晰的《Git使用指南》,重点说明新的工作流(例如:Git Flow 或 GitHub Flow)。
- 让每个团队成员执行以下操作:
# 1. 备份旧的SVN工作副本(重要!) # 2. 克隆全新的Git仓库 git clone https://gitlab.company.com/group/myproject.git cd myproject # 3. 查看所有分支 git branch -a # 4. 切换到需要的分支进行开发 git checkout -b feature-new-xxx origin/main
步骤8:善后与验证
- SVN仓库归档:迁移完成后,将SVN仓库设置为只读,并通知大家不再向其中提交代码。保留一段时间以备查验。
- 历史验证:随机抽查几个早期的SVN版本号(如
r123),在Git中用git log --grep或通过提交信息搜索对应的提交,确认内容一致。 - 构建验证:用Git仓库的最新代码和某个历史标签的代码,执行完整的构建和测试流程,确保功能一致。
应用场景分析
- 团队技术栈升级:团队向DevOps和敏捷开发转型,需要Git的强大分支能力和与CI/CD工具(如Jenkins, GitLab CI)的天然亲和性。
- 项目开源或托管平台迁移:计划将项目开源到GitHub,或从旧的SVN托管服务迁移到现代化的Git平台(如GitLab)。
- 合并与重组:公司并购或团队重组后,需要统一版本控制工具到Git。
技术优缺点
- 优点:
- 历史无损:
git svn工具非常成熟,能近乎完美地迁移提交历史。 - 发挥Git优势:迁移后,团队可以享受分布式开发、闪电般的分支操作带来的效率提升。
- 生态整合:更好地融入现代开发生态(代码评审、CI/CD、项目管理)。
- 历史无损:
- 缺点/挑战:
- 权限模型转换:从路径级到仓库/分支级的权限映射需要重新设计和配置,是迁移中最大的逻辑转换点。
- 学习曲线:对于习惯SVN的团队成员,需要学习Git的概念和工作流。
- 迁移过程耗时:对于超大、历史悠久的SVN仓库,克隆和整理步骤可能非常漫长。
注意事项
- 充分测试:务必在测试环境对迁移流程进行完整演练,尤其是复杂仓库(非标准布局、有移动历史等)。
- 沟通与培训:技术迁移成功与否,一半取决于人。提前沟通、提供培训和支持至关重要。
- 规划冻结期:安排一个低活跃度的时期(如周末)进行最终迁移,减少代码冲突和团队影响。
- 处理大文件:如果SVN历史中有不适合用Git管理的大文件(二进制库、媒体文件),考虑用
git lfs在迁移后管理,或将其移出版本库。 - 非标准布局:如果SVN仓库不是
trunk, branches, tags的标准布局,需要使用--trunk, --branches, --tags参数手动指定路径,操作会更复杂。
文章总结
将SVN迁移到Git是一项系统工程,但绝非不可完成的任务。其核心在于利用 git svn 工具忠实地完成历史的转换,并深刻理解SVN的“集中式路径权限”与Git的“分布式仓库协作”模型之间的差异,从而在目标Git平台上做好权限与工作流的重新设计。成功的迁移不仅能保留宝贵的历史资产,更能为团队注入新的协作活力,是团队研发效能升级的关键一步。记住,耐心准备、充分测试、有效沟通,是确保这次“大搬家”平稳顺利的不二法门。
评论