每一个可以努力的日子,都是一份厚礼。
将代码库从 SVN 迁移至 Git 并保留所有 commit 记录
公司内部原本使用 SVN 进行版本控制,但随着 Github 的流行我个人的代码管理习惯逐渐转变。虽然公司项目并非开源,SVN 所具有的标准 trunk / branches / tags 结构完全够用,使用 Git 仍然有如下优势:
- 类似 GitHub 的 GitLab 免费管理工具。将代码托管在自己内部服务器上的同时,提供了优美的 web 界面,图形化分支结构,更直观的代码审查,统计、issue 系统、wiki 等功能全面集成。
- 更方便主程做 code review,控制代码质量。创建主仓库,多人开发时使用 fork 模式,每个人拥有自己独立的 repo,独立的 trunk / branches,最后发送 pull request 进行代码合并。
- commit 和 push 更快。体现在 push 到远程仓库时 Git 会先对所有需要上传的文件进行 zip 打包压缩,然后一次性传输,在远程服务器解压,全部自动完成。而 SVN 则是一个一个文件地上传,代码是纯文本,总体积并不大,但是大量零碎的小文件频繁建立网络连接造成延迟。这在升级第三方的库或者框架时,成千上万的文件更新更加让人难以忍受。
- hook 可以更方便做自动化部署。当然这个 SVN 也有。
权衡后我决定花时间进行代码仓库的迁移。代码迁移并非简单地创建 Git repo 把当前项目代码一次性 commit 过去就够了,因为 SVN 中存有长年累月的 commit 历史记录,丢失历史记录将对今后追溯 debug 造成非常大的麻烦,所以如何保留 commit 记录就是迁移的关键。
一、迁移步骤
创建用户映射 (例如 users.txt
) ,将 SVN 用户和 Git 用户对应起来:
user1 = First Last Name <[email protected]>
user2 = First Last Name <[email protected]>
…
如果上面的文件中有用户缺失,后面的 SVN 命令将会停止。不过你可以更新用户映射然后接着再来(类似断点续传)。
现在从 SVN 仓库中拉取所有数据:
git svn clone --stdlayout --no-metadata -A users.txt svn://hostname/path dest_dir-tmp |
这个命令将会在 dest_dir-tmp
新建一个 Git repo,并开始从 SVN 中拉取代码。请注意 “--stdlayout
” 参数表示你的项目在 SVN 中是常见的 “trunk/branches/tags
” 目录结构,如果不是,那你需要使用 --tags
, --branches
, --trunk
参数(请通过 git svn help
自行了解)。
再后面的参数是 SVN 的地址,一些常见协议都是支持的 : svn://
, http://
, https://
. 注意这个 URL 应该指向项目的 base repository,例如 http://svn.mycompany.com/myrepo/repository
. 不要指到了 /trunk
, /tag
或 /branches
里。
如果出现用户名没找到,更新你的 users.txt
文件,然后
cd dest_dir-tmp git svn fetch |
如果你的项目非常大,你可能需要重复上面的命令好几次,直到所有的 SVN commit 都被抓下来了:
git svn fetch |
完成后,Git 将会 checkout SVN 的 trunk 到一个新的 Git branch,而其他的 SVN branch 将会设为 Git remote,你可以查看所有的 SVN branch:
git branch -r |
如果你想在你的 Git repo 中保留其他的 remote branch,你需要手动创建本地 branch。否则,SVN 的 branch 将不会在最后被 clone。
git checkout -b local_branch remote_branch # it's ok if local_branch and remote_branch are the same name |
SVN tags 被当作 branch 导入了,你需要创建本地 branch,打一个 tag,然后删掉那个 branch,这样才会在 Git 中生成 tag。例如 SVN tag “v1”:
git checkout -b tag_v1 remotes/tags/v1 git checkout master git tag v1 tag_v1 git branch -D tag_v1 |
把上面的 GIT-SVN repo Clone 到一个全新的干净 git repo:
git clone dest_dir-tmp dest_dir rm -rf dest_dir-tmp cd dest_dir |
之前从 remote branch 创建的本地 branch 又会在新 clone 的 repo 中成为 remote branch,于是对每个 branch 再做一次:
git checkout -b local_branch origin/remote_branch |
最后,从干净的 Git repo 中删掉 remote (指向我们刚刚已经删掉的 temp repo)
git remote rm origin |
这样一个全新 Git repo 就已经从 SVN 迁移好了。
二、新的 Git 远程仓库
将本地的 Git repo push 到远程仓库(我这里用的是 GitLab):
git remote add origin git@git.udev.hk:udba/udba.git git push -u origin master |
push 所有的 branch:
git push origin --all |
push 所有的 tag:
git push origin --tags |
最后再放两张 GitLab 的截图
– EOF –
这篇文章由lovelucy于2014-05-15 19:28发表在编程。你可以订阅RSS 2.0 也可以发表评论或引用到你的网站。除特殊说明外文章均为本人原创,并遵从署名-非商业性使用-相同方式共享创作协议,转载或使用请注明作者和来源,尊重知识分享。 |
批评不自由
则赞美无意义
Google Chrome 44.0.2403.89 Linux 大约9年前
You can try subgit. It has always been a pita to clone huge SVN repositories for me (memory intensive, 10+ hours or even days to complete)
Google Chrome 39.0.2166.2 Windows 7 大约10年前
coding最近支持了SVN自动转换成Git 骚年 😛
Google Chrome 48.0.2564.97 Mac OS X 10_10_5 大约8年前
少年,coding不支持私有的svn仓库的转换
Safari 9537.53 iPhone iPhone OS 7_1_1 like Mac OS X) AppleWebKit 大约10年前
博主,iphone的unblock youku不行了,趕緊弄一個急救唄!!
Mozilla Firefox 29.0 Windows 7 大约10年前
学习了,很好很强大
Mozilla Firefox 29.0 Linux 大约10年前
注意git svn命令的时候使用–prefix,否则很容易把远程分支搞混
Google Chrome 34.0.1847.131 Windows 7 大约10年前
感谢指点。Git 的坑其实挺多的,不熟的情况下用在大型、多人协作项目上,感觉会很苦逼……
Mozilla Firefox 29.0 Linux 大约10年前
根据我们很多项目的实践,在团队大多数人不熟悉git的情况下,从svn转到git弊大于利,冲突解决混乱,merge导致旧代码覆盖新代码,产生很多无用的merge commit,加上发布系统的人也不熟悉git,发布流程和git workflow完全不兼容……