2009年11月19日 星期四

Migrating svn repository to git

要將一個標準的 subversion repository (含有 trunk/ , branches/ , tags/ ) 轉移至 Git 其實相當容易。

$ git svn clone --prefix=svn/ --stdlayout http://example.com/svn

這樣 git 會自動將這些 Mirror 下來。

不過 git-svn 不會幫你處理 merge 的相關資訊,所以這個部份需要自己手動處理。若沒有讓 git 知道哪些 branch 曾經在哪些版本合併過,待你直接下 git merge [branch] 就會 conflict 到死。

假設我們有一個 subversion repository,rev1 的時候建立專案 , rev2 的時候開了一個 branch , rev3 的時候修改 branch , rev4 的時候把這個 branch 合併至 trunk。如果這些動作使用 git-svn clone 回來,那麼在 rev4 會遺失 rev3 的合併資訊只留下 rev1 為父節點的資訊。但事實上 rev4 的父節點應該是 rev3 以及 rev1 才對。

為了解決這個問題,git 的 repository 底下有一個奇妙的檔案叫做 .git/info/grafts ,這個檔案用來存放節點合併的資訊。

.git/info/grafts 的基本格式如下:

[合併版本] [合併目的] [合併來源]

假設我們剛剛的操作,有以下版本紀錄:


1 85de8c02f0b649dcdbbb0fb5045205900a28afac
2 1f47e9b22c0b4967a9338fd32ebbe745d769f0bc
3 f0bbdbf01a46f4bb0f79f330a7603ad1aca3bd40
4 1a0a6e58a2f6905b2165f6bad973b4c85356e100

那麼在 graft 底下可以這樣寫:
1a0a6e58a2f6905b2165f6bad973b4c85356e100   85de8c02f0b649dcdbbb0fb5045205900a28afac  f0bbdbf01a46f4bb0f79f330a7603ad1aca3bd40



這時候:

$ gitk

便可以看見合併的節點如何被相連起來

$ git merge [branch]

便不會 conflict。