2017年6月份的时候,我就着手在公司推广git,首先我自己尝试搭建了GitLab来管理代码,并且通过以下博客记录了GitLab的搭建,以及GitLab备份,GitLab升级等事情。

但是关于从SVN迁移到Git的具体操作到是没有记录下来,只记录了一份博客。

现在想想,今年年初的时候,我们部门的软件代码已经全部成功迁移到了GitLab上,管理的项目已经达到300+,GitLab成员已经达到100+,Group分了60+来进行管理,整个管理起来有条不紊的,权限分配的都很合理。

现在我们来讲一讲,去年是怎么从SVN迁移到Git的,可能很多人这一步都很难走对。因为你要迁移过来,但是又不能将原来的SVN的commit记录丢失,所以得用一套比较靠谱的方案。当时我自己用我自己的一份代码做好了迁移test之后,输出了一份《SVN项目迁移到Git操作指南》,然后将每个项目小组的组长包括Android、IOS、Html5等组长都培训了一轮之后,大家都成功的将已有的SVN项目迁移到了GitLab上,后续的新项目都直接在GitLab上新建了。


下面以网易云音乐为例,记录SVN代码仓库迁移到GitLab仓库的过程。

参考链接

在迁移的过程中,参考了以下的链接:

第一步、建立SVN用户到git用户的映射文件

在 Subversion,每个提交者在都在主机上有一个用户名,记录在提交信息中。如果想让已有的信息更好的映射到 Git 作者数据里,则需要 从 Subversion 用户名到 Git 作者的一个映射关系,因为Git是用邮箱来标识一个提交者的。建立一个叫做 userinfo.txt 的文件,每行一条svn作者 = 作者昵称 <邮箱地址>,用如下格式表示映射关系:

因为网易云音乐这个项目有ouyangpeng和huxiaoqiao的提交记录,所以userinfo.txt内容如下所示:

ouyangpeng = ouyangpeng <ouyangpeng@oaserver.dw.gdbbk.com>
huxiaoqiao = huxiaoqiao <huxiaoqiao@oaserver.dw.gdbbk.com>
  • 1
  • 2

现在SVN代码的文件中,使用如下命令获取到所有提交者的名字。

SVN代码的所有提交者的作者名可以通过以下命令获得:

获取svn提交的作者名

svn log --xml | grep "^<author" | sort -u | \awk -F '<author>' '{print $2}' | awk -F '</author>' '{print $1}' > userinfo.txt
  • 1

得到以下文本,然后根据以上的格式编辑作者的邮件信息等。

lihongmeng
liyang
wangshuyin
wuqi
youpeng
ouyangpeng
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这样我们的把有svn的提交记录的作者、邮箱userinfo.txt都准备好了,接下来就克隆svn的地址。

lihongmeng = lihongmeng <lihongmeng@oaserver.dw.gdbbk.com>
liyang = liyang <liyang@oaserver.dw.gdbbk.com>
wangshuyin = wangshuyin <wangshuyin@oaserver.dw.gdbbk.com>
wuqi = wuqi <wuqi@oaserver.dw.gdbbk.com>
youpeng = youpeng <youpeng@oaserver.dw.gdbbk.com>
ouyangpeng = ouyangpeng <ouyangpeng@oaserver.dw.gdbbk.com>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

第二步、通过git svn clone克隆一个git版本库,SVN里面包含trunk,branches和tags。

SVN版本库的内容如下所示:

把上面的userinfo.txt 拷贝到 新建好的准备克隆svn代码的git目录下, 
然后执行 git svn clone命令克隆一个git版本库

 git svn clone svn://172.28.1.171/XTCWatch_device_I3_APP/NetEaseCloudeMusic/ --no-metadata --authors-file=userinfo.txt --trunk=trunk --tags=tags --branches=branches
  • 1
  • 参数–no-metadata表示阻止git导出SVN包含的一些无用信息
  • 参数–authors-file表示SVN账号映射到git账号文件,所有svn作者都要做映射
  • 参数–trunk表示主开发项目
  • 参数–branches表示分支项目

敲完命令后,会要求填写SSH相关信息,填写好svn的账户名和密码 即可继续执行。

填写用户名

填写密码

填写完毕后,回车则会开始执行clone操作。

执行过程中,在不断的从svn服务器拉取代码到本地git版本库

使用git log 命令查看转换好的代码库,可以看到历史记录

widgetPhone的提交历史记录如下:

这个时候执行* git branch* 命令发现只有 master一个分支。

但是实际上我有好几个分支, 
APP_NetEaseCloudMusic_SearchSongs , 
APP_NetEaseCloudMusic_UseByAnonymous, 
App_NetEaseCloudMusic_V0.1_backup

执行命令 git show-ref可以看到所有的引用,如下所示, 
可以看到有master这个本地分支,同时有remote 分支trunk, APP_NetEaseCloudMusic_SearchSongs , APP_NetEaseCloudMusic_UseByAnonymous, 
App_NetEaseCloudMusic_V0.1_backup 等,

通过Git Version 发现trunk 和 Master分支的版本是一样的, 其他几个分支和SVN客户端branches 目录下的结构是一样的。 说明 git svn 将svn的主干和其他分支 转换为了git的 master 和其他branch 。

这时我们发现有一些remote 分支,不是本地仓库的分支, 我们还没有设置remote, 那就需要执行以下的命令将remote 分支移回本地分支。

尝试方法1

首先要移动标签,把它们从奇怪的远程分支变成实际的标签,然后把剩下的分支移动到本地。要把标签变成合适的Git标签,运行

cp -Rf .git/refs/remotes/tags/* .git/refs/tags/
rm -Rf .git/refs/remotes/tags
  • 1
  • 2

该命令将原本以tag/开头的远程分支的索引变成真正的(轻巧的)标签。

接下来,把refs/remotes下面剩下的索引变成本地分支:

cp -Rf .git/refs/remotes/* .git/refs/heads/
rm -Rf .git/refs/remotes
  • 1
  • 2

合并一起一共执行4条命令。

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

尝试方法2

在迁移 WidgetPhone 的时候,git/refs/remotes/tags/目录不存在,而目录.git/refs/remotes/origin/tags/存在,于是命令改为

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

现在所有的旧分支都变成真正的分支,所有的旧标签也变成真正的标签。 
执行后效果如下所示,可以看到其他的branch都挪到了本地。

尝试方法3

迁移 WidgetCommon 项目的时候,上面两种命令都无效,都提示 .git/refs/remotes/origin/tags/* 目录不存在,如下图所示:

没办法,去官网查询了下

使用如下的方法做操作。

首先要移动标签,把它们从奇怪的远程分支变成实际的标签,然后把剩下的分支移动到本地。要把标签变成合适的 Git 标签,运行

$ 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
  • 1

该命令将原本以 tag/ 开头的远程分支的索引变成真正的(轻巧的)标签。

接下来,把 refs/remotes 下面剩下的索引变成本地分支:

$ 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
  • 1

第三步、添加远程git服务器地址

1、添加远程git remote 地址

在本地的仓库中,增加远程git remote 地址:

git remote add origin git@172.28.10.23:AndroidWatch/NetEaseCloudMusic.git
  • 1

2、配置git 的 username 和 email

git config --global user.name ouyangpeng
git config --global user.email ouyangpeng@oaserver.dw.gdbbk.com
  • 1
  • 2
  • 3

下面是配置好的内容

3、执行* git push origin –all* 命令

然后执行* git push origin –all* 命令,推送到远程Gitlab仓库

$ git push origin --all
Counting objects: 7210, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (5548/5548), done.
Writing objects: 100% (7210/7210), 16.08 MiB | 9.68 MiB/s, done.
Total 7210 (delta 3588), reused 0 (delta 0)
remote: Resolving deltas: 100% (3588/3588), done.
remote: GitLab: You are not allowed to push code to protected branches on this p roject.
To 172.28.10.23:AndroidWatch/NetEaseCloudMusic.git
! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'git@172.28.10.23:AndroidWatch/NetEaseCloudMu sic.git'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

如上图所示,有可能push失败,是因为master分支没有给我授予权限push。 
因为我是管理员,所以我在该项目中,设置我为master,如下图所示:

将我设置我为master

然后就提交成功了。

DH207891+OuyangPeng@DH207891 MINGW32 /d/git test/AndroidWatch_NetEaseCloudMusic/                                                                                            NetEaseCloudeMusic (master)
$ git push -u origin --all
Counting objects: 7210, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (5548/5548), done.
Writing objects: 100% (7210/7210), 16.08 MiB | 9.87 MiB/s, done.
Total 7210 (delta 3586), reused 0 (delta 0)
remote: Resolving deltas: 100% (3586/3586), done.
To 172.28.10.23:AndroidWatch/NetEaseCloudMusic.git
* [new branch] master -> master
Branch master set up to track remote branch master from origin.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

4、执行 git push -u origin –tags 命令

如果你的项目有Tags的话,上面最后部分git push -u origin –all,运行之后并不能如它所说,分支和标签(branches and tags)都在gitlab服务器中。

实际上,只提交了branches到gitlab上面,并没有提交tags,当然,很简单,你可以使用git push –h查看下帮助,就会发现,你应该知道怎么做了,使用git push –tags就可以了。

执行下面命令即可,由于网易并没有建立tags,所以没有任何代码push到gitlab.

DH207891+OuyangPeng@DH207891 MINGW32 /d/git test/AndroidWatch_NetEaseCloudMusic/                                                                                            NetEaseCloudeMusic (master)
$ git push -u origin --tags
Everything up-to-date
  • 1
  • 2
  • 3
  • 4

第四步、查看gitlab上面是否正常提交

master分支

点击master下拉框,切换分支

切换到 APP_NetEaseCloudMusic_SearchSongs 分支 

查看commit 提交记录

切换到 Branch 选项 可以查看所有的 Branch

第四步、定期同步SVN后续提交的代码到Git仓库

第一步,通过git show-ref命令查看分支情况

其中 refs/remotes/git-svn 分支就是刚才用git svn clone 之后的远程分支,可以在本地建立一个分支来同步svn后续的提交记录

第二步,建立本地分支 local-git-svn 对应远程分支git-svn

[root@xtgl207940 trunk]# git show-ref
9caa27cc211162aeed6e944144f4c676d2f1dfe1 refs/heads/develop
9caa27cc211162aeed6e944144f4c676d2f1dfe1 refs/heads/master
0ba94e3383d6f478844b1e674465fbc6ae0277e3 refs/remotes/git-svn
9caa27cc211162aeed6e944144f4c676d2f1dfe1 refs/remotes/origin/develop
62333dcb3beeb73e28538f815abfdfe791b88c00 refs/remotes/origin/local-git-svn
9caa27cc211162aeed6e944144f4c676d2f1dfe1 refs/remotes/origin/master
[root@xtgl207940 trunk]# git checkout -b local-git-svn remotes/git-svn
切换到一个新分支 'local-git-svn'
[root@xtgl207940 trunk]#
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

第三步,同步svn最新的提交记录 
使用 git svn fetch 命令同步SVN最新的提交记录,然后可以通过 git log命令查看git的提交记录对应的svn记录相同。

[root@xtgl207940 trunk]# git svn fetch
[root@xtgl207940 trunk]# git log
  • 1
  • 2
  • 3

第四步,切换分支到master分支,然后merge刚才的local-git-svn分支

[root@xtgl207940 trunk]# git checkout master
切换到分支 'master'
您的分支与上游分支 'origin/master' 一致。
[root@xtgl207940 trunk]# git branch
develop
local-git-svn
* master
[root@xtgl207940 trunk]# git merge local-git-svn
更新 9caa27c..0ba94e3
Fast-forward
watch/src/main/java/com/xtc/watch/view/contact/activity/ContactPhoneActivity.java | 2 +-
watch/src/main/res/values/strings.xml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
[root@xtgl207940 trunk]#
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

第五步,提交master分支到GitLab远程仓库

第六步,查看gitlab上的代码


终于将之前写好的指导文件迁移到了CSDN博客上,这份指导文件已经完成了它的历史使命,因为我们团队内部所有代码都已经成功迁移到了GitLab上,SVN已经成为过去式,但是这份文件可以分享出来给有需要的人。

<p>1、查询端口号占用,根据端口查看进程信息</p>的更多相关文章

  1. cmd批处理bat命令根据端口号一键关闭杀死对应进程程序

    @ 目录 cmd批处理bat命令根据端口号一键关闭杀死对应进程程序 使用场景和功能介绍 主界面 下载地址 源代码 cmd批处理bat命令根据端口号一键关闭杀死对应进程程序 使用场景和功能介绍 java ...

  2. 解决xmapp中Apache端口号占用问题

    [原]解决 "安装xmapp后Apache不能正常启动" 问题 小伙伴们安装xmapp后发现Apache不能正常开启,下面给出了不同情况的解决办法,可以分为以下几种情况分析问题: ...

  3. tomcat 端口被占用 项目端口号被占用怎么解决

    1.Win+R  打开运行 ,输入cmd 打开命令行窗口 . 2.假设要查询端口被占用情况,在命令行下输入:netstat  -aon|findstr  "8883" 3.得到进程 ...

  4. tomcat解决端口号占用问题

    1.第一种方法 更改tomcat自己的端口号: conf 目录下 找到 server.xml,把默认的8080端口改个别的试试,tomcat 一般端口号改的要大于 6000,. 2.第二种方法 关闭端 ...

  5. linux 下查看进程占用端口和端口号占用进程命令

    linux 下查看进程占用端口:(1)查看程序对应的进程号: ps -ef | grep 进程名字 (2)查看进程号所占用的端口号: netstat -nltp | grep  进程号 ubuntu ...

  6. linux查看端口号占用命令-netstat

    题记 经常会发现,很多时候我们在运行一些带有端口的程序时,程序经常会报端口被占用的问题,比如Tomcat 8080,端口起不来. 查看端口号 netstat 如果发现某个端口被占用后,可以用命令查看, ...

  7. (一)Spring Boot修改内置Tomcat端口号--解决tomcat端口被占用的问题

    Spring Boot 内置Tomcat默认端口号为8080,在开发多个应用调试时很不方便,本文介绍了修改 Spring Boot内置Tomcat端口号的方法. 一.EmbeddedServletCo ...

  8. IntelliJ IDEA 2017版 spring-boot修改端口号配置把端口号改为8081

    1.修改端口号主要是通过配置文件修改.如图: 完整版配置 ######################################################## ###server 配置信息 ...

  9. 解决端口被占用问题(端口timewait)

    当jmeter做千级并发时,有报错的接口,查看是不是本地端口被占用完了 netstat -an   查看是否有端口在 timewait timewait是知道用那个端口,但是端口被别人占用着 见tcp ...

  10. linux下mysql 查看默认端口号与修改端口号方法

    一.查看默认端口号 1.登录mysql [root@localhost ~]# mysql -uroot -pEnter password: 输入数据库密码: 2.使用show global vari ...

随机推荐

  1. Andrew Ng机器学习公开课笔记 -- Logistic Regression

    网易公开课,第3,4课 notes,http://cs229.stanford.edu/notes/cs229-notes1.pdf 前面讨论了线性回归问题, 符合高斯分布,使用最小二乘来作为损失函数 ...

  2. rbac - 初识

    一.rbac 权限组件 1 项目与应用 一个项目,可以有多个应用 一个应用,可以在多个项目下 前提:应用是组件!! 2 什么是权限? 一个包含正则表达式url就是一个权限 who what how - ...

  3. JS模块化方案

  4. mysql int 整数类型 解释显示宽度 和 存储宽度

    存储宽度 是实际存储记录宽度 存储宽度默认是写死的,就算修改宽度也改变不了,改变的是显示宽度 ============有符号和无符号int============= 创建一个 无符号的 int 整数类 ...

  5. mysql中的多行查询结果合并成一个(转)

    SELECT GROUP_CONCAT(md.data1) FROM DATA md,contacts cc WHERE md.conskey=cc.id AND md.mimetype_id= 5 ...

  6. PHP对象转数组

    Solution json_decode( json_encode( $obj ), true ): But why?You should have a look at the function na ...

  7. soapUI-DataSource Loop

    1.1.1  DataSource Loop 当我们需要遍历某DataSource中的所有内容时.需要在TestCase中添加DataSource Loop步骤,然后双击它进行配置,如下图所示: Op ...

  8. testng日志和报告

    TestNG是通过 Listeners 或者 Reporters 生成测试报告. Listeners,即 org.testng.ITestListener 的实现,能够在测试执行过程中发出各种测试结果 ...

  9. PHP实现返回JSON和XML的类分享

    PHP实现返回JSON和XML的类分享 <?php     class Reponse{         //private $result = array('code'=null,'messa ...

  10. .Ignite是什么

    Ignite是什么 Apache Ignite内存数据组织是高性能的.集成化的以及分布式的内存平台,他可以实时地在大数据集中执行事务和计算,和传统的基于磁盘或者闪存的技术相比,性能有数量级的提升.  ...