因为历史遗留原因需要对公司的某个svn项目迁移到git,记录一下操作流程,以便不时之需。
# 参考链接
- <a href="https://blog.csdn.net/ouyang_peng/article/details/80372805" target="_blank">SVN项目迁移到Git操作指南</a>
- <a href="https://www.jianshu.com/p/5dcf658851f7" target="_blank">SVN项目迁移到Git</a>
# 准备工作
**如下操作是为了将svn的作者信息迁移至git**
1. 进入SVN项目的目录内,右击选择Git Bash Here
2. 使用如下命令获取所有作者名
```shell
svn log --xml | grep -P "^<author" | sort -u | perl -pe 's/<author>(.*?)<\/author>/$1 = $1 <$1\@email.com>/' >> userinfo.txt
```
>在SVN中,每个提交者在主机上有一个用户名,记录在提交信息中。如果想让已有的信息更好的映射到 Git 作者数据里,则需要 从SVN用户名到Git作者的一个映射关系,因为Git是用邮箱来标识一个提交者的。建立一个叫做 userinfo.txt 的文件,每行一条svn作者 = 作者昵称 <邮箱地址>
3. 执行完后会在当前目录输出一个txt文本**userinfo.txt**,打开后会看到类似如下的内容:
```txt
zhangsan = zhangsan <zhangsan@email.com>
lisi = lisi <lisi@email.com>
wangwu = wangwu <wangwu@email.com>
```
4. 请将邮箱替换成真实的邮箱,如果不知道可以选择不改
## 将svn仓库迁移至git
将userinfo.txt文件copy至要迁移的git目录
>例如:
我的userinfo.txt 在d:/work/svn/tmd/userinfo.txt
则将userinfo.txt copy至 d:/work/git/userinfo.txt
1. 打开`Git Bash Here` 执行如下命令
```shell
git svn clone https://21x.14x.x9x.x7x:18080/svn/tdm/ --no-metadata --authors-file=userinfo.txt --trunk=trunk --tags=tags --branches=branches
```
```txt
参数–no-metadata表示阻止git导出SVN包含的一些无用信息
参数–authors-file表示SVN账号映射到git账号文件,所有svn作者都要做映射
参数–trunk表示主开发项目,相当于git中的master
参数–branches表示分支项目,同git中的branch
```
2. 执行后会弹出OpenSSH 要求你输入svn的用户名和密码,输入回车之后会进入一段长时间的等待执行过程,执行过程就是git从svn服务器上拉取代码到本地
3. 拉取成功后可以使用 `git log` 查看历史提交记录,如果不存在,可以关掉 `Git Bash Here` 重新打开 然后再执行 `git log`
# 修复“不存在”的分支
1. 使用 `git branch` 查看分支,会看到只有`master`分支,不要紧看如下操作
2. 使用 `git show-ref` 查看所有引用
```shell
refs/heads/master
refs/remotes/origin/master
refs/remotes/origin/origin/branch_rebuild_201905
refs/remotes/origin/origin/trunk
refs/remotes/origin/origin/uploadOriginalDataByBatches
```
可以看到本地分支只有 `master`
## 将远程分支添加到本地分支
1. 方法一 首先要移动标签,把它们从远程分支变成实际的标签,然后把剩下的分支移动到本地。要把标签变成合适的Git标签,运行
```shell
cp -rf .git/refs/remotes/tags/* .git/refs/tags/
rm -rf .git/refs/remotes/tags
```
该命令将原本以tag/开头的远程标签索引变成真正的本地标签。
接下来,把refs/remotes下面的远程分支索引变成本地分支:
```shell
cp -rf .git/refs/remotes/* .git/refs/heads/
rm -rf .git/refs/remotes
```
合起来就是共执行以下命令
```shell
cp -rf .git/refs/remotes/tags/* .git/refs/tags/
rm -rf .git/refs/remotes/tags
cp -rf .git/refs/remotes/* .git/refs/heads/
rm -rf .git/refs/remotes
```
>执行如上操作时,出现git/refs/remotes/tags/目录不存在,且目录 .git/refs/remotes/origin/tags/ 存在时,请看 [方法二](#method2)
2. <a id="method2">方法二</a> 当出现目录不存在报错后请执行如下命令
```shell
cp -rf .git/refs/remotes/origin/tags/* .git/refs/tags/
rm -rf .git/refs/remotes/origin/tags
cp -rf .git/refs/remotes/origin/* .git/refs/heads/
rm -rf .git/refs/remotes
```
执行成功后,所有的remote分支都变为本地分支,所有的远程标签也变成本地标签。
```txt
* master
branch_rebuild_201905
trunk
uploadOriginalDataByBatches
```
>如果提示 .git/refs/remotes/origin/tags/* 目录不存在 请看 [方法三](#method3)
3. <a id="method3">方法三</a>
使用如下操作:
首先要移动标签,把它们从远程分支变成实际的标签,然后把剩下的分支移动到本地。要把远程标签变成本地的Git标签,运行
```shell
git for-each-ref refs/remotes/tags | cut -d / -f 4- | grep -v @ | while read tagname; do git tag "$tagname" "tags/$tagname"; git branch -r -d "tags/$tagname"; done
```
上述命令将原本以 `tag/` 开头的远程分支的索引变成本地标签。
接下来,把 `refs/remotes` 下面剩下的分支变成本地分支:
```shell
$ git for-each-ref refs/remotes | cut -d / -f 3- | grep -v @ | while read branchname; do git branch "$branchname" "refs/remotes/$branchname"; git branch -r -d "$branchname"; done
```
## push到远程仓库
1. 添加远程地址,执行
```shell
git remote add origin https://git.xxx.com/mikasa/tmd.git
```
2. `push`到远程仓库
执行 `git push origin --all`
3. 如果您的项目中存在标签`tags` 则需要将标签`push`到远程去,执行
`git push -u origin –tags`
4. 查看远程仓库的web页面,是否项目分支、标签以及提交记录都存在。
> 例如 gitee、github、gogs、gitlab
# 同步SVN后续提交的代码
1. 使用 `git branch` 查看远程分支
```txt
* master
branch_rebuild_201905
trunk
uploadOriginalDataByBatches
```
`trunk`分支就是对应 `git svn clone` 生成的远程分支`refs/remotes/origin/trunk`
>切换分支 `git checkout trunk`
2. 如果不存在 `trunk`,使用 `git show-ref`查看远程分支名称,
```txt
refs/heads/master
refs/heads/branch_rebuild_201905
refs/heads/trunk
refs/heads/uploadOriginalDataByBatches
refs/remotes/origin/master
refs/remotes/origin/branch_rebuild_201905
refs/remotes/origin/trunk
refs/remotes/origin/uploadOriginalDataByBatches
```
`remotes/origin/trunk`就是`git svn clone` 生成的远程分支,创建本地分支,使用命令 `git checkout -b trunk remotes/origin/trunk` ,创建并切换到trunk分支。
3. 使用`git svn fetch`命令同步SVN最新的提交记录,然后可以通过 `git log` 命令查看git的提交记录对应的SVN记录相同。
4. 切换到`master`分支,然后merge刚才的trunk分支
```shell
git checkout master # 切换到主分支
git merge trunk # 合并
```
5. 使用 `git push` push到远程分支

SVN项目迁移Git