每一個可以努力的日子,都是一份厚禮。
將代碼庫從 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完全不兼容……