使用svn-all-fast-export將SVN轉爲Git

最近將某項目代碼庫從SVN遷移到了Git。網上有介紹使用git svn來進行遷移的,我試過最終因git svn clone無法正常執行完成失敗了。我也注意到有一款採用Ruby開發的svn2git工具,原理應該是基於git svn進行二次開發。因爲之前用git svn方法沒成功並且每次嘗試消耗的時間過長,就沒有再試這個工具。

我最終採用了svn-all-fast-export工具。這個工具基於libsvn-dev開發,是直接對SVN庫目錄進行操作。svn-all-fast-export需要Linux環境運行,我採用VirtualBox+Debian;Synaptic新立得包管理器已包含這個軟件,直接安裝即可。

先建個目錄svn2git,保存SVN庫目錄(Svn_CQClient和Svn_CQServer)及對應的轉換規則配置文件(cqclient.rules和cqserver.rules)。目錄結構如下:

~/svn2git

|-Svn_CQClient/

|-Svn_CQServer/

|-cqclient.rules

`-cqserver.rules

在製作rules文件之前,需要先梳理一下SVN庫的內容並規劃將來的Git庫。以CQServer庫爲例說明,先建立一個表格,有幾列:Git、branches、based on branch、tags和labels(因爲CQServer最早期用VSS做版本管理,所以VSS轉SVN時保留了labels;如果你的SVN庫沒有/labels就不需要labels列)。

1. 規劃Git庫名和分支名

打開TortoiseSVN Repository Browser,逐個查看/trunk和/branch目錄下每個項目的“Show log”輸出(設置“Stop on copy/rename”標記,點“Show All”顯示完整日誌),看看該項目最早的代碼是從其他項目派生的,還是直接添加入庫的,將項目路徑寫入branches列,將它的源項目路徑(如有)寫入base on branch。還可以使用TortoiseSVN的Revision Graph來查看,已刪除的項目路徑也要進行處理並特別標註。

不同源的項目之間無法跨項目應用merge操作,如果放在同一個Git庫會產生根節點不同的分支樹。所以不同源項目一般應歸屬不同的Git庫。

同源項目可以在同一個Git庫中作爲不同的分支進行管理。如果新項目在建立時就是爲了替換某個同源舊項目,或是由舊項目改名而來,有明顯的承接關係,舊項目後續也沒有commit記錄,那麼分支名可以相同。

有時項目是從它的父目錄或子目錄複製過來的,比如某個項目之前在/trunk/保存了開發版本,後來把項目整個移到/trunk/Develop/目錄下,然後刪除了原父目錄下的文件。這樣的話可以將父目錄/trunk/和子目錄/trunk/Develop/規劃爲Git中的不同分支,並利用max revision規則(見下文)保留/trunk/刪除版本文件之前的樣子。

爲每一組同源項目分配一個Git庫名(第一列“Git”)。爲每個branches項分配一個Git分支名。

2. 規劃Git庫標籤

和branches類似,但是不需要確定分支名,可以使用通配符來標記。例如:

Gittagslabels
CQServerCQServer/([^/]+)/
CQServerRelease/([^/]+)/
([^/]+)/(Develop|Release)/
([^/]+)/
CQModuleCQModule/([^/]+)/([^/]+)/CQModule/
CQServer-x64CO3Server/([^/]+)/
CO3ServerCn/([^/]+)/
CQServerIpad/([^/]+)/
CQServerRelease-x64/([^/]+)/
CQServer-x64/([^/]+)/
 

這裏只是粗略地分一下,實際轉換時可能會發現某些tag跨不同Git庫導致錯誤的情況,就要編寫更細緻的規則把這些tag分配到不同Git庫或者直接忽略掉對應的commit記錄。

3. 編寫建庫規則

轉換配置文件的例子可參考https://github.com/svn-all-fast-export/svn2git/tree/master/samples

先根據Git庫規劃寫創建Git庫的規則,例:

create repository CQServer.git

end repository

把”CQServer.git”依次替換爲其他Git庫名(第一列“Git”)。

4. 編寫分支規則

根據第二列“branches”和取好的分支名轉換爲Git庫中的分支,例如:

match /trunk/Develop/

    repository CQServer.git

    branch master

end match

將紅字部分依次替換爲之前規劃好的配置。注意:目錄名末尾必須加”/”字符。

分支規則的書寫順序很重要。轉換程序會逐條處理SVN庫的commit記錄,將commit記錄中每個文件路徑按match規則(”match”之後的正則表達式,採用Qt4 QRegExp)的順序逐條匹配。如果匹配成功就按照match/end match之間的配置進行處理(repository指定接收的Git庫,branch指定接收或新建的分支名)。如果匹配失敗則繼續嘗試下一條match規則。

這相當於將SVN的commit記錄的文件修改按照match規則去修改對應的Git庫和分支,並進行commit和push。

如果match匹配全部失敗,轉換程序會報告錯誤並退出,因此全部匹配失敗是不允許的。

如果確實打算忽略某些commit記錄,可以在match/end match之間不寫任何語句。例如,在所有其他/trunk/的match規則的後面加上:

match /trunk/

end match

就可以忽略之前未被匹配到的/trunk/下的commit記錄。

5. 編寫labels和tags規則

例如:

match /labels/([^/]+)/(Develop|Release)/

    repository CQServer.git

    branch refs/tags/\1

    annotated true

end match

根據規劃表格中的“tags”和“labels”列編寫,替換上面紅字的部分。“\1”和“\2”表示match規則中被圓括號對包圍的那部分內容,第一對圓括號內的內容對應\1,第二對對應\2。這個寫法也適用於之前處理/trunk/和/branches/的branch語句。

注意:如果tag不是從SVN庫中某個版本直接導出的,而是從外部複製版本目錄到/tags/下(類似於新建一個項目),這樣的tag無法在Git庫中溯源,只能忽略掉。例如:

match /tags/CQServerRelease/

    min revision 1930

    max revision 3220

end match

這樣的異常tag記錄有一個特徵:TortoiseSVN中顯示commit message的字體是黑色,與正常tag的藍色字體不同。

“min revision”和“max revision”除了一般的match匹配規則還針對SVN的revision編號進行匹配,如果匹配成功才處理,匹配不成功則繼續嘗試下一條match規則。“min revision”和“max revision”可以同時出現也可以單獨出現。min revision的編號不能大於max revision,否則可能會出現非預期的結果卻不報錯。這個辦法也可以用於處理SVN記錄中已刪除的項目路徑。

6. 逐條檢查SVN commit記錄中所有包含”Deleted”的記錄

主要注意刪除或重命名項目分支目錄或版本標籤的情況,這類情況一般需要在轉換配置文件中進行特殊處理。

在svn-all-fast-export處理後期會對tags進行Finalising處理,即使tag創建後被刪除。如果tag刪除之後沒有被重新創建,Finalising就會異常報錯,因此對於這樣的tag要編寫對應的match規則進行處理(比如忽略刪除tag的記錄,或同時忽略tag創建和刪除記錄)。Tag改名也有類似問題,改名以後相當於舊名被刪除了,但是轉換工具仍會試圖對舊名進行處理。

7. 用轉換命令處理SVN庫

export SVN2GITDIR=~/svn2git; cd $SVN2GITDIR; svn-all-fast-export --identity-domain nd --rules cqserver.rules Svn_CQServer 1>out.log 2>err.log

要看看err.log和log-*.git的日誌信息是否正常。如果程序正常結束,log-*.git日誌末尾都應該有一些程序運行統計信息,非正常結束的情況部分日誌文件沒有這部分信息。

有些特別大的SVN庫可能會出錯,可以加“--commit-interval=1”參數看看能否解決。

8. 後期檢查

對比TortoiseGit和TortoiseSVN版本分支圖(Revision Graph),檢查分支版本文件及日誌,看看是否有異常或非預期的結果。如果轉換結果有錯,可用以下命令刪除Git庫和轉換日誌,修改轉換配置文件後再重新轉換:

export SVN2GITDIR=~/svn2git; cd $SVN2GITDIR; rm -rf *.git *.log

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章