2013年8月5日 星期一

我從 SVN 退役轉 Git 的三月有感


        這三個月,我的開發工作環境從以往熟悉的 SVN 轉為 GitHub。使用 SVN 這麼多年,心中早已經有一套 SVN 的哲學和心法,突然面對這麼一個對我而言全新的版本控管工具,有許多不易契合的操作,但畢竟兩者擅長不同,所以這裡不以優劣勝敗定論,單純從一個已經使用多年 SVN 的用戶角度來看待剛接觸三個多月的 Git 的心得與想法。

        當然,畢竟我是 Git 的初學者,對它的使用也侷限在 GitHub 這個網路服務的經驗,有些限制或許是來自 GitHub 而非 Git 本身,比起我還架設過自己專用的 SVN Server,兩者的比較一定在心態上是不太公平的。歡迎熟悉 Git 的高手給我指點,糾正我對 Git 錯誤的認知。

        首先,Git 和 SVN 的差異,主要是『分散式版本控管(DVCS)』和『集中式版本控管(VCS)』的管理哲學上的差異。然而集中式無法模擬分散式的優點,但是分散式透過使用方法的調整,卻可以被當作集中式來使用

        所以選擇分散式工具,理論上似乎可以保留未來最大的選擇權。嗯?是這樣嗎?

        他們本質上的差異,這裡有篇精彩的文章介紹,我就不多浪費篇幅。

        我所使用的 Git 工具就兩套交替使用,一個是 GitHub 官方提供的『GitHub for Windows』,另一個是著名 SVN 工具開發商另外製作的『小海龜 Git ( TotoriseGit ) 』。

GitHub for Windows

        極為簡單的 UI 設計,是『GitHub for Windows』的優勢,我利用它來做一般 80% 的例行性工作:sync、branch switching、release merge、branch create / delete / publish。但是這個工具對於複雜一點的進階操作就完全不行了,例如:解決衝突 ( Resolve conflict ) 、單一檔案的歷史異動追蹤(尤其為了追某段程式碼是誰改動的),另外它無法識別 unicode 文檔,全當作 binary 處理,所以很多 Diff 都失效。

TotoriseGit

        跟市佔率極大的 TotoriseSVN 近似的界面,功能強大,對熟悉 SVN 的人上手快速。上述『GitHub for Windows』做不到的我就交給小海龜來操作。

        首先,兩者在 branch 操作上有者截然不同的概念。

        SVN 的 Repositiory 因為是以檔案資料夾那種樹狀結構為基礎,所以他可以在任何一個資料夾的節點上,自由地長出所需的 branch or tag,某些場合這樣應用的靈活性相當大,例如只想對某一段模組產生不同版本的 branch,當然有時候也會因為這個彈性而讓相依性的管理變得混亂。

        Git 在 Branch 上的操作是以一整個 Repository 作為操作的單位無法針對某個資料夾或模組單獨作 branch out,也因此,完全沒有相依性管理混亂的問題,每一次的 branch out,都是整個 Repository 完整的 snapshot。但是這點就凸顯出『前期規劃』的重要性了。

        如果我在版本控管上,希望對每次的 release 都有對應的 branch 做控管,而且我 release 出去的程式單位可能有大有小,在 SVN 我不用顧慮太多,直接開幹open trunk 英譯,不是爆粗口)就好,等到底下有某個 component 可能被升等為獨立的應用程式,開始有自己的 release cycle,那就對其原始碼所在位置的資料夾直接做 branch out 就搞定了!(先不管 repository 這棵樹整體看起來多醜,和相依性多難管理

如上圖所示,Component A-A-A如果突然有獨立 release 的需求,就在其下建立他自己的 branch 就可以做到


        但是在 Git,我遇到的困擾就是,原本只是跟著大家一起 release 的 component 如今必須被 promote 成擁有獨立的 release cycle 的 application,這時候除了放棄過往的 change log 既往不咎,開全新的 Repository 幫他搬新家外,就沒別的辦法了,所以這就是為何初期 Repository 的規劃很重要的原因。當然,在 Git 裡面的樹結構真的非常簡單乾淨,相依性很容易維護。

如上圖所示,Component A-A 將來若有單獨釋出的可能,只能 Promote 成 App C 並且搬家到獨立的 Repository 內


        另外就是 SVN 在 local 的 branch switching 的操作是緩慢昂貴的(透過網路經由 svn server 切換),這導致 developer 多半會選擇重新 checkout 不同的 branch 版本到不同的本機資料夾內來做開發,對本機如何管理多個不同用途的 checkout folder 也是個令我頭痛的問題。

        但是 Git 的 branch switching 可以說是神速,幾乎感覺不到那一瞬間,而且是原地立即生效!

        當然,也不是所有 developer 都能接受這麼『無感』的切換,寧願堅持另外 checkout 獨立的 branch folder⋯,唉。

        但是這麼方便的 branch switching 是我逐漸愛上 Git 的重要特色。

        至於 Git 常為人所津津樂道的 offline commit & online push,我則沒那麼愛。因為我都是幾乎立即 push 回 server,這個設計對我來說就是增加多一道手續而已,反而麻煩。目前我的團隊還沒有遇到需要離線在火車或是飛機上 coding 和 commit 的需求,這個設計反而增加了團員 commit 卻忘記 push 的人為錯誤機率

        另外 merge 的策略感覺 Git 沒有 SVN 那麼多選擇,branch 之間的 merge 似乎只能走 fully merge,不能 by file / by revision 去『挑選』要 merge 的異動?這個限制常常困擾我,不知是否只是因為工具造成的關係?

        最後分享一個我們在 Git 上採用的版本管理的 Best Practice。以下這張圖,不管是用 Git 或是 SVN,都極富參考價值:

Google+ Badge