一、为什么从 SVN 迁移到 Git?

在过去很长一段时间,很多公司都使用 SVN 作为版本控制工具。随着 Git 的普及,以及 CI/CD 等现代开发工具链的兴起,越来越多团队考虑从 SVN 迁移到 Git。

本篇博客记录我实际操作的一次 SVN 到 Git 的迁移过程:我想将一个SVN老项目带走,因为SVN离开公司的中心服务器原来的提交历史等信息就会丢失,我自然就想到Git的自身就能进行版本控制的能力,然后我会出差来到一个无网络环境(局域网),此时我将进行一些开发做一些提交,最后回到公司将这些提交集成回公司的中心服务器.

Git的优势:

  • Git 分支管理灵活,支持分布式开发

  • 支持离线提交、离线历史查看

  • 集成更丰富的代码托管平台(GitHub、GitLab、Gitea 等)

  • 配合 CI/CD、Pull Request 等现代开发流程更友好


二、环境准备

工具:

如果你不熟悉Git可以看我的这篇博客:在Unity环境中使用Git进行版本控制(入门篇)_unity git-CSDN博客

安装了Git后在一个文件夹下验证一下环境:

在任意一个目录下右键发现一个Open Git Bash 验证下面两个命令

git --version
git svn --version

 


三、获取 SVN 作者信息映射表(可选)

如果不关心作者信息,则建议直接省略,省略这步则会直接使用SVN中的作者信息

如果想让 svn 的历史作者正确映射成 git 格式,需要一份作者映射表。

生成作者映射文件:

svn log -q | awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" = "$2" <"$2"@example.com>"}' | sort -u > userinfo.txt

然后根据需要编辑 userinfo.txt,把 SVN 用户名改成人名邮箱等 Git 风格。


四、执行 git-svn 克隆

进入一个空目录(该目录是用来存放项目的):

git svn clone https://svn服务器地址/项目路径 

clone后面加上svn的地址就行了,但是也可以加一些参数,但是我对此不是很懂,所以没有使用,有需要则需要更细致的查看git的官方文档.

要注意的是大概率会弹出一个弹窗要求你信任证书

因为如果 svn 是 https 且有自签证书,会提示信任证书,选择 t (临时) 或 p (永久信任)。

然后要求你输入你的svn账号密码.

参数说明:

参数含义
--no-metadata不保留 git-svn 内部元数据
--authors-file使用刚才的作者映射表
--stdlayout如果 SVN 仓库有标准目录结构(trunk/branches/tags)可以加上


五、离线开发与本地提交

Git 的好处就是,即使没网,也可以这样:

git add .
git commit -m "第一次离线开发提交"
git commit -m "第二次离线开发提交"

不用担心 SVN 连接失败。

你可以使用GUI工具,我上面提到博客也对此有说明.


六、恢复网络后同步回 SVN

先拉取一下 SVN 最新:

git svn fetch

然后同步你的历史提交:

git rebase remotes/git-svn
git svn dcommit

这样,你所有本地 Git 提交,会逐个同步回 SVN。

这里要提一下:这个由svn迁移的git仓库内部仍保持着对原来svn服务器的联系,所以你仍然可以更新或推送代码.所以这里的需要专门的命令(如 git svn dcommit而不是git commit)

Git SVN 工作流细致讲解(git svn fetch、git rebase remotes/git-svn、git svn dcommit)

这里用一个完整的场景,详细讲解 Git 与 SVN 协作中的三个核心命令的作用和顺序:


① 克隆仓库(git svn clone)

首先,我通过以下命令克隆 SVN 仓库:

git svn clone <SVN 仓库地址>

此时:

  • SVN 服务器当前版本是 r100;

  • Git 会创建一个远程跟踪分支 remotes/git-svn,指向 SVN 最新提交 r100;

  • Git 还会基于 remotes/git-svn 创建一个本地分支 master,作为本地工作分支,也指向 r100。


② 本地开发

我在本地 master 分支上进行了三次提交,分别是:

  • 提交 A

  • 提交 B

  • 提交 C

此时本地提交历史如下:

r100 → A → B → C(master)

而 remotes/git-svn 依然指向 r100:

remotes/git-svn → r100

③ 同事推送了新提交到 SVN

假设此时我的同事在 SVN 服务器上进行了 5 次提交,SVN 版本推进到了 r105。


④ 同步 SVN 最新提交(git svn fetch)

我需要拉取最新的 SVN 提交,执行命令:

git svn fetch

此时:

  • remotes/git-svn 被更新到 r105;

  • 本地 master 分支不变,仍基于 r100。

当前状态:

remotes/git-svn → r105
master → r100 → A → B → C

⑤ 变基到最新 SVN 提交(git rebase remotes/git-svn)

为了让我的提交基于 SVN 最新版本,我执行:

git rebase remotes/git-svn

这个命令做了三件事:

  1. 临时“摘取”我本地的提交 A、B、C;

  2. 将 master 分支指针移动到 remotes/git-svn(r105);

  3. 依次把 A、B、C 重放到 r105 之后,形成新的提交链(过程中若有冲突需解决):

r105 → A′ → B′ → C′(master)

(注:A′、B′、C′ 是变基后的新提交对象)


⑥ 推送到 SVN(git svn dcommit)

变基完成后,我执行:

git svn dcommit

这条命令会:

  1. 将 A′、B′、C′ 提交到 SVN 服务器,生成新版本 r106、r107、r108;

  2. 自动更新 remotes/git-svn,指向最新的 SVN 提交 r108;

  3. 本地 master 也指向 r108,保持同步。

最终状态:

SVN 服务器:r106 → r107 → r108
remotes/git-svn → r108
master → r108

✅ 全流程示意图:
# 初始状态
remotes/git-svn → r100
master → r100 → A → B → C

# 同事提交后
remotes/git-svn → r105
master(不变)

# 执行 git svn fetch
remotes/git-svn → r105
master(不变)

# 执行 git rebase remotes/git-svn
remotes/git-svn → r105
master → r105 → A′ → B′ → C′(变基)

# 执行 git svn dcommit
SVN 服务器 → r106 → r107 → r108
remotes/git-svn → r108
master → r108

✅ 关键总结:
  • remotes/git-svn 仅是 SVN 服务器最新提交的“镜像”,不会存储你的本地提交;

  • git rebase remotes/git-svn 会把你的本地提交“重放”到 SVN 最新提交之后,让提交链保持线性;

  • git svn dcommit 会按顺序把你的提交推送到 SVN,并自动更新本地 remotes/git-svn 和 master。


七、推送到云端 Git 仓库

如果你还想同步备份到云 Git 仓库(比如 Gitee、GitHub、GitLab):

git remote add origin https://你云端Git地址.git
git push -u origin master

-u的意思是将名为origin的仓库设为默认推送或拉取的仓库

以后想同步:

git push
git pull

此时SVN中心服务器和Git云服务器都能和你这个仓库交互.

 其实这里我还遇到一个问题:我本想使用gitee作为我的云,但是遭遇了推送失败,原因是免费版本的云服务器限制单个文件要小于100MB,很不巧我的项目的历史提交中包含这么大的文件,所以我没法使用gitee,没办法我临时搭建一个自己的git服务器,我以前使用过gitea,轻量强大

Gitea简单部署:

https://github.com/go-gitea/gitea

从发布版里面找windows的64版本,下载下来就行了(我是临时用用,建议从官方文档查看规范的部署流程).

下载下来后,放在一个专门的目录下就完成了(这个目录就是你的服务器了) ,此时启动该exe

我的理解本质就是一个大的后端项目,访问该地址(ctrl+左键)

要求数据库,我选择SQLite,这样我不需要部署数据库,公司名填一下就可以安装了

默认第一个注册用户是管理员,后续操作和Github没有太大差别. 


八、日常双轨工作流建议

场景命令
从 SVN 拉取更新git svn fetch
把本地改动同步到 SVNgit svn dcommit
离线开发用 git commit
推送云端 Gitgit push origin master
拉取云端 Gitgit pull origin master

九、常见问题

1. SSL 证书错误怎么办?

SVN 自签证书的话,第一次拉取时会弹出信任确认,选 t 或 p。


2. 推送到 Git 报错:remote contains work that you do not have locally?

远程仓库可能有默认 README、.gitignore,你先:

git pull origin master --rebase

然后再推:

git push

3. 有没有办法以后彻底脱离 SVN?

可以,后续可以做一次仓库“脱 SVN 清洗”,删掉 .git/config 里的 svn-remote 部分,然后强制推送纯 Git 历史。

Logo

纵情码海钱塘涌,杭州开发者创新动! 属于杭州的开发者社区!致力于为杭州地区的开发者提供学习、合作和成长的机会;同时也为企业交流招聘提供舞台!

更多推荐