【git学习】SVN项目迁移到Git操作指南
2017年6月份的时候我就着手在公司推广git首先我自己尝试搭建了GitLab来管理代码并且通过以下博客记录了GitLab的搭建以及GitLab备份GitLab升级等事情。git学习------在CenterOS系统上安装GitLab并自定义域名访问GitLab管理页面git学习------如何汉化GitLab转git学习------Git 分支管理最佳实践git学习------ Gitlab如何进行备份恢复与迁移git学习------ 解决Gitlab 版本升级之后发送 merge request 出现 http 500 的返回码错误Git学习–如何通过Shell脚本自动定时将Gitlab备份文件复制到远程服务器?Git学习–如何通过Shell脚本实现 监控Gitlab备份整个过程并且通过邮件通知得到备份结果Git学习–关于Jenkins编译时候如何获取Git分支的当前分支名Git学习–GitLab如何屏蔽掉注册功能Git学习–GitLab如何修改时区但是关于从SVN迁移到Git的具体操作到是没有记录下来只记录了一份博客。git学习------从SVN迁移到Git之后项目开发代码继续在SVN提交如何同步迁移之后继续在SVN提交的代码到Git现在想想今年年初的时候我们部门的软件代码已经全部成功迁移到了GitLab上管理的项目已经达到300GitLab成员已经达到100Group分了60来进行管理整个管理起来有条不紊的权限分配的都很合理。现在我们来讲一讲去年是怎么从SVN迁移到Git的可能很多人这一步都很难走对。因为你要迁移过来但是又不能将原来的SVN的commit记录丢失所以得用一套比较靠谱的方案。当时我自己用我自己的一份代码做好了迁移test之后输出了一份《SVN项目迁移到Git操作指南》然后将每个项目小组的组长包括Android、IOS、Html5等组长都培训了一轮之后大家都成功的将已有的SVN项目迁移到了GitLab上后续的新项目都直接在GitLab上新建了。下面以网易云音乐为例记录SVN代码仓库迁移到GitLab仓库的过程。参考链接在迁移的过程中参考了以下的链接git与svn 共舞走进git时代系列二》 从SVN迁移到GIT教程SVN迁移到Git的过程一些技巧)svn 迁移到git下全过程将代码库从 SVN 迁移至 Git 并保留所有 commit 记录Git 与其他系统 - 迁移到 Git从SVN迁移代码到Git实践总结第一步、建立SVN用户到git用户的映射文件在 Subversion每个提交者在都在主机上有一个用户名记录在提交信息中。如果想让已有的信息更好的映射到 Git 作者数据里则需要 从 Subversion 用户名到 Git 作者的一个映射关系因为Git是用邮箱来标识一个提交者的。建立一个叫做userinfo.txt的文件每行一条svn作者 作者昵称 邮箱地址用如下格式表示映射关系因为项目有ouyangpeng的提交记录所以userinfo.txt内容如下所示ouyangpengouyangpengouyangpengoyp.com现在SVN代码的文件中使用如下命令获取到所有提交者的名字。SVN代码的所有提交者的作者名可以通过以下命令获得获取svn提交的作者名svn log--xml|grep^author|sort-u|\awk-Fauthor{print $2}|awk-F/author{print $1}userinfo.txt得到以下文本然后根据以上的格式编辑作者的邮件信息等。xxx1 xxx2 xxx3 ouyangpeng这样我们的把有svn的提交记录的作者、邮箱userinfo.txt都准备好了接下来就克隆svn的地址。xxx1xxx1xxx1yourcompany.comxxx2xxx2xxx2yourcompany.comxxx3xxx3xxx3yourcompany.comouyangpeng ouyangpengouyangpengoyp.com第二步、通过git svn clone克隆一个git版本库,SVN里面包含trunk,branches和tags。SVN版本库的内容如下所示把上面的userinfo.txt 拷贝到 新建好的准备克隆svn代码的git目录下然后执行git svn clone命令克隆一个git版本库gitsvn clone svn://172.28.xxx.xxx/NetEaseCloudeMusic/ --no-metadata --authors-fileuserinfo.txt--trunktrunk--tagstags--branchesbranches参数–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该命令将原本以tag/开头的远程分支的索引变成真正的轻巧的标签。接下来把refs/remotes下面剩下的索引变成本地分支cp-Rf.git/refs/remotes/* .git/refs/heads/rm-Rf.git/refs/remotes合并一起一共执行4条命令。cp-Rf.git/refs/remotes/tags/* .git/refs/tags/rm-Rf.git/refs/remotes/tagscp-Rf.git/refs/remotes/* .git/refs/heads/rm-Rf.git/refs/remotes尝试方法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/tagscp-rf.git/refs/remotes/origin/* .git/refs/heads/rm-rf.git/refs/remotes现在所有的旧分支都变成真正的分支所有的旧标签也变成真正的标签。执行后效果如下所示可以看到其他的branch都挪到了本地。尝试方法3迁移 WidgetCommon 项目的时候上面两种命令都无效都提示 .git/refs/remotes/origin/tags/* 目录不存在如下图所示没办法去官网查询了下https://git-scm.com/book/zh/v1/Git-%E4%B8%8E%E5%85%B6%E4%BB%96%E7%B3%BB%E7%BB%9F-%E8%BF%81%E7%A7%BB%E5%88%B0-Git使用如下的方法做操作。首先要移动标签把它们从奇怪的远程分支变成实际的标签然后把剩下的分支移动到本地。要把标签变成合适的 Git 标签运行$gitfor-each-ref refs/remotes/tags|cut-d/-f4-|grep-v|whilereadtagname;dogittag$tagnametags/$tagname;gitbranch-r-dtags/$tagname;done该命令将原本以tag/开头的远程分支的索引变成真正的轻巧的标签。接下来把refs/remotes下面剩下的索引变成本地分支$gitfor-each-ref refs/remotes|cut-d/-f3-|grep-v|whilereadbranchname;dogitbranch$branchnamerefs/remotes/$branchname;gitbranch-r-d$branchname;done第三步、添加远程git服务器地址1、添加远程git remote 地址在本地的仓库中增加远程git remote 地址gitremoteaddorigin git172.28.xxx.xxx:AndroidWatch/NetEaseCloudMusic.git2、配置git 的 username 和 emailgitconfig--globaluser.name ouyangpenggitconfig--globaluser.email ouyangpengoyp.com3、执行** git push origin --all** 命令然后执行** git push origin --all** 命令推送到远程Gitlab仓库$gitpush origin--allCounting objects:7210, done. Delta compression using up to8threads. Compressing objects:100%(5548/5548), done. Writing objects:100%(7210/7210),16.08MiB|9.68MiB/s, done. Total7210(delta3588), reused0(delta0)remote: Resolving deltas:100%(3588/3588), done. remote: GitLab: You are not allowed to push code to protected branches on this p roject. To172.28.xxx.xxx:AndroidWatch/NetEaseCloudMusic.git![remote rejected]master -master(pre-receive hook declined)error: failed to push some refs togit 172.28.xxx.xxx:AndroidWatch/NetEaseCloudMu sic.git如上图所示有可能push失败是因为master分支没有给我授予权限push。因为我是管理员所以我在该项目中设置我为master如下图所示将我设置我为master然后就提交成功了。DH207891OuyangPengDH207891 MINGW32 /d/git test/AndroidWatch_NetEaseCloudMusic/ NetEaseCloudeMusic(master)$gitpush-uorigin--allCounting objects:7210, done. Delta compression using up to8threads. Compressing objects:100%(5548/5548), done. Writing objects:100%(7210/7210),16.08MiB|9.87MiB/s, done. Total7210(delta3586), reused0(delta0)remote: Resolving deltas:100%(3586/3586), done. To172.28.xxx.xxx:AndroidWatch/NetEaseCloudMusic.git *[new branch]master -master Branch mastersetup to track remote branch master from origin.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.DH207891OuyangPengDH207891 MINGW32 /d/git test/AndroidWatch_NetEaseCloudMusic/ NetEaseCloudeMusic(master)$gitpush-uorigin--tagsEverything up-to-date第四步、查看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[rootxtgl207940 trunk]# git show-ref9caa27cc211162aeed6e944144f4c676d2f1dfe1 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[rootxtgl207940 trunk]# git checkout -b local-git-svn remotes/git-svn切换到一个新分支local-git-svn[rootxtgl207940 trunk]#第三步同步svn最新的提交记录使用git svn fetch命令同步SVN最新的提交记录然后可以通过git log命令查看git的提交记录对应的svn记录相同。[rootxtgl207940 trunk]# git svn fetch[rootxtgl207940 trunk]# git log第四步切换分支到master分支然后merge刚才的local-git-svn分支[rootxtgl207940 trunk]# git checkout master切换到分支master您的分支与上游分支origin/master一致。[rootxtgl207940 trunk]# git branchdevelop local-git-svn * master[rootxtgl207940 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-2files changed,2insertions(),2deletions(-)[rootxtgl207940 trunk]#第五步提交master分支到GitLab远程仓库第六步查看gitlab上的代码终于将之前写好的指导文件迁移到了CSDN博客上这份指导文件已经完成了它的历史使命因为我们团队内部所有代码都已经成功迁移到了GitLab上SVN已经成为过去式但是这份文件可以分享出来给有需要的人。