2017年6月25日 星期日

[git]開始使用git - 用git操作svn repo

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的方式。

題外話,我當初接觸git就是為了他的local功能,因為實在太好用了,最後慢慢就希望全部換成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

快速鏈接:(x86)、(x64)

非必備程式:

svn-migration-scripts.jar

這個是Atlassian提供的一個小工具,方便處理一些事情。如果要使用也需要安裝java

source位置:source

快速鏈接:直接下載

如果不確定是否所需要的工具都有了,可以用 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>

使用工具產生

假設你的人名清單很明確可以一個一個自己手刻,但是如果很多情況下建議用產生的方式。

產生有兩種方式:

  1. 用svn-migration-scripts.jar
  2. 用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的產生結果:

某個open source svn的人名清單,這邊沒有pipe到檔案因此可以直接看到
某個open source svn的人名清單,這邊沒有pipe到檔案因此可以直接看到

用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即可。

看到編碼,UTF-8 with BOM是錯的選擇save with encoding選擇 UTF-8
選擇為UTF-8

開始使用 git svn

整個的使用流程如下:

  1. 從svn建立git repo
  2. 日常git版控行為 (開branch,commit,merge master等) 這個就不說明
  3. 從svn抓取最新
  4. 把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
的縮寫
假設呼叫clone過程不知道什麼原因停掉了,可以呼叫 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。

可以看到這個repo只有一個trunk,所以remote/svn/trunck
可以看到這個repo只有一個trunk,所以remote/svn/trunck

接下來就像日常使用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的方式):

  1. 加入一個remote - 例如 git remote add origin {{git repo url}}
  2. 然後push上去:git push -u origin master
在去哪個git repo看就會發現都上去了

結語

要換使用一個工具或方法通常都是因為有某些痛點和需求。因此從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溝通的部分
標籤:

沒有留言 :

張貼留言