SVN 迁移到 Git

摘要

  • 本文介绍如何使用git-svn将 SVN 中的项目迁移到 Git

Git-Svn 简介

  • git-svn 是 Git 官方提供的工具,用于把 SVN 仓库的提交历史逐条转换为 Git commit,并支持后续同步,是 SVN 迁移到 Git 的经典方案。

  • git-svn 做 SVN → Git 迁移,本质是利用 Git 内置的“SVN 适配器”把 SVN revision 流水线转换成 Git commit。

  • 它的优势主要体现在完整保留 SVN 线性历史迁移成本低可控性强这三个维度。

Git-Svn 安装

Linux 安装

1
sudo dnf install git-svn -y

Mac 安装

1
brew install git-svn

查看版本与帮助信息

1
2
3
4
5
6
7
8
# 查看版本
git svn --version
# 查看全部命令
git svn help
# 查看某个命令的帮助信息,比如这里查看clone
git svn help clone
# 查看手册
git svn --help

实战迁移

查看svn最后一次提交时的 revision

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 输入密码后,凭证会被保存在 ~/.subversion/auth/ 中
svn info https://svn.test.com/mytools/sometool/trunk --username 你的svn用户名
# 输出
Path: trunk
URL: https://svn.test.com/mytools
Relative URL: ^/callblocker/trunk_as
Repository Root: https://svn.test.com/mytools
Repository UUID: b1d85008-4086-4607-87e8-e67b222846c5
Revision: 7840
Node Kind: directory
Last Changed Author: hanqunfeng
Last Changed Rev: 7840
Last Changed Date: 2026-05-18 16:24:34 +0800 (Mon, 18 May 2026)

## 说明
Revision: 7840 表示最新的Revision

迁移trunk(不包含branch和tags)

  • 前台运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 运行 git svn clone 时,它会自动使用缓存的凭证
# 注意,因为不包含 branch和tags ,所以svn地址要直接定位到trunk路径
git svn clone \
https://svn.test.com/mytools/sometool/trunk \
-r 7835:HEAD \
--log-window-size=1000 \
sometool

## 参数说明
`-r`: 仅仅保留最近多少次的log,上面最后一次是7840,这里从7835开始,相当于保留从7835到7840的6次提交,如果保留全部就不加
`--log-window-size`: 每次向 SVN 服务器请求 1000 条 revision 日志,然后再继续请求下一批。默认 100。设置较大可以减少与svn服务器之间的通信次数,降低迁移时间,但同时也会增加内存占用和单次请求时间。一般建议大于2万Revision时才开启。

# 可以通过如下命令查看commit历史
git log
  • 后台运行

1
2
3
4
5
# 如果上面已经缓存或密码了,可以使用如下命令
nohup git svn clone https://svn.test.com/mytools/sometool/trunk sometool > clone.log 2>&1 &

# 如果没有运行过 svn info,即没有缓存过密码,可以通过如下命令进行迁移
echo "你的svn密码" | nohup git svn clone https://svn.test.com/mytools/sometool/trunk sometool --username 你的svn用户名 --no-auth-cache > clone.log 2>&1 &

发布到git仓库

  • 注意此时不需要执行 git add .git commit,因为迁移过程中这些commit已经自动生成了

1
2
3
4
5
# 设置仓库
git remote add origin https://gitlab.test.com/android/sometool.git

# push
git push -u origin master

小贴士

  • 如果 git push 时报如下错误,说明上传的bady大小超过了限制,可以改用 ssh push 的方式
1
2
3
# error: RPC failed; HTTP 413 curl 22 The requested URL returned error: 413
# ssh push 的方式需要设置 SSH Keys
git remote set-url origin git@gitlab.test.com/android/sometool.git
  • 生成 key(如果你没有)
1
ssh-keygen -t ed25519 -C "your_email@example.com"
  • 添加 key 到 GitLab
1
2
3
4
5
# 复制:
cat ~/.ssh/id_ed25519.pub

# 然后到 GitLab:
User Settings → SSH Keys → Add Key

同时迁移branchtags

  • 标准svn结构

1
2
3
4
project/
├── trunk
├── branches
└── tags
1
2
3
4
5
6
7
git svn clone \
https://svn.test.com/mytools/sometool \
--stdlayout \
sometool

# 参数说明
--stdlayout:标准布局
  • 非标准结构,例如

1
2
3
4
project/
├── source
├── release
└── version
1
2
3
4
5
6
git svn clone \
https://svn.test.com/mytools/sometool \
--trunk source \
--branches release \
--tags version \
sometool

转换 SVN Tag 和 Branch

  • git-svn 导入后,查看git分支会看到类似如下的内容

1
2
3
4
5
6
7
git branch -a
* master
remotes/origin/sometool-Branch
remotes/origin/sometool-V1.0.72
remotes/origin/tags/sometool-V1.0.0.00-b582-p0
remotes/origin/tags/sometool-V1.0.02.00-b591-p0
remotes/origin/tags/sometool-V1.0.02.00-b595-p0
  • 实际的branch是:

1
2
remotes/origin/sometool-Branch
remotes/origin/sometool-V1.0.72
  • 实际的tags是

1
2
3
remotes/origin/tags/sometool-V1.0.0.00-b582-p0
remotes/origin/tags/sometool-V1.0.02.00-b591-p0
remotes/origin/tags/sometool-V1.0.02.00-b595-p0
  • 但此时都显示为branch,所以需要将其转换为tag

1
2
3
for tag in $(git branch -r | grep 'tags/' | sed 's|origin/tags/||'); do
git tag "$tag" "origin/tags/$tag"
done
  • 然后检查

1
2
3
4
git tag -l
WiFiDoctor-V1.0.0.00-b582-p0
WiFiDoctor-V1.0.02.00-b591-p0
WiFiDoctor-V1.0.02.00-b595-p0
  • 转换 Branch

1
2
3
4
# 这里创建需要保留的分支
git branch sometool-Branch remotes/origin/sometool-Branch

git branch sometool-V1.0.72 remotes/origin/sometool-V1.0.72
  • 添加远程仓库

1
git remote add origin https://gitlab.test.com/android/sometool.git
  • 推送所有内容

1
2
3
4
5
6
7
8
9
10
11
# 推送分支:
git push --all origin

# 推送标签:
git push --tags origin

# 删除本地没用的分支
git fetch --prune

# 再次查看分支,此时就正确了
git branch -a

把 SVN 用户名映射成 Git 的用户

1
2
3
4
5
git svn clone \
https://svn.test.com/mytools/sometool \
--stdlayout \
--authors-file=authors.txt \
sometool
  • authors.txt 格式

1
2
3
SVN 用户名       Git 用户
zhangsan = Zhang San <zhangsan@example.com>
lisi = Li Si <lisi@example.com>

git-svn 优点与缺点对比表

  • 一、核心能力对比

维度 优点 缺点
SVN → Git 迁移能力 可将 SVN revision 逐条转换为 Git commit 不支持现代 Git 迁移增强(如智能重写)
历史保留 完整保留 commit 顺序、message、时间 复杂历史(merge / branch)可能失真
作者信息 可通过 --authors-file 精确映射 SVN 用户 不配置时作者信息可能不规范
revision 映射 保留 SVN revision(git-svn-id) Git commit 与 SVN 强绑定,历史较“冗余”
  • 二、分支与标签支持

维度 优点 缺点
trunk 映射 自动映射为主分支 无明显缺点
branches 支持 支持 SVN branches → Git branches 转换后通常需要手动整理
tags 支持 支持 SVN tags → Git tags 需要额外脚本转换为真正 tag
灵活性 可选择只迁移 trunk 多分支结构处理较繁琐
  • 三、迁移方式与成本

维度 优点 缺点
使用复杂度 命令简单(git svn clone) 参数较多时容易踩坑
工具依赖 Git 官方工具,无需第三方软件 Windows 环境可能缺组件
学习成本 对 Git 用户友好 对 SVN 复杂仓库理解要求高
部署成本 无需额外服务 无 GUI 可视化迁移工具
  • 四、性能与规模

维度 优点 缺点
中小型仓库 表现稳定
大型仓库 可通过 --log-window-size 优化 10万+ revision 性能较慢
网络依赖 支持断点式 fetch/rebase 强依赖 SVN server 性能
内存使用 可控 大历史导入时较高
  • 五、功能扩展能力

维度 优点 缺点
增量同步 支持 git svn fetch 维护复杂
双向同步 支持 dcommit 回写 SVN 实际工程中很少使用
历史可追溯性 SVN revision 与 Git commit 可对照 Git history 不够“现代化”
生态兼容 Git 原生工具链可用 不适合 Git-centric 工作流重构
  • 六、适用场景总结

场景 是否适合 git-svn
SVN → Git 一次性迁移 ✔ 非常适合
保留完整 SVN 历史 ✔ 最常用方案
只迁移 trunk 简化历史 ✔ 很适合
大规模企业 Git 重构 ⚠ 可用但不最佳
复杂 Git 历史重写 ❌ 不适合
长期 SVN + Git 双向开发 ⚠ 可用但维护成本高