git作為分散式版控的一項優勢是可以在offline的情況下查到log,並且能夠隨時隨地commit;這個對於當中央repo在公司內部的時候會更加有感(因為通常內部都要透過vpn,就有可能導致速度慢,甚至有些vnp還會切斷你的外網, 沒有google要怎麼寫code XD)
很不幸的,如果你今天被要求使用svn或者tfs,你就沒有辦法像git一樣在無連線狀態下查log。
但是別絕望,git其實可以透過一個Bridge來和svn溝通,從外部來看,你好像還是使用svn,但是其實你實際上使用git。所以git的那些優點(local有一個版本,因此可以local commit,快速切branch等)完全可以使用。
這是一個很好開始嘗試git的方式。
昨天有幸為 Study4的6月場次介紹git,其中有學員有特別提到關於git和svn溝通的部分, 因此把當初所做的事情作了一些整理。如果有任何地方看不懂或者有缺或者漏的地方,在留言給我。
這篇的情境
這篇的主要的情境是:作為一個開發者,我的中央版控使用的是svn,但是我希望使用git來管控應該怎麼做?
因此,這是一個單項同步的概念:svn中央庫作為main repo,而不是說在建立一個中央的git repo然後和中央svn做雙向同步。
這篇針對的是windows環境,在linux和mac不確定是否一樣操作,但是本質應該差不多。
用git作為svn的溝通需要準備什麼?
首先有幾個程式是必備的:
- Git for windows
既然要用git做為和svn溝通的工具,git當然是需要安裝的程式。
快速鏈接:Git for windows
- git svn
- 這個是git和svn溝通的bridge - 以前需要額外下載,目前是整合在git for windows裡面
- svn的command line工具
如果有安裝TortoiseSVN(小烏龜),可以不用安裝,小烏龜有帶。
可以再CollabNet下載到,目前最新版本是1.9.5
非必備程式:
如果不確定是否所需要的工具都有了,可以用 svn-migration-scripts.jar
做檢查,在command line輸入:
java -jar svn-migration-scripts.jar verify
準備工作 - svn使用者對照表
在svn裡面,誰commit是用帳號做表現,但是在git裡面則是 姓名+email。
很有可能目前svn和git的對應著無法直接對上,因此先建立一個對應表。
這個對應表的格式很簡單,就是:
{{svn帳號}} = {{git姓名}} <{{git email}}>
多人,就是每個人空一行。
以我的例子來說,假設svn帳號是J00,然後要對到我,那麼這個檔案內容就會是:
J00 = Alan Tsai <alan@alantsai.net>
使用工具產生
假設你的人名清單很明確可以一個一個自己手刻,但是如果很多情況下建議用產生的方式。
產生有兩種方式:
- 用svn-migration-scripts.jar
- 用svn log搭配一些工具產生 - 需要先用svn把repo抓下來,個人覺得比較麻煩
用svn-migration-scripts.jar
執行 (把 {{svn repo url}} 換成對應的repo url):
java -jar svn-migration-scripts.jar authors {{svn repo url}} > author.txt
會得到這個repo裡面每一個使用者的清單,在手動調整一下對應的git名稱即可,下面是我拿open source的一個svn repo的產生結果:
用svn log產生
這個的前期條件是已經有把那個svn repo用svn抓下來。
在那個資料夾下面執行:
svn log --quiet --xml | sed -n -e "s/<\/\?author>//g" -e "/[<>]/!p" | sort | sed "$!N; /^\(.*\)\n\1$/!P; D" > author.txt
這個會得到一個所有svn使用者的清單。
請注意建立出來的txt檔案格式,一定要是UTF-8 (不包含BOM)
這個可以用Visual Studio Code看出來,在右下角,UTF-8
是對的。假設要改,可以點一下,然後選擇Save with Encoding
在選擇UTF-8
即可。
開始使用 git svn
整個的使用流程如下:
- 從svn建立git repo
- 日常git版控行為 (開branch,commit,merge master等) 這個就不說明
- 從svn抓取最新
- 把git的commit推上svn
從svn建立git repo
首先是需要把svn所有commit抓下來,這個如果svn repo很大的話,需要一些時間,因此要做好放著讓他跑的準備。
如果你的svn repo是標準方式建立的(換句話說,會有trunk、branches和tags的話)呼叫方式如下:
git svn clone svn://localhost svn -A author.txt --stdlayout --prefix=svn/
參數說明如下:
-A
- 這個傳入的是那個帳號名稱對應檔 - 在 準備工作 - svn使用者對照表 篇的到的結果檔案
--stdlayout
- 表示svn使用的是標準方式建立出來,如果今天不是標準方式建立,那麼需要自己設定 trunk名稱:
--trunk=
,branch名稱:--branches=
和 tag名稱:--tags=
--prefix=svn/
- 建立出來的svn 遠端 branch用
svn/
作為前戳,方便區分哪些是svn那邊的remote branch。
git svn clone
其實就是: git svn int git svn fetch的縮寫
設定svn ignore檔案
由於svn可能有自定一些ignore的規則,因此當clone完之後,建議先把ignore加進來。
clone完直接使用:
git svn show-ignore >> .gitignore git add .gitignore git commit -m "加入svn ignore清單"
日常版控行為
抓下來之後,會發現其實整個svn的trunk、branch和tags都變成了git的遠端remote branch。
接下來就像日常使用git的方式使用 - 也可以使用gui工具例如source tree。
等到最後要準備上到svn的時候,需要先從svn抓最新的回來
從svn抓取最新
和同git遠端repo溝通一樣,在溝通前,要先做一次更新,確保本機和正式機器的版本是一樣新。
這個時候,可以呼叫:
git svn rebase
這個其實類似于git裡面的git pull --rebase
。
所以如果有發生衝突,同等於在rebase的時候發生衝突要處理的方式一樣。
把git的commit推上svn
假設沒有開branch,那麼再上一個步奏svn抓取最新的時候,會自動把master對最新的做rebase,因此不用做任何處理,直接呼叫:
git svn dcommit即可
假設有開branch,那麼這個時候應該要用rebase
+merge
來達到master和branch 合併的時候會是 Fast Forward Merge:
git checkout branch1 git rebase master git checkout master git merge branch1 git svn dcommit
建立一個git repo mirror
到目前為止其實會發現,git svn只是有一個特殊的branch在記錄目前svn版本在哪裡,然後只有需要和遠端溝通的時候呼叫git svn相關指令,其他操作者一般git沒有兩樣。
這時候假設想要把目前記錄推送到某一個git repo上面,做法其實很簡單(就是一般加remote的方式):
- 加入一個remote - 例如
git remote add origin {{git repo url}}
- 然後push上去:
git push -u origin master
結語
要換使用一個工具或方法通常都是因為有某些痛點和需求。因此從svn要轉git,先用這種方式,等到都確定要轉的時候,可以讓大家改成用那個git repo版本而把svn給停用掉。
另外一個常見的版控,TFS也有類似的bridge工具可以下載 - 運作原理和git svn差不多。
參考資料
- Atlassian關於從Svn到Git的說明(英文)
- 很棒的一系列介紹如何從svn轉到git
- git svn 指令(英文)
- git svn每一個指令和參數的含義
- 官方介紹git svn
- 鏈接是中文內容
- Migrating from SVN to Git, preserving branches and tags
- 不錯的概觀介紹。
- 第 29 天:如何將 Subversion 專案匯入到 Git 儲存庫
- 保哥30天git裡面關於和svn溝通的部分
沒有留言 :
張貼留言