[Tools] 版本控制:SVN

版本控制,通常是將專案的程式碼,存放在伺服器(Server 端)或存在共用的磁碟空間。
每位開發者,可以從 Server 端將最新的專案程式碼下載到自己電腦(Local 端),讓自己的電腦中的 Code 處於最新的狀態,也可以把對程式碼的修改繳交(即 Commit)到 Server 端,每 Commit 一次,Server 端的程式碼就會更新版本編號,讓專案前進到新版狀態。

版本控制工具常見的是 Git 和 SVN(Subversion),SVN 我已使用多年,因此較熟悉 。而 Git 的操作跟 SVN 差不多。

為什麼需要版本控制
首先,版本控制有兩個優點:
  1. 記錄每個開發者對專案所做的每個變更。當程式出現問題時,可以將專案退版,讓程式碼回到之前某個穩定版本。如此容易維持專案穩定,也比較容易找到出錯的原因。
  2. 專案開發的過程,有可能衍生出其他的專案分支(Branch),版本控制能獨立維護各分支,專案分支可以互相獨立的進行開發,如下圖所示:
Figure 1. Version Control

通常在 SVN 專案目錄下會有名為 Trunk 的資料夾。Trunk 是專案進行的主要路徑,由下往上更新。Trunk 更新到某個版本,有可能分支出另一個分支專案路徑,稱為 Branch。例如知名的 Linux 作業系統 CentOS,就是 RedHat的一個分支。Fig. 1 中 Trunk 開發到 Older Version 1 時,就將程式碼複製出去形成一個 Branch,與 Trunk 獨立開來,各自開發。當然,Branch 有可能再衍生出另一個 Branch。

在 Linux 內設定 SVN
可參考這篇文章

SVN 常用指令

Checkout,簡寫為 co,在 Local 端尚未有 Server 上的專案時,可以將專案透過 Checkout 下載到本地端,指令為:

svn co <SVN_Project_Path>

將 Local 端的檔案更新到最新版,指令為:

svn update

Commit,簡寫為 ci,在 Local 端變更專案後,可以 Commit 將變更繳交到 Server,同時繳交時可以撰寫註解,描述這次的變更內容,指令為:

svn ci -m "comment can be typed here."

某個檔案如果不在 SVN Server 端,我們可以透過 add 來將這個檔案加入,指令為:

svn add <File or Folder>

將某個檔案從 SVN Server 端移除,可以輸入下面指令:

svn delete <File>
(要執行 Commit 指令後才會真正從 Server 端移除檔案)

Revert 代表回復到前一版本(也就是將目前 SVN Server 上的最新版檔案取代 Local 端的檔案)。將某個檔案退回前一版的指令為:

svn revert <File_Name>
(File_Name 可包含路徑)

如果要將某個資料夾(包含其子資料夾在內)的所有檔案都 Revert,指令為:

svn revert -R <Path of Directory> 
或者
svn revert --depth=infinity <Path of Directory>

用下面的指令可以觀看本地端的檔案狀態:

svn st

svn st 指令會顯示檔案狀態,常見的狀態有:
顯示 'M' 代表本地端的檔案有變更。
顯示問號 '?' 代表本地端檔案不存在 Server 上。
顯示 'C' 代表此檔案有 Conflict 尚未解決。
顯示 'D' 代表此檔案在執行 Commit 指令後將從 Server 端刪除。

我們可以將本地端的專案退回 Server 上的某特定版本,假設 Server 上最新版本號碼為 100,我們可以用以下步驟退回第 95 版:

svn update
(也可以執行 svn up,up 是 update 的簡寫)
svn merge -r 100:95 ./
(如果想用第 95 版取代目前 Server 上的第 100 版本,可以再次 Commit)

觀看專案 Information,指令為:

svn info

Conflict 的解決
Conflict (衝突)代表兩個開發者,對於某 Code 的同一段落同時做了變更,且其中一位開發者先將變更 Commit 到 SVN Server 。如此另一位開發者執行 svn update 或者執行 Commit 動作時,就會有 Conflict 的狀態必須解決,如下圖所示:
Figure 2. SVN Conflict
通常 Conflit 發生時,SVN 會提供幾個選項。比較建議的作法是選擇 postpone 選項,然後開啟有衝突的 Code,搜尋 "mine" 關鍵字,可以看到衝突的位置:

<<<<<<< .mine
[Code of Developer A] // 這裡是 Developer A 的變更
=======
[Code of Developer B] // Developer B 做的變更
>>>>>>> .rxxx
此部份的 Code ,可透過討論來確定最新的版本如何撰寫。處理完畢後,執行下面指令來解除檔案的 Conflict 狀態:

svn resolved <File_Name>
接著 Commit:
svn ci -m "update code and solve conflict."

如此就完成 Conflict 的解決。

心得
初學 SVN 時,常被 Conflict 處理所阻礙,也常忘了某些 Local 端新增的 Code 要先 add 再 check in。但在熟悉之後,開始體會到版本控制對於專案穩定的重要性。
我會建議在使用 SVN 時,做任何動作前一定要先作 svn up 的動作,避免自己 Local 端的檔案跟 Server 端的檔案逐漸發散掉,且可避免 Conflict 發生的機率。並且不要等到大量的 Code 更新後才 Commit,反而要養成小部份 Code 更新就 Commit 的習慣,就算只更新一行程式碼也無所謂,如此才可確保整個 SVN 專案的穩定。

為了避免使用 SVN 時影響到其他的開發者,以下使用經驗必須注意與熟悉:

  1. svn update 之前,一定要使用檔案 Diff 工具,來觀看自己改過的 code 跟 Server 端的 code 不同之處。這個步驟很多初學者容易忽略,這是一個非常重要的步驟
    透過這個步驟,可以檢查修改過的地方是否如你所預期的。同時也可以注意是否無意中修改到不該動到的 code。
  2.  svn update 之後,一定要使用 svn st 來觀看是否有 Local 端新增的檔案沒有 add 到 SVN Server 上。很多時候我們以為 svn up 之後,就已經上傳所有更新了,但事實上還有很多檔案沒有在 SVN 的維護範圍內,造成其他人 update code 後,要執行時產生錯誤,因此需特別注意。
  3. 每次更動 Local 端的檔案前,一定要先 svn up。

Reference
Ben C., Brian W., & C. Michael Pilato. (Eds.). (2004). Version Control with Subersion. Sebastopol, California. USA: O'Reilly Media.


留言