Windows下使用PowerShell一键SVN迁移至Git脚本

目录

Git和SVN区别

  • SVN是集中式的,只有中央仓库。Git是分布式的,有本地和远程两仓库
  • SVN是按照文件存储,允许比较混乱的目录的目录结构,如果迁移前,不整理目录,会出现严重的文件混乱
  • SVN的分支是一个目录
  • Git有本地工作区、暂存区、远程仓库。因此代码提交到中央有区别

SVN先add提交到暂存,commit后直接到远程仓库
Git先add提交到暂存,commit后到本地仓库,最后push到远程仓库

Git的服务端与客户端介绍

Git客户端与SVN客户端选择

本教程使用的是Git作为Git客户端,TortoiseSVN作为SVN客户端。

迁移前的准备工作

  • 先在svn规整相关目录
svn路径 git路径
trunk master
tags tags
branches branches

例如在svn的branches有文件夹如下src、test,文件README.md,且历史提交记录里有publish文件夹,那么迁移到git后会生成src、test、publish等分支,但README.md文件会丢失

  • 准备users.txt文件,该文件是svn和git账户的映射关系。有了这个文件以后,会将svn的提交记录同步到git上,否则失败。如果是Visual SVN用户,请务必添加VisualSVN Server的相应映射。以下users.txt文件格式示例:
user=user<user@mail.com>
test=test<test@mail.com>
VisualSVN Server=admin<admin@mail.com>
  • 上述文件也可通过命令生成,需要进入svn项目目录生成,且生成的只有此项目的users.txt文件
# 这是powershell命令
svn.exe log --quiet | ? { $_ -notlike '-*' } | % { "{0} = {0} <{0}>" -f ($_ -split ' \| ')[1] } | Select-Object -Unique | Sort-Object | Out-File 'users.txt' -Encoding utf8

通过生成的users.txt的文件只有此项目的。本迁移脚本需要所有用户的映射关系。迁移过程中,如遭遇xxxx not defined in ./users.txt file就是因为svn用户没在users.txt文件中定义,添加上即可

迁移脚本

  • 本脚本撰写时,svn服务器是被反代理出外网的,为了迁移快一点。会在本地局域网完成迁移以后,再改为远端地址
  • 如果迁移时遭遇如RPC failed; HTTP 413 curl 22 The requested URL returned error: 413,请检查自己的代理软件设置,比如nginx,需要设置client_max_body_size,设置最大请求长度即可。

本脚本基于powershell,且users.txt要求所有用户(包括已被删除的)映射关系,否则报错

# Git本地仓库目录
$gitPath = "D:\Git"
# git 本地Http路径
$gitLocalHttpUrl = "http://192.168.0.2:6610"
# git 远端Http路径,如果全是本地,可以改为和git本地Http地址一致即可
$gitRemoteHttpUrl = "https://git.youurl.com:6547"
# svn 本地Http路径
$svnLocalHttpUrl = "http://192.168.0.2:4782/svn"

# 项目名数组放这里
$data = @(
    [pscustomobject]@{
        # 项目名称
        name = "Project1";
    },
    [pscustomobject]@{
        name = "Project2";
    }
)

# 如果Git路径不存在,那么创建,如果路径已存在,不影响命令继续执行
if (![System.IO.Directory]::Exists($gitPath)) {
    md $gitPath
}

function migrate {
    param (
        [string]$projectName
    )
    # 项目路径
    $projectPath = "$($gitPath)\$($projectName)"
    # 推送分支的临时文件夹,迁移完成后可删除
    $projectBarePath = "$($gitPath)\$($projectName).bare"

    cd $gitPath
    git svn clone $svnLocalHttpUrl/$projectName --prefix=svn/ --no-metadata --trunk=/trunk --branches=/branches --tags=/tags  --authors-file "users.txt" $projectPath
   
    # 添加.ignore相关文件
    cd $projectPath
    git svn show-ignore --id=svn/trunk > .gitignore
    git add .gitignore
    git commit -m 'Convert svn:ignore properties to .gitignore.'

    # 准备迁移分支
    git init --bare $projectBarePath
    cd $projectBarePath
    git symbolic-ref HEAD refs/heads/svn/trunk

    # 推送分支到空目录
    cd $projectPath
    git remote add bare $projectBarePath
    git config remote.bare.push refs/remotes/*:refs/heads/*
    git push bare

    # 更正分支名
    cd $projectBarePath
    git branch -m svn/trunk master
    # 将svn标记迁移到git标记 这句代码要求严格的文件结构,如果不符合规范,会漏掉branches和tags
    # git for-each-ref --format='%(refname)' refs/heads/svn/tags | % { $_.Replace('refs/heads/svn/tags/','') } | % { git tag $_ "refs/heads/svn/tags/$_"; git branch -D "svn/tags/$_" }
    # 将所有svn分支创建为适当的git分支。这条命令会将所有branches、tags都创建为对应的git的branches,需要后期手动处理相关
    git for-each-ref --format='%(refname)' refs/remotes | % { $_.Replace('refs/remotes/', '') } | % { git branch "$_" "refs/remotes/$_"; git branch -r -d "$_"; }

    # 推送文件到远端
    git remote add origin $gitLocalHttpUrl/$projectName
    git push origin --all

    # 如果路径名不等,那么设置最新地址
    if (!"$($gitLocalHttpUrl)/$($projectName)".Equals("$($gitRemoteHttpUrl)/$($projectName)")) {
        git remote set-url origin $gitRemoteHttpUrl/$projectName
    }

    # 将.ignore单独推送,之前执行的命令会漏掉这个文件
    cd $projectPath
    git remote add origin $gitRemoteHttpUrl/$projectName
    git push origin --all
}

foreach ($curr in $data) {
    try {
        Write-Host 开始迁移 $curr.name 数据
        migrate -projectName $curr.name
    }
    catch {
        Write-Host "发生异常:$_"
        break
    }
}

本脚本主要参考以下教程

了解如何从 Subversion (SVN) 迁移到 Git(包括历史记录)
svn迁移到gitlab

posted @ 2024-10-29 13:11  全面回憶  阅读(23)  评论(0编辑  收藏  举报