如何把 SVN 仓库迁移到 Git 并保留历史
SVN 迁移 Git 用 git svn clone:准备作者映射文件(users.txt),git svn clone --stdlayout --authors-file 完整转换历史、分支、标签,再清理引用推到 Git 远程。大仓库建议通宵跑。
官方工具 git svn clone 能把 SVN 的完整历史(提交、分支、标签)转换成 Git。 关键准备是作者映射文件——SVN 用户名要映射成 Git 的"名字 <邮箱>"格式。
迁移步骤
# 1. 生成作者映射(从 SVN 日志提取所有提交者)
svn log -q https://svn.company.com/repo | awk -F '|' '/^r/ {print $2" = "$2" <"$2"@company.com>"}' | sort -u > users.txt
# 手工把 users.txt 里的名字和邮箱改规范
# 2. 克隆转换(trunk/branches/tags 标准布局)
git svn clone https://svn.company.com/repo --stdlayout --authors-file=users.txt --no-metadata my-repo
cd my-repo
--stdlayout 对应标准的 trunk/branches/tags 结构;非标准布局用 -T/-b/-t 单独指定。
转换后的清理
# SVN 的分支/标签会变成 refs/remotes/ 下的引用,转成真正的 Git 分支和标签
git for-each-ref refs/remotes/tags | cut -d / -f 4- | while read t; do git tag "$t" "refs/remotes/tags/$t"; git branch -r -d "tags/$t"; done
git for-each-ref refs/remotes | cut -d / -f 3- | while read b; do git branch "$b" "refs/remotes/$b"; done
# 推到新远程
git remote add origin git@github.com:org/repo.git
git push --all && git push --tags
注意事项
- 大仓库转换可能跑数小时,建议服务器上执行;
- SVN 的 svn:ignore 转成 .gitignore(
git svn show-ignore); - 迁移期冻结 SVN 写入,或切只读。
常见问题(FAQ)
Q:迁移后还能回 SVN 吗?
git svn 支持双向(dcommit 回推 SVN),但过渡期越长同步成本越高。建议一刀切,SVN 归档只读。
Q:SVN 的目录拷贝式分支在 Git 里什么样?
git svn 会尽量识别为真正的分支。历史特别乱的老仓库可能有部分分支识别不全,接受"近期历史准确、远古历史可能粗糙"的现实。
Q:有没有更现代的工具?
reposurgeon、svn2git(基于 git svn 的封装,处理分支标签更自动化)。数据量大或布局怪异时值得试。