Subversion 版本控制系統的基礎觀念

本文介紹 Subversion 版本控制系統的基礎觀念和術語,以及導入版本控制系統時應考慮的事項。

P.S. 這篇文章原本寫於 2004 年 6 月,之前將部落格搬到 blogger.com 時沒有整理進來,現在補上,順便重新編排、修剪。

簡介

在開發過程中,你是否碰到過以下幾種情形:
  • 檔案被別人(或自己)覆蓋;
  • 檔案遺失(拖放檔案時誤動作...);
  • 想要比對各版本之間的程式碼有何不同;
  • 想要回到之前修改的版本(需求反覆變更、自己改錯了...);
  • 這些 code 不是我改的,是誰碰過我的程式碼?
  • 軟體發行之後,必須凍結共用的程式碼一段時間,免得其他人在改 bug 的同時,因為你修改了共用的程式而增加更多新的問題。
如果有以上情形,你需要的是對專案進行版本控制(version control)。版本控制也有人稱它為原始碼控制(source code control),是 SCM 的一環,其目的即在於解決上述各種問題,讓你可以:
  • 隨時復原錯誤,就好像是專案的時光回溯器,可以將檔案恢復到之前的任何版本;
  • 多人同時修改同一份程式碼,不會有相互覆蓋的情況;
  • 保留所有修改的歷程,如果你發現自己的程式碼有被別人更動過,可以很容易找到是誰更改的,以及何時更改的;
  • 在發行正式版的同時,還能繼續發展新版本,無須下令凍結所有程式碼。
版本控制系統則是提供上述功能的軟體系統,它提供了一個地方讓你集中存放開發過程中的所有程式檔案及文件,以便達到集中控管的目的。

基本觀念


這個小節簡單介紹幾個使用版本控制系統時必須了解的基礎觀念,包括:檔案庫(repository)、工作區(workspace)、取出檔案(checkout)、送交檔案(commit)、分支(branch)等等。

檔案庫

前面提到,版本控制系統有一個集中存放檔案的地方,一般稱之為「檔案庫(repository)」,檔案庫裡面儲存了專案相關產出的所有歷史版本(包括目前開發中的版本)。有的版本控制系統是以資料庫的方式儲存,有的是以檔案的方式儲存;不論儲存的方式為何,對使用者來說,最重要的就是要把檔案庫放在一台穩定、安全的機器上,並且要定期備份。

主從式架構

現在我們知道,檔案庫既然是檔案的集中營,那麼一定是放在某台機器上,供所有開發人員存取,其作業方式如下圖所示,是一種主從式(Client/Server)的架構:



檔案庫所在的機器必須安裝版本控制系統,以提供檔案存取的服務給各個用戶端。圖中的「開發人員A」和「開發人員B」即代表用戶端,而用戶端機器上必須安裝版本控制系統的用戶端工具,才能存取檔案庫。

在連線方式上,用戶端可以透過各種網路協定來存取檔案庫,某些版本控制系統要求你一定要隨時與檔案庫保持連線,才能修改檔案內容;某些版本控制系統(例如 Subversion)則採用比較寬鬆的方式,你可以在沙灘上用筆記型電腦修改程式,等到回辦公室時再將檔案同步。有一個名叫 SVK 的工具甚至可以讓你以完全離線的方式操作檔案庫,此工具是架構在 Subversion 之上。

哪些東西要放進檔案庫?

顯然,專案的程式碼要存放在檔案庫中,以便進行版本控制。那麼,還有哪些東西也要版本控管?

基本上,你在開發一個專案的過程當中,需要用來建置軟體的檔案,都可能要放到檔案庫裡面,例如:建置專案的組態檔或 makefile、測試資料等等。在決定哪些檔案要放進檔案庫時,你可以問自己一個問題:「如果少了這個檔案,能夠建置和發行軟體嗎?」這可以協助你決定至少該把哪些東西放進檔案庫。

視團隊的需要而定,其他專案開過程中的產出,如分析設計文件、團隊成員的討論信件、FAQ、會議記錄等等也都可能納入版本控管。
基本操作和術語本小節簡單介紹幾個使用版本控制工具時必須熟悉的基本術語和操作,包括:工作區(workspace)、取出(check out)檔案、存入/送交(check in/commit)檔案、更新(update)、衝突與合併(conflict and merge)。

工作區(Workspace)

檔案庫存放了專案開發所需的所有檔案及其歷史版本,但是對於團隊成員個人而言,並不需要全部的檔案,我們只需要自己負責的部分就夠了。因此,我們會從檔案庫中取出(複製)一部分自己需要的檔案到自己本機的硬碟裡,這些存放在本機的檔案,就稱為本機複本(local copy),而存放本機複本的地方,則稱為工作區(workspace)。相對於本機複本,儲存在檔案庫中的版本則稱為主要複本(master copy)。

對小型專案而言,本機複本可能就是專案的所有原始碼和文件,而大型專案可能會切割成數個子系統或模組,所以開發人員只要取出自己負責的子系統就行了。

工作區有時候也稱為工作目錄(working directory)或程式碼的工作複本(working copy)。

取出(Check Out)

一開始,我們個人的工作區都沒有任何檔案,因此第一個動作就是要從檔案庫中取出我們需要的工作複本,這個動作稱為:取出(check out)。當你執行 check out 時,版本控制系統就會從檔案庫拷貝一份你需要的工作複本到你的工作目錄,這個工作複本的所有檔案目錄結構都會跟檔案庫裡面的目錄結構一模一樣。

存入/送交(Check In/Commit)

當你取出工作複本之後,就可以修改自己本機的檔案,等到你覺得改得差不多了,或者已經完成某個工作項目了(例如:解決一個 bug),就可以把修改過的檔案存入檔案庫,這個動作稱為:存入或送交(check in or commit)。

更新(Update)

當你修改自己的工作複本時,當然其他團隊成員也可能正在修改一些檔案,每個人的修改作業都是獨立進行且不會相互影響的,別人修改的結果也不會立即反映在你本機的工作複本上。如果你要看到別人修改的最新版本,你就必須執行更新(update)動作。當你的同僚執行 update 時,他們(通常)也會取得你最近 check in 的版本。

Note: Check out 和 update 的行為有些相似,二者皆是從檔案庫把檔案拉回本機,但他們的使用時機和目的並不相同。你必須把檔案 check out 至本機,之後才可以對這些工作複本執行 update 動作。
衝突與合併(Conflict and Merge)

在沒有版本控制的時代,總是偶爾會發生團隊成員彼此互相覆蓋程式碼的意外,有時候,這種意外發生一次就足以釀成大災難。

考慮以下情況:假設 John 取出了 A.java 和 B.java,Mary 也是。兩個人都各自修改了 A.java 的不同部分,而 John 先 check in 了,之後 Mary 如果也執行 check in,版本控制系統便會偵測到 Mary 欲送交的檔案已經有人先一步修改並送交至檔案庫了。

由於兩人修改的是 A.java 中的不同部分,版本控制系統通常可以分辨各自修改的部分,並將兩個人修改的結果合併(merge)。

可是,萬一 John 和 Mary 都修改了 A.java 的同一行程式碼,那麼比較晚執行送交的人就必須處理這個衝突(conflict)。她可能會開啟版本控制系統的差異比對工具,並與對方討論該如何進行合併。這種衝突的情況可能不常見,但萬一發生了,版本控制系統可以確保彼此不會互相蓋掉對方的成果。

在處理檔案取出的動作時,Subversion 採取的是「樂觀鎖定」的作法,也就是完全不鎖定檔案;直到發生衝突時,才由工具進行合併,或由開發人員手動解決。

有些版本控制系統是採取悲觀鎖定的作法,以事先避免衝突發生。換句話說,當某人 check out 某個檔案時,該檔案就會被鎖定成唯讀狀態,此時別人可以讀取這個檔案的內容,或者用它來建置專案,但無法修改,這樣就不會造成衝突了。只是,後來想要修改的人,就必須等到取得鎖定的人 check in 檔案之後才能修改它。
悲觀鎖定可以避免衝突,但實際用起來卻不大方便,因為一個檔案同時間只有一個人能取得修改權,其他人得排隊等候。萬一先取出檔案的人遲遲未送交(例如:休假去了),其他人就只能乾瞪眼。
發行版本與修訂版次

就 Subversion 而言,它是將每一次送交動作視為完成一次修訂,並賦予一個修訂版次的編號(revision number),且每送交一次,修訂版次的編號就自動加一。當我向別人提到這點時,總是被問到:「多人開發時,版本編號遞增這麼快,這樣不是很亂嗎?你如何管理軟體的版本?」基本上,這是把軟體的發行版本(release)和修訂版次(revision)混淆了。

簡單地說,我們(開發人員)平常在寫程式時,大都很少處理發行版本的問題,甚至連修訂版次編到幾號了也不在乎;只有當我們要回復到某個歷史版本或進行版本差異比對時,修訂版次對我們來說才有實質作用。至於產品的發行版本,我們可以利用 Subversion 的標記(Tag)功能來做版本的區分;不過,剛開始接觸 Subversion 時應該還不會馬上用到這項功能,這裡就先略過不談。

導入版本控制系統


了解版本控制的基本觀念之後,接著就可以挑選一個版本控制系統,嘗試運用於實際的專案開發工作。如果是一人團隊,應該沒什麼問題;如果是多人團隊,在將版本控制系統導入現行開發流程時,可能就得多花點準備工夫了。以下列出一些準備工作:
  1. 選擇合適的工具。目前市面上可以買到或免費取得的版本控制系統有很多,你可能要花一點時間比較一下各種產品的功能,並且根據自己的需求和預算,挑選最適合自己團隊的工具。
  2. 安裝並測試版本控制系統的各項功能。
  3. 選擇一名管理員。團隊中必須有一個人負責管理檔案庫、建立專案的初始目錄結構、定期備份檔案庫等工作。有時候,他還得協助其他團隊成員解決檔案庫操作的疑難雜症。
  4. 教育訓練。教開發人員如何在日常開發工作中使用版本控制系統,讓他們了解跟之前的作業方式有什麼差別、可以獲得哪些好處,以減少因為改變工作習慣而產生的阻力。
  5. 正式將專案納入版本控管。

小結


本文介紹了版本控制系統的基本觀念和術語,你應該會發現,這些觀念並不難,而且非常貼近日常軟體開發工作所遭遇的問題。了解這些基礎概念之後,接著便可以開始嘗試將版本控制工具導入實際的軟體開發流程。希望本文提供了足夠的基礎,作為您進一步學習使用版本控制系統的跳板。

術語整理

英文 中文 說明
check out 取出 從檔案庫中取出檔案。
commit/check in 存入 將檔案從本地端存入檔案庫。
export 匯出 把整個模組從檔案庫中取出來,取出來的檔案不包含版本控制系統的管理檔案,也就是匯出的模組將不再由 版本控制系統控管。
import 匯入 把整個目錄結構匯入檔案庫。當你要把一個新的專案放進檔案庫進行版本控管時,就需要執行這個動作。
local copy 本地複本 放在用戶端機器的工作目錄中的專案複本。
master copy 主拷貝 放在檔案庫裡的專案複本。
module 模組 一個目錄階層,通常一個專案就是一個模組。
release 發行版本 軟體產品的一個版本。為了區別產品的版本以及個別檔案的修訂版次,因此不使用 version,而用 release。
repository 檔案庫 存放所有檔案(包含歷史版本)的地方,用戶端執行 check out 時就是從這裡取出檔案。
revision number 修訂版次 一個檔案的修改版本,例如:1.1、1.3.2.2。
tag 標記 在開發過程的某個時間點上,為一組檔案提供的符號名稱。透過 tag 一群檔案,你可以很容易在某個 release 裡面找出這些檔案。
update 更新 從檔案庫中取得其他人修改的檔案,以更新本機的副本(local copy)。
workspace/
working directory
工作區/工作目錄 本機的工作目錄,又稱為沙盒(sandbox)。

參考資料

1] Pragmatic Version Control with CVS. Dave Thomas and Andy Hunt. The Pragmatic Programmers, LLC. 2003.
[2] Version Control with Subversion. Ben Collins-Sussman, Brian W. Fitzpatrick, and C. Michael Pilato. http://svnbook.red-bean.com/


3 則留言:

  1. 您好:
    想請教您有關subversion在asp.net專案上的運用架構應該如何較為適當,目前有漸漸在導入subversion來管理版本,暫時只有將新專案納入.
      架構上我們有正式主機,測試主機,而專案開發的方式是採用VS remote site 配合frontpage server extensions 來維護,若要採用subversion,是否要先建立一個新的repository ,再將測試主機上的專案import進入repository中.開發人員在自己本機建立working folder,然後checkout repository的內容,之後就是update上測試主機.

    請教您,不知這樣子做法對嗎?

    Ps.目前是採用TortoiseSVN,預計不會建立SVN SERVER的方式,而是採用檔案的方式.

    回覆刪除
  2. 您說的那種方式大致上沒問題,其實我也是這麼做的,可能只有一些細節上的差異。

    你說不會建立 SVN Server 啊?我不太懂這句話的意思,Subversion 檔案庫不都是放在 SVN server 上面嗎?難道你是用網路共享資料夾的方式?官方文件上有說,絕對不要用這種方式喔!

    回覆刪除
  3. 感謝回覆!好像隔很久..呵!

    那段有點打錯,應是說目前我們採用檔案的方式,利用TortoiseSVN,並沒有建立SVN SERVER.

    只是先前在研究是否要建SVN SERVER時,考量到我們現有的網站是採FSE的方式,感覺中間有點落差及不了解的地方,還請指教!

    回覆刪除

技術提供:Blogger.
回頂端⬆️