Gitea:从SVN迁移到Git

目录

环境信息

迁移步骤


SVN和Git都是优秀的版本管理工具。不幸的是,对于从SVN迁移到Git的过程、命令和说明,网上不少文章存在误导性。因此本文以Gitea为例,演示从SVN迁移到Git的详细过程。

本文前提条件:

  • 已经完成Gitea安装(含Git软件安装)
  • 在Gitea中,已完成了初始配置并正常运行
  • 在Gitea中,根据需要配置Organization、Teams、User Accounts等组织协作信息(可选)
  • 在Gitea中,已经创建Repository(这里名字为:gsyspm,无需对该Repository初始化)

环境信息

在以上git Repository创建完成且未被初始化的情况下,需要从原SVN仓库迁移导入至Git,包括在SVN的提交Commit 和作者log日志。需要导出的SVN信息:

  • SVN仓根URL:http://20.1.1.11:7001/usvn/svn/sys_pm
  • SVN仓中trunk相对于根的路径:pmis/01develop/02code/trunk
  • SVN仓中branches相对于根的路径:pmis/01develop/02code/branches
  • SVN仓中没有Tags信息
  • 需要迁移的SVN版本号范围:从1至HEAD

迁移步骤

以下步骤通过git svn命令完成从SVN至Git的迁移:

1、在任意PC电脑上(能够访问SVN和Gitea)创建迁移临时用目录:migrate_svn_to_git/

2、进入该目录。创建文本authors_map.txt,存放SVN作者至Git作者映射信息文件,格式形式如下:

loginname=JoeUser<[email protected]>

     

或者可通过以下方式自动生成该作者映射文件。

   进入本地既有的SVN目录(该目录已经完成从SVN checkout至最新)通过以下命令生成(在Bash中执行)authors_map.txt文件,然后将生成得到的该txt文件拷贝至 migrate_svn_to_git/ 目录下:

svn log -r 1:HEAD --xml | grep "<author" | sort -u | awk -F '<author>' '{print $2}' | awk -F '</author>' '{print $1"="$1"<"$1"@yykj.com>" }'  > authors_map.txt


3、通过以下两条git svn命令从SVN仓导出至本地(在Bash中执行):

#以SVN仓根URL对当前本地目录进行git初始化
git svn init http://20.1.1.11:7001/usvn/svn/sys_pm --prefix fromsvn/ --no-metadata --username=LOGIN_SVNUSER  --trunk=pmis/01develop/02code/trunk --branches=pmis/01develop/02code/branches 



#从SVN仓导出到本地git仓中(耗时可能很长甚至几天几夜)
git svn fetch  -r 1:HEAD --authors-file=authors_map.txt

选项说明:

  • --prefix  指定“.git/”和“.git/svn/”目录下的"refs/remotes/$prefix/"中的prefix值(该值末尾有斜杠),若不指定,默认为“origin/”(可近似理解为远端SVN仓的别名,之所以说近似是因为它不是标准的git远端仓库的概念,通过git remote命令也无法显示此别名)
  • --no-metadata  不导出SVN元数据信息(导出时本地不会生成.svn目录)。若还需要从git反向导入至git,需要导出SVN元数据信息,则不能使用此选项
  • --username  指定登录SVN用户名。若不指定,则以当前登录操作系统用户作为默认SVN登录名
  • --trunk --branches --tags  SVN的标准结构是主干/分支/Tags的目录命名是"trunk/branches/tags"且它们直接在SVN仓根目录下,对于标准机构则应把选项改为--stdlayout(或-s)。由于我们这里SVN不是标准若SVN结构(主干分支目录命名符合标准,但不是直接放在SVN仓根目录下),所以通过--trunk及--branches分别指定其相对于SVN仓根目录的相对路径
  • -r 指定导出的SVN版本号起止范围
  • --authors-file  指定从SVN作者到git作者的映射文件。若SVN中存在的提交作者范围超出该映射文件范围,则会报错而中止

4、导出后tags和branch信息在.git/svn/目录下,需要先据此创建git本地tags和branch,然后待后面步骤推送至gitea的远端。即,tags和branch的refs信息有三类:

  • SVN的remote远端refs信息(导出后,存放在.git/svn/refs/remotes目录下)
  • git本地仓的refs信息(存放在.git/refs目录下)
  • git的remote远端refs信息(存放在.git/refs/remotes目录下)

通过以下命令将“SVN的remote远端refs信息”转换为“git本地仓的refs信息”,然后清理删除“SVN的remote远端refs信息”:(在Bash中执行)

#先for循环调整tags(其中“fromsvn”为前文指定的--prefix)
for t in $(git for-each-ref --format='%(refname:short)' refs/remotes/fromsvn/tags);
do
    tagname=${t/fromsvn\/tags\//}
    git tag ${tagname} $t && git branch -D -r $t;
done;

【注】refs在git内部就是指针,指向40字节的SHA-1哈希值。命令中refs/remotes为指向远程各分支的head指针,refs/tags本地tags列表。

命令说明:

  • git for-each-ref  git命令,列出匹配指定模式的git内部refs(包括“.git/”和“.git/svn/”目录下的)并以指定的格式输出。对于Tag输出形式:refs/remotes/fromsvn/tags/XXX(其中fromsvn为前文指定的--prefix)。可查看通过git svn初始化命令生成的.git/config文件内容,找到SVN Tag映射到git本地refs名字。
  • ${ t/fromsvn\/tags\//}  Bash语法。结构为${ VAR/PATTERN/NEWSTRING},将变量值进行正则匹配并替换。这里的意思为将变量值中“fromsvn/tags/”字符串删除。
  • git tag <tagname> <object>  在git本地创建tag。tagname为经过正则处理后的字符串;若不指定<object>,则tag默认以当前HEAD的版本号创建。这里不使用默认值,通过<object>指定为:该refs 的Hash值
  • git branch-D -r  删除remote远端refs信息
#然后再for循环调整branch(其中“fromsvn”为前文指定的--prefix)
for b in $(git for-each-ref --format='%(refname:short)' refs/remotes/fromsvn);
do
    branchname=${b/fromsvn\//}
    git branch ${branchname,,} refs/remotes/$b && git branch -D -r $b;
done;

命令说明: 

  • git for-each-ref  git命令,列出匹配指定模式的git内部refs(包括“.git/”和“.git/svn/”目录下的)并以指定的格式输出。对于branch输出形式:refs/remotes/fromsvn/XXX(其中fromsvn为前文指定的--prefix)。可查看通过git svn初始化命令生成的.git/config文件内容,找到SVN branch映射到git本地refs名字。
  • ${ branchname,,}  Bash语法。结构为${ VAR,,},将表示将变量值全部转为小写。
  • git branch <branchname> <start-point>  在git本地创建branch。若不指定<start-point>,则Branch默认以当前HEAD的版本号创建。这里不使用默认值,通过<start-point>指定为:该refs 的Hash值
  • git branch-D -r  删除remote远端refs信息

5、转换ignore文件(根据实际需要选择是否执行,此处不执行)

git svn show-ignore > .gitignore
git add .gitignore
git commit -m 'Convert svn:ignore properties to .gitignore'


6、其他调整。以上处理完成后,应检查分支和tag项是否正确,若需要重命名或删除历史不用的branch/tags等,则可以通过手工执行git命令完成。

7、查看并检查结果(在Bash中执行)
8、至此已经完成从SVN到git本地迁移工作。

git branch
git log
git tag

9、下一步,从git本地推送到gitea远端仓(在Bash中执行):

#增加git远端仓定义
git remote add origin_base http://20.200.54.51:3000/gsyspm/base_repos.git


#将本地仓所有分支推送至远端仓(若弹出输入用户密码,请输入gitea_admin用户和密码)
git push --all origin_base


#将本地仓所有tag信息推送至远端仓(若弹出输入用户密码,请输入gitea_admin用户和密码)
git push --tags origin_base

选项说明:

  • --all  将本地所有branch分支全部都推送至远端仓(不推送tag信息)。
  • --tags  在git push中的--tag选项表示将本地仓所有tag信息推送至远端仓(不推送branch分支)。

10、通过浏览器查看gitea服务端的结果。

猜你喜欢

转载自blog.csdn.net/zyplanke/article/details/124468631