Version Control with Subversion

Draft Revision 1411M

Ben Collins-Sussman

Brian W. Fitzpatrick

C. Michael Pilato

(TBA)


Table of Contents

前言
目標讀者
本書結構
排版慣例
本書是自由的
致謝
1. 簡介
什麼是 Subversion?
Subversion 的歷史
Subversion 的功能
安裝 Subversion
Subversion 的元件
用戶端元件 (供使用者使用)
伺服器元件 (供管理員使用)
2. 基本概念
檔案庫
各種版本控制的模型
檔案分享的問題
鎖定-修改-解鎖的解決方案
複製-修改-合併的解決方案
Subversion 實務
工作複本
修訂版本
工作複本如何追蹤檔案庫
混合修訂版的限制
摘要
3. 導覽
幫幫我!
匯入
修訂版: 數字, 關鍵字, 與日期. 我的天啊!
修訂版號
修訂版關鍵字
修訂版日期
最初的取出動作
基本工作流程
更新工作複本
對工作複本產生更動
檢視你的更動
svn status
svn diff
svn revert
解決衝突 (合併他人的更動)
手動合併衝突
將檔案複製並蓋過你的工作檔
棄踢: 使用 svn revert
送交更動
檢視歷史紀錄
svn log
svn diff
檢視本地端更動
比較檔案庫與本地複本
檔案庫與檔案庫之間的比較
svn cat
svn list
對歷史紀錄的最後叮嚀
其它有用的命令
svn cleanup
svn import
摘要
4. 分支與合併
何謂分支?
使用分支
建立一個分支
與分支共事
事情的內涵
在分支之間複製更動
複製特定的更動
重覆合併問題
合併整個分支
從檔案庫移除一個更動
切換工作複本
標記
建立一個簡單的標記
建立一個複雜的標記
分支維護
檔案庫配置
資料生命週期
摘要
5. Repository 管理
檔案庫的基本知識
了解異動與修訂版
無版本控制的性質
檔案庫的建立與設定
Hook scripts
Berkeley DB 設定
檔案庫維護
管理員的工具箱
svnlook
svnadmin
svnshell.py
Berkeley DB 工具
檔案庫善後
檔案庫回復
匯入檔案庫
檔案庫備份
網路檔案庫
httpd, Apache HTTP 伺服器
你需要什麼, 才能設定基於 HTTP 的檔案庫存取
基本 Apache 設定
權限, 認證, 以及授權
伺服器名稱與 COPY 要求
瀏覽檔案庫的 HEAD 修訂版
雜項的 Apache 功能
svnserve, 自訂的 Subversion 伺服器
設定匿名 TCP/IP 存取
設定使用 SSH 存取
使用哪一個伺服器?
檔案庫權限
新增專案
選擇一種檔案庫配置
建立配置, 匯入起始資料
摘要
6. 進階主題
執行時期的設定區域
設定區域配置
設定與 Windows 登錄檔
設定選項
Servers
Config
性質
為什麼要用性質?
使用性質
特殊性質
svn:executable
svn:mime-type
svn:ignore
svn:keywords
svn:eol-style
svn:externals
外部定義
供應商分支
通用供應商分支管理程序
svn-load-dirs.pl
7. Developer Information
Layered Library Design
Repository Layer
Repository Access Layer
RA-DAV (Repository Access Using HTTP/DAV)
RA-SVN (Proprietary Protocol Repository Access)
RA-Local (Direct Repository Access)
Your RA Library Here
Client Layer
Using the APIs
The Apache Portable Runtime Library
URL and Path Requirements
Using Languages Other than C and C++
Inside the Working Copy Administration Area
The Entries File
Pristine Copies and Property Files
WebDAV
Programming with Memory Pools
Contributing to Subversion
Join the Community
Get the Source Code
Become Familiar with Community Policies
Make and Test Your Changes
Donate Your Changes
8. 完整 Subversion 參考手冊
Subversion 命令列用戶端: svn
svn 選項
svn 子命令
svn add
svn cat
svn checkout
svn cleanup
svn commit
svn copy
svn delete
svn diff
svn export
svn help
svn import
svn info
svn list
svn log
svn merge
svn mkdir
svn move
svn propdel
svn propedit
svn propget
svn proplist
svn propset
svn resolved
svn revert
svn status
svn switch
svn update
svnadmin
svnadmin 選項
svnadmin 子命令
svnadmin list-unused-dblogs
svnadmin create
svnadmin dump
svnadmin help
svnadmin load
svnadmin lstxns
svnadmin recover
svnadmin rmtxns
svnadmin setlog
svnlook
svnlook 選項
svnlook author
svnlook cat
svnlook changed
svnlook date
svnlook diff
svnlook dirs-changed
svnlook help
svnlook history
svnlook info
svnlook log
svnlook proplist
svnlook tree
svnlook youngest
A. 給 CVS 使用者的 Subversion 指引
不同的修訂版號
目錄版本
更多不需網路的動作
區分狀態與更新
分支與標記
中介資料性質
衝突排解
二進制檔案與轉換
Versioned Modules
B. 匯入 CVS 檔案庫
需求
執行 cvs2svn.py
C. 故障排除
常見問題
使用 Subversion 的問題
每當我想要存取檔案庫時, 我的 Subversion 用戶端會停在那裡.
當我想要執行 svn 時, 它就說我的工作複本被鎖定了.
尋找或開啟檔案庫時有錯誤發生, 但是我確定我的檔案庫 URL 是正確的.
我要如何在 file:// URL 中指定 Windows 的磁碟機代號?
我沒有辦法經由網路寫入資料至 Subversion 檔案庫.
在 Windows XP 中, Subversion 伺服器有時會送出損壞的資料.
要在 Subversion 用戶端與伺服器進行網路傳輸的檢查, 最好的方法是什麼?
編譯 Subversion 的問題
我把執行檔編輯好了, 但是當我想要取出 Subversion 時, 我得到 Unrecognized URL scheme. 的錯誤.
當我執行 configure, 我得到像 subs-1.sed line 38: Unterminated `s' command 的錯誤.
我無法在 Windows 以 MSVC++ 6.0 來編譯 Subversion.
D. WebDAV 與自動版本
基本 WebDAV 概念
簡易 WebDAV
DeltaV 擴充
Subversion 與 DeltaV
將 Subversion 對映至 DeltaV
自動版本支援
mod_dav_lock 的替代品
自動版本互通性
Win32 網路資料夾
Mac OS X
Unix: Nautilus 2
Linux davfs2
E. 其它 Subversion 用戶端
Out of One, Many
F. 協力廠商工具
ViewCVS
SubWiki
Glossary

List of Figures

2.1. 典型的主從式系統
2.2. 應避免的問題
2.3. 鎖定-修改-解鎖的解決方案
2.4. 複製-修改-合併的解決方案
2.5. …複製-修改-合併的解決方案 (續)
2.6. 檔案庫的檔案系統
2.7. 檔案庫
4.1. 發展的分支
4.2. 起始檔案庫的配置
4.3. 有新複本的檔案庫
4.4. 檔案歷史的分支
5.1. 一種建議的檔案庫配置.
5.2. 另一種建議的檔案庫配置.
7.1. Subversion's "Big Picture"
7.2. Files and Directories in Two Dimensions
7.3. Revisioning Time—the Third Dimension!

List of Tables

2.1. 檔案庫存取的 URL
7.1. A Brief Inventory of the Subversion Libraries
E.1. Subversion 的圖形用戶端

List of Examples

5.1. 利用 svnshell, 在檔案庫之中巡行
5.2. txn-info.sh (回報未處理異動)
5.3. 使用漸進式檔案庫傾印
6.1. 登錄項目 (.REG) 檔案的範例.
7.1. Using the Repository Layer
7.2. Using the Repository Layer with Python
7.3. A Simple Script to Check Out a Working Copy.
7.4. Contents of a Typical .svn/entries File
7.5. Effective Pool Usage

前言

如果 C 給了你夠多的繩子來吊死自己, 那麼 Subversion 可視為是一種收納繩子的器具. ”—Brian Fitzpatrick

在開放原碼軟體的世界中, Concurrent Versions System (CVS)長久以來, 一直都是版本控制的不二選擇. CVS本身是自由軟體, 而且它是 “非鎖定式” 的系統 —這讓分布廣闊的程式設計人員能夠分享彼此的工作— 完全符合開放原碼世界的合作模式. CVS, 以及它那半混亂式的發展模式, 已經成為開放原碼文化的基石.

但是就像許多的工具, CVS 已經開始顯露疲態. 比較起來, Subversion 是一個新的工具, 是設計來成為 CVS 的後繼者. 設計者要以兩個方法來贏得 CVS 使用者的心: 產生一個設計 (還有 "外觀與感覺") 類似 CVS 的開放原碼系統, 以及試著修正 CVS 中最廣為人知的缺點. 雖然結果不見得會是版本控制設計的下一個偉大革命, 但是 Subversion 絕對 會是個強力, 可用性高, 而且深具彈性的工具.

目標讀者

本書是寫給那些想要以 Subversion 來管理資料的電腦使用者. 雖然 Subversion 可以在許多不同的作業系統上執行, 不過主要的使用界面還是命令列. 由於這樣的原因, 本書的例子都假設使用者使用的是類似 Unix 的作業系統, 而且熟悉 Unix 與其命令列的界面.

大多數的使用者可能是程式設計師或系統管理員, 需要追蹤原始碼的的變更; 這是 Subversion 最常見的用法, 因此也是本書例子的情景. 但是請記住, Subversion 可以用來管理任何類似的資訊: 圖形, 音樂, 資料庫, 文件等等. 對 Subversion 而言, 所有的資料就只是資料而已.

雖然本書撰寫時, 我們假設讀者都沒有使用過版本控制軟體, 但是我們也試著讓 CVS 的使用者能夠很快地上手. 一些 sidebar 會隨時出現討論 CVS, 而且也有一章附錄用來概述 CVS 與 Subversion 之間的不同.

本書結構

本書的前三章對 Subversion 有概括性的介紹. 我們一開始先介紹 Subversion 的功能, 討論它的設計與使用者模型, 然後進行一個導引. 不管是否有相關的經驗, 所有的讀者都應該讀這幾章的內容. 它們是本書其它章節的基礎.

第四, 五, 六章討論比較複雜的議題, 像是分支, 管理檔案庫 (repository), 以及進階的功能, 像是性質, 外部定義, 以及存取控制. 系統管理員與進階使用者絕對會希望讀這幾章的.

第七章是特別寫給那些想要在他們的軟體裡使用 Subversion 的 API, 或者是想要修改 Subversion 的程式設計師.

本書最後以參考資料結束: 第八章是所有 Subversion 命令的參考指南, 而附錄則涵蓋了許多有用的主題. 這幾章大概是你在讀完本書之後, 最常使用的部份.

排版慣例

### O'Reilly almost certainly needs to fill this in, depending on how they typeset the book.

請注意這裡使用的程式碼例子, 就只是—單純的例子. 在適當的編譯器設定之下, 它們都能夠正常被編譯, 但是只是用來示範手邊的問題而已, 而不是用來作為程式設計的範例.

本書是自由的

本書起初只是 Subversion 計畫的發展人員所寫的文件而已, 後來就成為獨立的工作, 並且重新改寫. 因為如此, 這個文件也和 Subversion 一樣, 使用的是自由的開放原碼授權. 事實上, 本書是在公眾面前寫成的, 是 Subversion 的一部份. 這意味著兩件事:

  • 你可以在 Subversion 的源碼樹中, 找到本書的最新版本.

  • 你可以任意散佈、修改本書 — 它用的是自由授權. 當然了, 除了散佈自己私有的版本, 我們比較希望你能夠將回應與修正送回給 Subversion 開發者社群. 請參見 the section called “Contributing to Subversion”, 以了解如何加入本社群.

You can send publishing comments and questions to O'Reilly here: ###insert boilerplate.

http://svnbook.red-bean.com 可以找到還滿新的線上版本.

致謝

### Huge list of thanks to the many svn developers who sent patches/feedback on this book.

### Also, individual-author acknowledgements to specific friends and family.

Chapter 1. 簡介

版本控制是管理資訊變化的技術. 對於程式設計者來說, 它已經成為不可或缺的工具, 他們常常將花時間修改軟體, 產生部份的變更, 然後第二天再取消所作的變更. 想像有一群程式設計人員同時工作的情況, 你就能夠理解, 為什麼需要一個良好的系統來管理可能的混亂.

什麼是 Subversion?

Subversion 是一個自由/開放源碼的版本控制系統, 也就是說 Subversion 管理著隨時間改變的檔案. 這些檔案放置在一個中央 檔案庫 (repository) 中. 這個檔案庫 很像一個尋常的檔案伺服器, 不過它會記住每一次檔案的變動. 這樣你就可以把檔案回復到舊的版本, 或是瀏覽檔案的變動歷程. 許多人會把版本控制系統想像成某種 “時光機器”.

某些版本控制系統也是 software configuration management (SCM) 系統. 這些系統是特別設計來管理大量程式碼的, 而且具有許多功能, 專門用在軟體發展之用 — 像是可完全了解程式語言, 或是提供編譯軟體的工作. 不過 Subversion 並不是這樣的系統; 它是一個泛用系統, 可用來管理任何 類型的檔案, 其中包括了程式源碼.

Subversion 的歷史

在 1995 年時, Karl Fogel 與 Jiim Blandy 成立了 Cyclic Software, 提供 Concurrent Versions System (CVS) 的商業支援, 並著手改良它. Cyclic 作出了第一個具網路功能的 CVS 公開版本 (由 Cygnus 軟體公司捐贈). 在 1999 年, Karl Fogel 出版了一本書, 講的是 CVS, 以及它所促成的開放源碼發展模式. Karl 與 Jim 很早前就提過, 要製作一個 CVS 的取代軟體的概想; Jim 甚至還起草了一個新的, 理論性的 檔案庫設計, 而且還想到了一個不錯的計劃名稱. 最後, 在 2000 年二月, CollabNet (http://www.collab.net) 的 Brian Behlendorf 提供 Karl 全職的工作, 專職發展 CVS 的替代程式. Karl 集合了一個團隊, 於五月開始發展. 由於 Subversion 是以自由授權撰寫的, 它很快就吸引了一堆發展人員.

Subversion 的原始設計團隊定下了幾個簡單的目標. 他們決定它必須在功能上可取代 CVS. 也就是說, 所有 CVS 可達成的事, 它都要能夠作到. 在修正最顯而易見的瑕疵的同時, 還要保留相同的發展模式. 還有, Subversion 應該要和 CVS 很相像, 任何 CVS 使用者只要花費少許的力氣, 就可以很快地上手.

經過十四個月的撰寫之後, Subversion 於 2001 年 8 月 31 號開始 “自行管理”. 也就是說, 發展人員不再使用 CVS 來管理 Subversion 的程式碼, 而以 Subversion 自己來管理.

雖然起始這個計畫, 與提供大部份成果的資金都歸功於 CollabNet (它付出幾位全職 Subversion 開發人員的薪水), 這還是個開放源碼計畫, 由一般開放源碼界所公認的規則所支配. CollabNet 擁有程式碼的版權, 不過程式碼是以 Apache/BSD 風格的版權發行, 完全符合 Debian Free Software Guidelines. 換句話說, 每個人都可以隨意地自由下載、修改、以及重新散播 Subversion; 完全不需要經過 CollabNet, 或是任何人的允許.

Subversion 的功能

Subversion 哪裡比 CVS 的設計更好? 這裡是個簡短的列表, 以滿足你的好奇心. 如果你不熟悉 CVS 的話, 可能不了解這些特色在哪裡. 別害怕: 第二章會提供你版本控制的簡單介紹.

目錄版本控制

CVS 只能追蹤單獨檔案的歷史, 不過 Subversion 實作了一個 “虛擬” 的版本控管檔案系統, 能夠依時間追蹤整個目錄的更動. 目錄檔案都被納入版本控管. 最後, 用戶端有真正可用的 move (移動) 與 copy 指令.

不可分割的送交

一個送交動作, 不是導致所有更動都送入檔案庫, 就是完全不會送入. 這讓發展人員以邏輯區段建立更動, 並送交更動.

納入版本控管的描述資料 (Meta-data)

每一個檔案與目錄都附有一組隱形 “性質 (property)”. 你可以自己發明, 並儲存任何你想要的鍵值對. 性質是隨著時間來作版本控管的, 就像檔案內容一樣.

選擇不同的網路層

Subversion 有抽象的檔案庫存取概念, 可以讓人很容易地實作新的網路機制. Subversion “先進” 的網路伺服器, 是 Apache 網頁伺服器的一個模組, 它以稱為 WebDAV/DeltaV 的 HTTP 變體協定與外界溝通. 這對 Subversion 的穩定性與互通性有很大的幫助, 而且額外提供了許多重要功能: 舉例來說, 有身份認證, 授權, 線上壓縮, 以及檔案庫瀏覽. 另外也有小而獨立的 Subversion 伺服器程式, 使用的是自訂的通訊協定, 可以很容易地透過 ssh 以 tunnel 方式使用.

一致的資料處理方式

Subversion 使用二進制差異運算法, 來表示檔案的差異, 它對文字 (人類可理解的) 與二進制檔案 (人類無法理解) 兩類的檔案都一視同仁. 這兩類的檔案都同樣地以壓縮形態儲存在檔案庫中, 而且檔案差異是以兩個方向在網路上傳送的.

更有效率的分支 (branch) 與標記 (tag)

分支與標記的花費並不必一定要與計畫大小成正比. Subversion 建立分支與標記的方法, 就只是複製該計畫, 使用的方法就像 hard-link 一樣. 所以這些動作只會花費很小, 而且是固定的時間.

Hackability

Subversion 沒有任何的歷史包袱; 它主要是一群共用的 C 程式庫, 具有定義完善的 API. 這使得 Subversion 便於維護, 並且可被其它應用程式與程式語言使用.

安裝 Subversion

Subversion 建立在一個可移殖的 layer, 稱為 APR (Apache Portable Runtime 程式庫) 上. 這表示 Subversion 應該可以在任何可以執行 Apache 的 httpd 伺服器的作業系統上: Windows, Linux, 所有的 BSD 分支, Mac OS X, Netware, ... 等等.

取得 Subversion 最簡單的方式, 就是下載為你的作業系統所編譯的二進制套件. Subversion 的網站 (http://subversion.tigris.org) 常常有自願者提供的, 可供下載的可執行檔. 網站上, 也常有供微軟作業系統使用者使用的圖形介面安裝套件. 如果你使用的是 Unix 系的作業系統, 你可以使用系統內定的套件發行系統 (rpm, deb, ports), 來取得 Subversion.

另外, 你也可以直接從源碼建立 Subversion. 你可以從網站上, 下載最新的源碼發行檔. 解開之後, 請遵循 INSTALL 檔案裡的說明, 把它建立起來. 請注意發行的源碼套件中, 包含了所有你需要建立命令列用戶端, 可與遠端檔案庫溝通的套件 (尤其是 apr, apr-util, 以及 neon 程式庫). 但是 Subversion 還有許多其它相依套件, 像是 Berkeley DB, 另外 Apapche httpd 也是個可能性. 如果你想要建立一個 “完整的” 的編譯, 請確定你具備了所有記載在 INSTALL 裡的套件. 如果你計劃要與 Subversion 工作, 你可以使用你的用戶端程式, 抓取最新的, 流血前線的源碼. 這記載在 the section called “Get the Source Code” 內.

Subversion 的元件

安裝好之後, Subversion 會有數個不同的部份. 以下是你取得的程式的快速綜覽.

用戶端元件 (供使用者使用)

svn

命令列用戶端程式. 這是用來管理資料的主要工具, 在第 2, 3, 4, 以及第 6 章有詳細說明.

svnversion

用來回報工作複本的混合版本狀態. (請參考 Chapter 2, 基本概念, 以了解混合版本的工作複本.)

伺服器元件 (供管理員使用)

這些會在 Chapter 5, Repository 管理 中討論.

svnlook

用來檢閱 Subversion 的檔案庫的工具.

svnadmin

用來調整與修整 Subversion 的檔案庫的工具.

mod_dav_svn

給 Apache-2.X 網頁伺服器使用的外掛模組; 可以用來將你的檔案庫透過網路對外開放, 以供他人進行存取。

svnserve

一個獨立的伺服器程式, 可以作為伺服器行程執行, 或是被 SSH 啟動; 另一個讓你的檔案庫在網路上可供其他人存取的方法.

假設你已經正確地安裝 Subversion, 你應該可以開始使用了. 接下來的兩章, 我們會帶領你涵蓋 Subversion 的命令列用戶端程式 svn 的使用.

Chapter 2. 基本概念

本章對 Subversion 有簡短與非正式的描述. 如果你是版本控制的新手, 本章相當適合你. 我們一開始會討論一般性的版本控制, 慢慢導向 Subversion 背後的概念, 並且利用 Subversion 舉出簡單的例子.

即使本章都以人們共同一群程式源碼來作為例子, 但是請記住 Subversion 可用來管理任何種類的檔案 — 並非僅僅侷限在幫助程式設計師而已.

檔案庫

Subversion 是一個用以分享資訊的中央系統, 核心為 檔案庫 (repository), 作為儲存資料的集散地. 檔案庫儲存資料的形式是 檔案系統樹 (filesystem tree) — 也就是典型的目錄與檔案的架構. 許多的 用戶端 會先連上檔案庫, 然後對這些檔案作讀取或寫入的動作. 藉由寫入資料, 一個用戶端能夠讓資訊為他人所用; 藉由讀取資料, 該用戶端能夠擷取他人的資訊.

Figure 2.1. 典型的主從式系統

典型的主從式系統

為什麼這樣會很有趣? 到目前為止, 這些聽起來就像一個典型的檔案伺服器. 事實上, 檔案庫 就是 一種檔案伺服器, 但是與你所見的不太相同. 讓 Subversion 檔案庫如此不同的原因, 在於 它會記住所有的更動: 每個檔案的每一個更動, 甚至是每一個目錄所作的更動, 像是目錄與檔案的新增, 刪除, 以及重新編排.

當一個用戶端自檔案庫讀取資料時, 它通常只會看到最新版本的檔案系統樹. 但是用戶端也可以看到早先的檔案系統. 舉例來說, 用戶端可以詢問歷史性的問題, 像是 "上個星期三, 這個目錄裡有什麼東西?", 或 "誰是最後一個更動這個檔案的人, 而且作了哪些更動?" 這就是任何 版本控制系統 的核心問題: 記錄並追蹤隨著時間對資料所作的更動.

各種版本控制的模型

檔案分享的問題

所有的版本控制系統都必須解決同樣的基本問題: 如何讓使用者分享資料, 但是不讓他們不小心成為彼此的阻礙? 使用者要不小心覆寫掉彼此在檔案庫裡的更動, 實在是太容易了.

考慮一下以下的情景: 假設我們有兩個協同工作人員, Harry 與 Sally. 他們決定同時編輯同一個儲存在檔案庫的檔案. 如果 Harry 先存入檔案庫, (幾個月之後) Sally 很有可能以她自己的新版檔案覆寫過去. 雖然 Harry 的版本並不會就此消失 (因為系統記得每一次的更動), 但是任何 Harry 所作的更動不會出現在 Sally 的新版檔案中, 因為她打從一開始就沒看過 Harry 的更動. 總地來說, Harry 的心血就這麼消失了—至少從該檔案的最新版就遺漏掉了—. 這絕對是我們想要避免的情況!

Figure 2.2. 應避免的問題

應避免的問題

鎖定-修改-解鎖的解決方案

許多版本控制系統以鎖定-修改-解鎖的方式 來解決這個問題, 這是個很簡單的解決方案. 在這樣的系統中, 檔案庫在同一時間只允許一個人修改一個檔案. 首先 Harry 必須在他開始更動之前, 先 "鎖定" 該檔案. 鎖定檔案就像從圖書館借書; 如果 Harry 已鎖定一個檔案, 那麼 Sally 就無法對其進行任何更動. 如果她想要鎖定該檔案, 檔案庫會拒絕她的要求. 她所能作的, 就只是讀取這個檔案, 然後等著 Harry 完成他的更動, 解除他設下的鎖定. 在 Harry 解除該檔案的鎖定之後, 他的回合就結束了, 現在輪到 Sally 可以對其進行鎖定並編輯內容.

Figure 2.3. 鎖定-修改-解鎖的解決方案

鎖定-修改-解鎖的解決方案

鎖定-修改-解鎖模型的問題, 在於它的限制多了點, 而且經常會成為使用者的絆腳石:

  • 鎖定可能會造成管理上的問題. 有的時候 Harry 在鎖定一個檔案之後, 然後就忘了這件事. 在此同時, 由於 Sally 還在等著編輯這個檔案, 她什麼事也不能作, 然後 Harry 就跑去休假了. 現在 Sally 必須找個管理員, 才能解除 Harry 的鎖定. 這樣狀況, 最後導致了許多不需要的延遲與時間的浪費.

  • 鎖定可能造成不必要的工作瓶頸 如果 Harry 編輯的是文字檔的開頭部份, 而 Sally 只是要修改同一檔案的結尾部份呢? 這樣的更動完全不會重疊在一起. 他們可以同時修改同一個檔案, 而不會造成任何的傷害, 只要這些更動適當地合併在一起. 像這樣的情況, 他們並不需要輪流進行才能完成.

  • 鎖定可能會造成安全的假象 假設 Harry 鎖定並編輯檔案 A, 同時 Sally 鎖定並編輯檔案 B. 但是假設 A 與 B 彼此相依, 而對各檔案所作的修改是完全不相容的語意. 突然之間 A 與 B 彼此無法執行. 鎖定系統完全無法避免這樣的狀況 —但是它在某種程度上提供了一種安全的假象. 它很容易讓 Harry 與 Sally 認為藉由鎖定檔案, 每個人都有個好的開始, 工作互不干涉, 如此讓他們不會在早期就討論他們互不相容的更動

複製-修改-合併的解決方案

Subversion, CVS, 還有其它的版本控制系統使用一種 複製-修改-合併的模型, 作為鎖定的取代方法. 在這種模型下, 每一個使用者用戶端會讀取檔案庫, 然後建立檔案或計畫的 工作複本. 然後使用者進行各自的工作, 修改他們自己的私有複本. 最後, 私有複本會合併在一起, 以產生一個新的, 最後的版本. 版本控制系統通常會協助合併的動作, 但是最後人類還是負有讓它能夠產生正確結果的責任.

這裡舉個例子. 假設 Harry 與 Sally 各自從檔案庫 建立同一個專案的工作複本. 他們同時工作, 並對同一個複本中的檔案 "A" 作了修改. Sally 先將她的更動送回檔案庫. 當 Harry 試著要存回他的更動時, 檔案庫會通知他, 他的檔案 A 已經 過時. 換句話說, 檔案庫裡的檔案 A 在他上次產生複本後已經更動過了. 所以 Harry 要求他的用戶端程式, 將檔案庫裡新的更動與他的檔案 A 工作複本 合併 起來. 通常 Sally 的更動與他的更動不會重疊; 所以只要讓兩組更動整合在一起, 他就可以將他的工作複本回存至檔案庫.

Figure 2.4. 複製-修改-合併的解決方案

複製-修改-合併的解決方案

Figure 2.5. …複製-修改-合併的解決方案 (續)

…複製-修改-合併的解決方案 (續)

要是 Sally 的更動真的與 Harry 的更動重疊的話呢? 這該怎麼辦呢? 這種情況稱為 衝突 (conflict), 通常也不會是多大的問題. 當 Harry 要求用戶端程式將最新的檔案庫更動, 合併到他自己的工作複本時, 他自己的檔案 A 會被標示為衝突的狀態: 他可以看到兩邊互相衝突的更動, 然後手動在這兩者之間作選擇. 請注意, 軟體不會自動地解決衝突; 只有人類才有理解能力, 進而作出明智的決定. 當 Harry 手動地解決重疊的更動之後 (也許就是和 Sally 討論這個衝突!), 他就可以安全地將手動合併的檔案存回檔案庫.

複製-修改-合併模型聽起來有點混亂, 但是實務上跑起來可是相當地平順. 使用者可以同時各自工作, 不需等待他人. 當他們同時處理同一個檔案時, 大多數的情況下, 這些同時產生的更動都不會互相重疊; 衝突是相當少見的. 而且解決衝突所需要的時間, 也遠低於鎖定系統所損失的時間.

最後, 這些通通都回歸到一個最重要的因素: 使用者溝通. 當使用者彼此溝通不良時, 語法與語意衝突都會增加. 沒有任何系統能夠強迫使用者完美地溝通, 而且也沒有任何系統能夠偵測出語意衝突. 所以並沒有任何論點, 能夠導出鎖定系統可減少衝突發生的虛假承諾; 實務上, 鎖定系統似乎比其它系統對生產力有更大的傷害.

Subversion 實務

工作複本

你已經讀過有關工作複本的部份; 現在我們要示範 Subversion 如何建立並使用它.

Subversion 工作複本就只一個普通的目錄樹, 位於你的本地系統中, 其中包含了一堆檔案. 你可以依你喜好, 自由地編輯這些檔案. 而且如果這些是源碼檔, 你可以依一般的方法編譯它們. 你的工作複本就是你自己的私有工作空間: Subversion 不會將其它人的更動合併進來, 也不會讓你的更動讓他人取得, 除非你明確地要求要這樣作.

你在自己的工作複本檔案中作了一些更動, 並且確認它們都能正常地工作, 此時 Subversion 提供你許多命令, 讓你將這些更動 "發表" 給同一計畫的其他人使用 (藉由寫至檔案庫). 如果別人發表了他們的更動, Subversion 提供你許多命令, 可將這些更動合併至你的工作目錄中 (藉由讀取檔案庫).

工作複本也包含了其它額外的檔案, Subversion 建立並維護這些檔案, 讓它自己可以執行這些命令. 特別一提, 工作複本中的每個目錄都會有一個名為 .svn 的子目錄, 也就是工作複本的 管理目錄. 每個工作目錄中的檔案, 都能夠幫助 Subversion 了解哪些檔案有未出版的更動, 哪些與其他人的工作相比是過時的檔案.

一個典型的 Subversion 檔案庫通常會包含數個專案使用的檔案 (或源碼檔); 一般來講, 每一個專案是檔案庫檔案樹中的子目錄. 在這樣的安排中, 一個使用者的工作複本, 通常對應到檔案庫裡的某一特定的子目錄.

舉例來說, 假設你有一個包含兩個軟體專案的檔案庫.

Figure 2.6. 檔案庫的檔案系統

檔案庫的檔案系統

換句話說, 檔案庫的根目錄有兩個子目錄: paintcalc.

要取得一個工作複本, 你必須 取出 (check out) 某個檔案庫裡的子目錄. ("check out" 聽起來有點像是要鎖定或預約某項資源, 但是它不是; 它就只是為你建立一個計畫的私有複本.) 舉個例子, 如果你取出 /calc, 你會得到一個像這樣的工作複本:

$ svn checkout http://svn.example.com/repos/calc
A  calc
A  calc/Makefile
A  calc/integer.c
A  calc/button.c

$ ls -a calc
Makefile  integer.c  button.c  .svn/

這一串字母 A, 表示 Subversion 已經加入幾個物件到你的工作複本之中. 現在你有檔案庫的 /calc 目錄的個人複本, 外加一些額外的東西—.svn— 這裡面有 Subversion 所需的額外資訊, 早先有提到過.

假設你更動了 button.c. 由於 .svn 目錄會記得檔案的修改日期與原始的內容, Subversion 能夠知道你改了這個檔案. 但是 Subversion 不會讓你的更動公諸於世, 除非你明確地表明要這麼作. 發表你的更動的行為, 通常稱為 送交 (或 存入 (check in)) 更動至檔案庫.

要發表你的更動讓其他人知道, 可以使用 Subversion 的 commit 命令:

$ svn commit button.c
Sending button.c
Transmitting file data..
Committed revision 57.

現在對 button.c 所作的更動, 已經送交至檔案庫了; 如果其他使用者取出 /calc 的工作複本, 他們會在最新版的檔案中看到你的更動.

假設你有個合作伙伴 Sally, 他和你同一時間取出 /calc 的工作複本. 當你送交你對 button.c 的更動, Felix 的工作複本並沒有改變; Subversion 只會依使用者要求來變更工作複本.

要讓她的專案也能跟上變動, Sally 可以藉由使用 Subversion 的 update 命令, 要求 Subversion 更新 他的工作複本. 這會讓你的更動合併到她的工作複本中, 外加他人自上次取出檔案以後所送交的更動.

$ pwd
/home/sally/calc

$ ls -a 
.svn/ Makefile integer.c button.c

$ svn update
U button.c

以上取自svn update命令的輸出, 表示 Subversion 更新了 button.c 的內容. 請注意 Felix 不必指定要更新哪個檔案; Subversion 使用 .svn 目錄與檔案庫裡的額外資訊, 來決定哪些檔案必須更新到最新版.

修訂版本

svn commit的動作, 可以將不限數目的檔案與目錄的更動, 視為單一不可分割的異動以進行發表. 在你的工作複本中, 你可以修改檔案的內容, 建立, 刪除, 更名, 以及複製檔案與目錄, 然後將所有的更動視為一個單位, 一口氣送交回去.

在檔案庫中, 每一次的送交都被視為是一個不可分割的異動: 不是所有送交的更動都成功, 就是全部都不成功. Subversion 會試著維持這樣的不可分割特性, 不管是遭遇程式失敗, 系統當機, 網路有問題, 還是其它使用者進行的動作.

每一次檔案庫接受一個送交的更動, 就會讓檔案樹進入一個新的狀態, 稱之為 修訂版本. 每一個修訂版本都會被賦與一個唯一的, 比前一個修訂版號大一的自然數. 一個新建立的檔案庫的修訂版號為零, 其中除了空的根目錄外, 什麼都沒有.

有一個把檔案庫具象化的好方法, 就是將之視為一系列的樹. 想像有一系列的修訂版號, 自左至右, 由 0 開始. 每一個修訂版號下都有一個檔案系統的樹狀結構, 每一個檔案樹都是每一次送交之後的檔案庫 “快照”.

Figure 2.7. 檔案庫

檔案庫

請特別注意, 工作複本並不見得一定會符合檔案庫某一特定的修訂版; 每個檔案可能會對應到不同的修訂版本. 舉個例子, 假設你的工作目錄, 是從檔案庫登出了 4 號修訂版:

calc/Makefile:4
     integer.c:4
     button.c:4

此時工作目錄對應的是檔案庫的 4 號修訂版. 不過要是你修改了 button.c, 送交這個更動. 假設此時其它人都沒有送交任何更動, 你所送交的更動就會變成檔案庫的第 5 號修訂版, 然後你的工作複本就會變成像這樣:

calc/Makefile:4
     integer.c:4
     button.c:5

假設在這個時候, Sally 送交了 integer.c 的更動, 產生了 6 號修訂版. 如果你以 svn update 更新你的工作目錄, 它看起來就會像這樣:

calc/Makefile:6
     integer.c:6
     button.c:6

Sally 對 integer.c 的更動會出現在你的工作複本中, 而你的更動還是在 button.c 之中. 在這個例子中, 版本 4, 5, 6 的 Makefile 內容都是一樣的, 不過 Subversion 會將工作複本中的 Makefile 標示為版本 6, 表示它還是最新版本. 所以, 在你對工作複本作了一次完整更新之後, 它基本上就是完全對應到檔案庫的某一個版本.

工作複本如何追蹤檔案庫

對每個工作目錄中的檔案, Subversion 會在管理區域 .svn/ 中, 記錄兩個重要的資訊:

  • 工作檔案的基本修訂版本 (亦稱為檔案的 工作版本), 以及

  • 時間戳記, 記錄本地複本最近一次被檔案庫更新的時間.

有了這些資訊, 再藉由諮詢檔案庫, Subversion 就可以決定某個工作檔案是處於下列四個狀態何者之一:

未更動, 現行版本

本檔案在工作目錄中未被更動, 而且自工作版本之後, 也沒有任何該檔案的更動被送交回去. 對它執行 svn commit 不會發生任何事, 執行 svn update 也不會發生任何事.

本地修改, 現行版本

這個檔案在工作目錄中被修改過, 而自其基礎修訂版號後, 也沒有任何更動送交回檔案庫. 由於有尚未送交回去的本地端修改, 所以對它的 svn commit 會成功地發表你的更動, 而 svn update 則不會作任何事.

未更動, 過時版本

這個檔案在工作目錄中並未更動, 但是檔案庫已被更動. 本檔案應該要更新, 以符合公開修訂版. 對它的 svn commit 不會發生任何事, 而 svn update 會讓工作目錄中的檔案更新至最新版本.

本地修改, 過時版本

這個檔案在工作目錄與檔案庫都受到了更動. 對它執行 svn commit 會產生 "out-of-date" 錯誤. 這個檔案應該要先被更新; svn update 會試著將已發表的更動, 與本地的更動合併在一起. 如果 Subversion 無法自動無誤地完成它, 那麼就會留給使用者, 讓他來解決這個衝突.

聽起來好像要注意很多東西, 但是 svn status 的命令會顯示任何在工作複本裡的項目的狀態. 欲取得該命令更詳細的資訊, 請參見 the section called “svn status”.

混合修訂版的限制

Subversion 的一個基本原則, 就是要盡量地保有彈性. 有一種特別的彈性, 就是工作複本可包含混合修訂版的能力.

一開始可能無法理解, 為什麼這樣的彈性會被視為一項特色, 而不是責任. 在完成至檔案庫的送交動作後, 剛送交的檔案與目錄的修訂版, 會比工作複本其它部份的修訂版還要新. 這看起來有點混亂. 就像我們早先示範過的, 我們永遠都可藉由 svn update, 將工作複本帶回至單一的工作修訂版. 為什麼會有人要 故意 混合不同的工作修訂版呢?

假設你的專案夠複雜, 你發現有時強制將工作複本的某些部份帶回到 “舊版本” 反而更好; 在第 3 章, 你會學到怎麼達成. 也許你想要對早先版本的子模組進行測試, 也許你想要在最新的檔案樹中, 檢視某個檔案幾個過去的版本.

但是, 當你在工作複本中使用混合修訂版時, 這項彈性有幾個限制.

首先, 如果檔案或目錄不全都是最新版本時, 對它們的刪除動作是無法送交的. 如果一個項目在檔案庫中, 存在著比目前更新的版本, 你想要送交的刪除動作會被拒絕, 以防止你不小心毀了還沒看過的更動.

第二, 你無法送交一個對目錄的描述資訊更動, 除非它完全是最新版本的. 你會在第 6 章學到如何將 “性質” 附加到項目. 一個目錄的工作修訂版, 會定義出特定的實體與性質的集合, 因此送交一個對過時目錄的性質更動, 很有可能會毀掉你還沒檢視過的性質.

摘要

本章涵蓋了幾個 Subversion 的基本概念:

  • 我們介紹了中央檔案庫, 用戶端工作複本, 以及檔案庫修訂版樹的陣列.

  • 本章示範幾個例子, 說明兩個協同工作者如何利用 '複製-修改-合併' 模式, 透過 Subversion 來發表並接收彼此所作的更動.

  • 我們也談了一些有關 Subversion 如何追蹤與管理工作複本的資料.

現在, 你應該對 Subversion 如何工作有個清楚的概念. 有了這樣的知識, 你現在已經準備好進行到下一章, 對 Subversion 的命令與功能來個詳細的巡禮.

Chapter 3. 導覽

現在我們將詳細講解如何使用 Subversion. 當你看完這一章後, 應該就能夠進行每日會用到的功能. 一開始會先取出程式碼, 更動程式, 然後檢視這些更動. 你也會看到如何將別人的更動, 取回至自己的工作複本. 檢視這些更動, 然後處理可能發生的衝突.

請注意本章並不打算列出所有 Subversion 的命令—更確切地說, 它