现有项目代码 SVN 迁移到 Git

目标

  • 将现有的 SVN 仓库管理方式迁移到 Gitea 中。
  • 用 Gitea 补上 SVN 在日常开发中的短板。

前言

目前公司产品代码主要用 SVN 管理,更多是作为测试版本归档点使用:

  • 测试通过的版本打一个版本号,整体打包后上传到 SVN。
  • 版本之间的具体改动过程、功能迭代过程,基本不在 SVN 里体现。

对比 git 的使用方式,这种做法相当于只在“稳定节点”上有记录,开发过程中的细粒度提交、并行分支、合并记录都缺失,尤其在多人并行开发时,很难追踪是谁在什么时间改了什么。

因此,我们希望:

  • 开发过程以 git + Gitea 为主,完整记录每一步改动;
  • SVN 继续保留为“对外测试/归档”的渠道,两者之间通过版本号和 tag 对齐。

下面的迁移流程主要解决“存量项目怎么从 SVN 迁到 Gitea,并且不打乱原有测试流程”的问题。

SVN迁移到GIT流程

1. git 与 SVN 管理方式的差异(与迁移相关的部分)

这里只挑和迁移、日常工作流关系最大的一些差异说明:

  1. 版本管理方式不同
    • 在 git 中,稳定测试版本只需要打一个 tag,例如 v1.2.3
    • Gitea 仓库对外只暴露 git 仓库,SVN 可以只保存这些带 tag 的稳定版本(继续做归档)。
  2. 分支与并行开发
    • git 中可以为每个需求/缺陷开独立分支(如 feature/xxxhotfix/xxx),分支之间可以方便地合并与回退。
    • 这解决了“多线并行开发时,代码容易互相覆盖、不好回溯”的问题。
  3. 工单与合并记录
    • 在 Gitea 中可以用 Issue 记录需求和问题,用 PR 记录合并过程;两者可以互相关联,后续追踪非常方便。
  4. 模块拆分与复用
    • 一些通用模块(协议栈、公共库等)可以独立成仓库,用子模块/subtree 等方式复用,避免在 SVN 中一份代码复制到多个工程的情况。

了解这些差异后,就更容易设计“git + Gitea 负责日常开发,SVN 只做版本归档”的协作模式。

2. 迁移流程概览

整体可以分成两种思路:

  1. 只迁当前稳定版本到 git,后续开发都在 git 中进行(推荐起步方式)。
  2. 连同 SVN 历史记录一起迁到 git,尽量保留原来的提交历史。

无论哪种方式,第一步都是在 Gitea 上建好对应仓库,然后再决定是:

  • 直接用当前 SVN 内容做一次“初始化提交”;还是
  • 借助 git svn 等工具,把 SVN 的历史一并导入。

下面分别展开说明。

2.1 在 Gitea 中创建空仓库并完成首次导入

  1. 在 Gitea 中,按照团队约定的组织/仓库命名规则,创建空仓库(可参考 gitea_org_create.mdgitea_repo_manage.md)。
  2. 从 SVN 检出当前稳定版本到本地工作区。
  3. 在工程根目录按团队要求补上基础文件,例如:README.md.gitignore.clang-format 等。
  4. 使用 git init 初始化本地仓库。
  5. 使用 git add . 将文件加入暂存区。
  6. 使用 git commit -m "init: 从 SVN 导入稳定版本 <SVN_REV>" 进行首次提交,建议在提交信息中标注对应的 SVN 版本号或标签。
  7. 使用 git tag <tag_name>(例如 svn-r1234v1.0.0)给这个版本打上标签。
  8. 使用 git remote add origin <remote_url> 关联到 Gitea 上的远程仓库地址。
  9. 使用 git push -u origin main 将主分支推送到远程。
  10. 使用 git push origin --tags 将标签推送到远程。

到这里,Gitea 上已经有了一个可用的 git 仓库,并且首个版本和原来的 SVN 稳定版本一一对应。
后续新的开发工作就可以基于这个仓库进行。

2.2 简单保留部分历史版本(手工方式)

如果不希望引入 git svn 等工具,但又希望在 git 中保留一些关键历史版本,可以用**“覆盖 + 提交”**的方式手工迁移几个重要节点:

  1. 先按 2.1 的方式,用最早想保留的那个 SVN 版本做一次初始化提交。
  2. 记录该 SVN 版本号,例如在提交说明里写上 SVN r100,并打一个标签(如 svn-r100)。
  3. 然后用下一个版本的 SVN 内容覆盖当前工作区(可以重新从 SVN 检出,或者复制覆盖)。
  4. 使用 git status 确认变更,git add .,再提交一次,提交信息中写上对应的 SVN 版本号。
  5. 如此循环,直到覆盖完所有你关心的历史版本。

这个方法操作相对简单,但缺点是:

  • 提交粒度是“按版本打包”,而不是 SVN 原本的每一次提交。
    如果项目历史很长、对精确追踪单次改动不敏感,这种方式通常足够用。

2.3 使用 git-svn 工具完整迁移历史

如果需要尽量保留 SVN 的历史提交记录,可以使用 git svn 工具进行迁移。

git svn clone -r5791:HEAD [svn_url] [new_name]
  • -r5791:HEAD 表示从 SVN 的 r5791 版本开始到最新(HEAD)的所有提交都导入。
    • r5791 可以根据项目需求调整;通常可以从某个“起点版本”开始导入,而不是从项目最初始版本开始。
    • 具体版本号可以通过浏览器访问 SVN 仓库查看。
  • new_name 是导入后本地 git 仓库的目录名,可以不写,默认与 SVN 仓库名相同。

迁移完成后,会在本地得到一个带有完整历史记录的 git 仓库。
接下来可以按 2.1 的方式,将该仓库推送到 Gitea:添加 remote、push 分支和 tag。

提示:git svn 适合作为一次性迁移工具,迁移完成并确认无误后,建议不再在日常开发中使用 git svn,以避免误操作影响后续纯 git 仓库的使用。

3. 迁移后的日常管理方式

迁移完成后,建议采用以下原则来衔接原有 SVN 流程:

  1. 日常开发以 git + Gitea 为主

    • 所有新功能、缺陷修复、分支管理、代码评审,都在 Gitea 上进行。
    • SVN 不再用来承载开发分支和中间状态,只保留关键发布版本。
  2. 测试/发布版本继续同步到 SVN(按需)

    • 当某个 tag 或 Release 版本需要交付测试或归档时,可以:
      • 从 Gitea 仓库检出对应 tag;
      • 按原有流程打包;
      • 将打包结果拷贝到 SVN,作为“对外归档”的一个版本。
    • 这样,原有依赖 SVN 的流程(如老工具脚本、老项目习惯)可以逐步、平滑地迁移,而不必一次性全部替换。
  3. 版本对齐与追溯

    • 建议在 SVN 的版本说明中标明对应的 git tag 或提交号,反之在 git 的 Release 说明中也可以备注“已同步到 SVN 的某路径”。
    • 出现问题时,可以从 SVN 版本快速定位到 git 中的具体提交,反之亦然。

通过上述方式,可以在不打乱原有测试归档习惯的前提下,让新项目开发尽快转到 git + Gitea 的工作流上来,逐步减少对 SVN 的依赖,并且对团队管理上并未有明显变化。