svn2git vs git-svn

  • svn2git一次性完整迁移,适合永久迁移到 Git
  • git-svn双向同步工具,适合过渡期或需要继续使用 SVN

📋 功能对比表

特性 svn2git git-svn
用途 一次性迁移 双向桥接
分支处理 ✅ 自动转换为 Git 分支 ❌ 保持为远程分支
标签处理 ✅ 自动转换为 Git 标签 ❌ 保持为远程分支
作者映射 ✅ 支持 ✅ 支持
增量迁移 ❌ 不支持 ✅ 支持
双向同步 ❌ 不支持 ✅ 支持
学习曲线 简单 较复杂
适合场景 永久迁移 过渡期/并行使用

svn2git

准备环境

# 1. 安装必要工具
sudo dnf install git subversion ruby ruby-devel gcc make

# 2. 安装 svn2git
sudo gem install svn2git

# 3. 创建工作目录
mkdir ~/svn-migration && cd ~/svn-migration

获取SVN信息

# 查看 SVN 仓库结构
svn list svn://svn-server/
# 应该显示所有仓库列表,如:project1/ project2/

# 查看具体仓库结构
svn list svn://svn-server/project1
# 应该看到:trunk/ branches/ tags/ 或类似结构

# 获取作者列表
svn log --xml svn://svn-server/project1 | \
  grep author | \
  sort -u | \
  perl -pe 's/.*>(.*?)<.*/$1 = $1 <$1@xxxx-it.cn>/' > authors-project1.txt

创建作者映射文件

# 编辑 authors.txt
cat > authors.txt << 'EOF'
lx = 李兴 <lixing@xxxx-it.cn>
zhangsan = 张三 <zhangsan@xxxx-it.cn>
admin = 管理员 <admin@xxxx-it.cn>
(no author) = 未知用户 <unknown@xxxx-it.cn>
EOF

创建项目特定的作者映射

# 获取该项目的历史作者
svn log --xml svn://192.168.1.100/svn/project-a | \
  grep author | \
  sort -u | \
  perl -pe 's/.*>(.*?)<.*/$1 = $1 <$1@xxxx-it.cn>/' > authors-project-a.txt

执行迁移

# 使用 svn2git 迁移
svn2git svn://192.168.1.100/svn/project1 \
  --trunk trunk \
  --branches branches \
  --tags tags \
  --authors authors.txt \
  --verbose 2>&1 | tee migration.log


# 分批次迁移
svn2git svn://server/repo \
  --revision 0:500 \
  --authors authors.txt

# 然后继续
svn2git --revision 501:1000

验证迁移结果

# 进入迁移后的目录
cd project1

# 查看 Git 仓库
git log --oneline | head -10
git branch -a
git tag -l

# 与 SVN 对比
svn log --quiet svn://192.168.1.100/svn/project1 | wc -l
git log --oneline | wc -l

推送到git

# 添加 Gitea 远程仓库
git remote add origin http://gitea.xxxx-it.cn/username/project1.git

# 推送所有分支
git push --all origin

# 推送所有标签
git push --tags origin

参数详解(完整列表)

基本参数

参数 作用 示例
--trunk <path> 指定主干路径 --trunk trunk
--branches <path> 指定分支路径 --branches branches
--tags <path> 指定标签路径 --tags tags
--authors <file> 作者映射文件 --authors authors.txt
--verbose 详细输出 --verbose
--revision <start:end> 迁移指定版本范围 --revision 100:500

高级参数

参数 作用 示例
--username <name> SVN 用户名 --username lixin
--password <pass> SVN 密码 --password Pass123
--metadata 包含 SVN 元数据 --metadata
--exclude <path> 排除特定路径 --exclude branches/old
--preserve-properties 保留 SVN 属性 --preserve-properties

布局参数

参数 作用 使用场景
--notrunk 无主干目录 非标准布局
--nobranches 无分支目录 只有主干
--notags 无标签目录 只有主干和分支

实际执行示例

标准 SVN 仓库迁移

# 假设 SVN 结构:
# svn://192.168.1.100/svn/project1/
# ├── trunk/
# ├── branches/
# └── tags/

svn2git svn://192.168.1.100/svn/project1 \
  --trunk trunk \
  --branches branches \
  --tags tags \
  --authors ./authors.txt \
  --verbose

非标准布局

# 假设 SVN 结构:
# svn://192.168.1.100/project2/
# ├── main/           # 主干
# ├── features/       # 功能分支
# └── releases/       # 发布标签

svn2git svn://192.168.1.100/project2 \
  --trunk main \
  --branches features \
  --tags releases \
  --authors ./authors.txt

只有主干,无分支标签

# 假设 SVN 只有主干:
# svn://192.168.1.100/project3/
# └── src/           # 代码都在这里

svn2git svn://192.168.1.100/project3 \
  --trunk src \
  --nobranches \
  --notags \
  --authors ./authors.txt

主干就是根目录

# 非标准布局(无 trunk)
svn2git svn://server/project \
  --rootistrunk
# 等价于:
svn2git svn://server/project \
  --trunk . \          # 主干就是根目录
  --nobranches \       # 没有分支目录
  --notags            # 没有标签目录

git-svn

自动执行

# 一行命令搞定所有
git svn clone svn://192.168.1.100/svn/project1 \
  --stdlayout \
  --authors-file=authors.txt \
  --username lixing
# 完成!可以直接开始工作
cd project1
git log --oneline
# 只能处理标准参数
git svn clone svn://server/repo \
  -T trunk -b branches -t tags

手动执行

初始化Git仓库

git init

配置

git svn init svn://192.168.1.100/svn/project1 \
  --stdlayout \
  --authors-file=authors.txt

--stdlayout:用于标准 SVN 布局,简化配置
--authors-file:用于美化提交历史,专业规范

获取数据

git svn fetch --username lixin -r 1:500
# 网络中断了?可以继续:
git svn fetch -r 501:HEAD

优化Git仓库

移除SVN相关信息:
在转换过程中,git-svn会在Git仓库中保留一些SVN的元数据。可以使用以下命令移除这些信息:

git config --remove-section svn

压缩Git仓库:
为了减少Git仓库的大小,可以使用以下命令压缩仓库:

git gc --aggressive --prune=now

验证和提交

  1. 检查转换结果
    使用以下命令检查Git仓库的历史记录,确保所有的SVN提交都正确转换为Git提交:
    git log
    
  2. 添加远程仓库
    如果需要将本地Git仓库推送到远程Git仓库,可以使用以下命令添加远程仓库:
    git remote add origin <远程Git仓库的URL>
    
  3. 推送到远程仓库
    将本地的Git仓库推送到远程仓库:
    git push -u origin master