在 Subversion 中使用 WebDAV
本文詳敘了WebDAV怎樣用于Subversion。特別是,客戶端怎么用Neon生成WebDAV請求,以及服務器端怎么將WebDAV請求轉變成Subversion代碼倉庫的操作。這里的服務器端是一個作為mod_dav功能后端的Apache 2.0模塊。
本文大量引用了 Subversion設計文檔和最新的 Delta-V協議草案。這兩份文檔的詳細內容就不在本文中重復了。
注意:Subversion使用DeltaV來進行通信,但是Subversion客戶端并不是一個通用的DeltaV客戶端。實際上,Subversion客戶端依賴于服務器的一些專有特性。更進一步來說,Subversion服務器端也不是一個通用的DeltaV服務器。它只是實現了DeltaV協議的一個子集。當且僅當只使用Subversion服務器端實現的這個子集的功能時,WebDAV或者DeltaV客戶端才能正常的與 Subversion服務器端協作
Subversion的2.0版將會處理WebDAV協作性(包括與Class 1、Class 2和DeltaV)的問題。Subversion客戶端需要的專有特性都會在DeltaV中提供一個替代方案,雖然替代方案不太高效。
Subversion的1.0版會支持只讀的Class 1 WebDAV客戶端。任何能夠增強DeltaV協同性,且容易實現的功能都將被考慮。
基本概念
Subversion使用一個基于樹的格式來描述版本庫的變更集。這個樹是在客戶端(通過在工作副本中“行走”)被構造用來描述變更。這個樹作為被應用于版本庫一個線性序列的變更被編組到服務端。版本庫可以以隨機存取的方式接受變更,所以從樹到一系列變化的映射對版本庫來說非常容易。
Subversion為文件,目錄甚至修訂版本的抽象概念提供了屬性。牽涉屬性的每一個操作可以通過操作PROPFIND和PROPPATCH HTTP方法直接映射到WebDAV的屬性。修訂版本被建模為DeltaV基線,所以修訂版本的屬性可以通過基線的PROPFIND來獲得。
Subversion服務端能夠有效的計算兩個版本之間的增量(這些增量是完整的樹增量,不是簡單的文本增量)。Deltav沒有直接模擬樹增量概念。客戶端可以通過在各種WebDAV資源上發送一系列PROPFIND請求發現變更,但是這個調用多個請求將是一個耗時的操作。作為替代,Subversion將這個概念整理為一個自定義的WebDAV報告。使用這個報告,客戶端可以了解工作副本中的哪項過時并可以發送GET和 PROPFIND方法獲取新數據。
在Subversion中,分支和標簽是簡單的拷貝,是用WebDAV COPY處理的。
在某處需要討論拷貝.需要討論拷貝的歷史如何被保存 (svn是自動處理的, 但是與其他服務端交互的時候可能需要我們在其他服務端設置一個自定義屬性.
Subversion中使用的Deltav概念
Subversion使用了許多Deltav概念, 列表如下. 注意這些概念中有很多并沒有被Subversion完全實現; 我們已經實現了足夠的概念以滿足我們的需要,但是比較少.
-
基線
-
活動
-
版本資源
-
版本控制配置
-
基線集合
-
版本控制的資源
-
工作資源(功能)
-
合并功能
-
標簽功能
-
版本控制集合功能
Subversion項目表現為URL形式
第一個要定義的概念是項目是如何顯示給客戶端的。 在服務端Subversion將所有項目表現為URL的形式。 這個項目下的文件或子目錄將通過URL命名空間被表現。
例如,假設我們有一個叫做“example”的項目。并且我們說,這個項目將被表現為這個URL: http://subversion.tigris.org/repos/example/。
這個映射通過Apache HTTP Server(在問題中托管Subversion代碼和特定項目)的一系列配置參數被設置。配置可能像下面這樣:
<Location /repos/example> DAV svn SVNPath /home/svn-projects/example </Location>
這個項目下的文件或目錄將直接被映射到URL命名空間。例如,如果這個項目在一個子目錄“sub”中包含一個文件“file.c”,那么那個文件的 URL將是: http://subversion.tigris.org/repos/example/sub/file.c。
初始檢出
當用戶執行一個Subversion項目的初始檢出操作,客戶端將發出一連串的PROPFIND和GET請求。這些請求將遍歷版本庫,獲得一些所需的元數據, 然后獲得最新的修訂版本號.描述獲取活動集合的OPTIONS請求。描述到達基線集合的一系列PROPFIND請求。
(從下面移到這里,需要被重寫)
當初始化檢出操作被執行后, Subversion獲取到DAV:活動集合給定值并在工作副本的每個目錄中將其存儲為屬性。每個集合都有屬性。屬性列出了服務端活動被創建的位置。第一個位置被存儲在客戶端用來在提交過程中使用。
或許應該描述我們獲取元數據后,檢出“非最新的”(如日期或修訂版本號)如何工作。
提交變更
Subversion提交使用Deltav的“活動”概念來建模。一個活動能夠被看做是一次傳輸一系列資源。
創建活動
在提交的時候, Subversion客戶端將讀取存儲的DAV:DAV:activity-collection-set用來了解應該在哪里創建活動。 接下來,客戶端將為活動的位置生成一個UUID(惟一值) 。最后客戶端發送一個MKACTIVITY方法請求, 請求的URL從活動位置和UUID被表現。zh
簡短總結:
-
在檢出時:
-
請求: OPTIONS for DAV:activity-collection-set
響應:http://www.example.com/repos/foo/$svn/act/
-
在提交時:
-
請求: MKACTIVITY http://www.example.com/repos/foo/$svn/act/01234567-89ab-cdef-0123-456789abcdef
響應: 201 (Created)
CHECKOUT方法能夠指定一個活動用來檢出。 這個功能用于關聯所有的條目和新創建的活動。
存儲提交信息
檢出基線,并對工作基線應用PROPPATCK方法。
將變更映射到WebDAV
Subversion的變更集用tree delta表示(查看SVN的設計細節以確定那些變更可以放進tree delta)。tree delta會被拆成請求集,其中請求是以下幾種形式之一:
-
刪除文件或目錄
這些變更被映射成DELETE操作。目標父集的版本資源使用CHECKOUT方法檢出(到當前活動)。目標(名稱)隨后被DELETE方法從結果工作集刪除。 -
添加文件
這種變更會映射為對目標父集的版本資源進行CHECKOUT操作。新文件被使用PUT請求創建于結果工作集。屬性使用PROPPATCH設置。 -
添加目錄
這種變更被映射為對目標父集的版本資源進行CHECKOUT操作。新目錄被使用MKCOL請求創建于結果工作集。屬性通過PROPPATCH設置。 -
添加指向前代祖先(副本)的文件或目錄(這種文件或目錄類似linux的文件鏈接?)
需要更新本節
tree delta可以指定文件或目錄為其他文件或目錄的一份副本。這個副本可被其他元素的tree delta修改。
這種變更被映射為,對包含新資源的父集的版本資源進行CHECKOUT操作。VERSION-CONTROL方法會在當前工作集內創建新的版本控制資源(VCRs),VCR的DAV:checked-in屬性指向其祖先的版本資源。 -
提示:看起來我們應該使用COPY把正確資源拷入當前工作集。這將會創建一個新的版本歷史(隨后被放入當前工作集),該版本歷史使用DAV:precursor-set屬性指定其祖先的版本資源。
由于版本資源不指定修訂版,不可能COPY一個版本資源到當前工作集,此舉不會通知我們究竟是哪個修訂版被拷貝。相反,我們最好從正確的基線中拷出版本資源。這表明,客戶端可以把一個URL/修訂版對映射為基線的版本資源URL。
第二個問題時,我們如何設置版本歷史的 DAV:precursor-set屬性。或者,更詳細點,我們如何根據存儲在倉庫的信息提取該值。這仍需要研究。 -
用文件/目錄替換另一個文件/目錄
這種變更不能對應WebDAV的任何操作,因為tree delta會映射為兩個連續的操作:先delete然后add -
移動文件或目錄
這種變更不能對應WebDAV的任何操作,因為tree delta會映射為兩個不同的操作:先delete然后add前代祖先。 -
替換文件
映射為對目標的版本資源進行CHECKOUT操作,然后PUT到結果工作集。 -
替換目錄
在Subversion的術語中,“替換目錄”意味著目錄內的添加、刪除及其他操作。每個變更會單獨映射,而且對目錄的變更是隱式操作的。 -
屬性delta
屬性delta(與文件或目錄相對)直接被映射為WebDAV術語中的PROPPATCH。目標的版本資源使用CHECKOUT檢出,PROPPATCH會應用于結果工作集。
最終提交
最后的提交動作將會向Subversion服務器生成一個MERGE請求,指定檢入的活動(之前創建),以及被更新的指向新版本資源的相應版本控制資源。
關于當前工作基線,以及如果用其創建新的基線(包含提交信息),下文的評論(?)并不正確。
版本控制資源也是基線控制的,即對它的更新會自動創建一個新基線。本質上,提交會相應于新的Subversion修訂版創建一個新基線。
例子
警告: 本節沒有更新到最新對SVN-to-DAV的映射的變更,在此警告移除前,暫認為本節已過期。
考慮下以下一組操作,以及相應的tree delta(摘自SVN的設計文檔):
-
重命名/dir1/dir2為/dir1/dir4,
-
重命名/dir1/dir3為/dir1/dir2, 并且
-
把file3從/dir1/dir4移動到/dir1/dir2.
01 |
< tree-delta > |
02 |
< replace name = 'dir1' > |
03 |
< directory > |
04 |
< tree-delta > |
05 |
< replace name = 'dir2' > |
06 |
< directory ancestor = '/dir1/dir3' > (1) |
07 |
< tree-delta > |
08 |
< new name = 'file3' > (2) |
09 |
< file ancestor = '/dir1/dir2/file3' /> |
10 |
</ new > |
11 |
</ tree-delta > |
12 |
</ directory > |
13 |
</ replace > |
14 |
< delete name = 'dir3' /> (3) |
15 |
< new name = 'dir4' > (4) |
16 |
< directory ancestor = '/dir1/dir2' > |
17 |
< tree-delta > |
18 |
< delete name = 'file3' /> (5) |
19 |
</ tree-delta > |
20 |
</ directory > |
21 |
</ new > |
22 |
</ tree-delta > |
23 |
</ directory > |
24 |
</ replace > |
25 |
</ tree-delta > |
遍歷此delta,我們列出了對應的WebDAV請求。上文delta的數字編號大致相當于下面的列表項編號。這種對應關系并不十分準確,因為一個特定的、既成的行為通常基于delta中的一組元素。
-
<directory ancestor="/dir1/dir3"> 指定我們用/dir1/dir3替換/dir1/dir2
CHECKOUT /dir1/dir2/
(返回該目錄的一個當前工作資源URL)COPY /dir1/dir3/
Destination: http://www.example.com/$svn/wrk/.../
Overwrite: T -
/dir1/dir2/file3是新的(因為我們剛剛重寫了原始的dir2目錄),并來源于/dir1/dir2/file3。因此,我們只需要COPY文件到目標目錄的當前工作資源:
COPY /dir1/dir2/file3
Destination: http://www.example.com/$svn/wrk/.../file3 -
CHECKOUT /dir1/dir3/
(返回該目錄的一個當前工作資源URL)DELETE /$svn/wrk/.../
-
我們將會在/dir1下創建新的子目錄(dir4)。由于還沒有檢出/dir1,我們這樣做:
CHECKOUT /dir1/
(返回該目錄的一個當前工作資源URL)現在我們把正確的目錄復制到新的當前工作資源:
COPY /dir1/dir2/
Destination: http://www.example.com/$svn/wrk/.../dir4/ -
COPY在服務器上創建了完整的一組當前工作資源,我們只需刪除不再需要的那部分:
DELETE: /$svn/wrk/.../dir4/file3
URL布局
Subversion 服務器通過自定義的URL公開倉庫。例如,foo倉庫可能位于http://www.example.com/repos/foo/。但是,服務器還需要一組其他公開資源來保證正常操作。這些附加資源會與主倉庫URL下的某位置下的所有倉庫關聯。默認,此位置為$svn,也可以通過 SVNSpecialURI指令來設置:
<Location /repos/foo> DAV svn SVNPath /home/svn-projects/foo SVNSpecialURI .special </Location>
在SVNSpecialURI指定的位置下,我們需要公開一些集合(collections)。假設我們使用默認的$svn,這些集合為:
-
$svn/act/
-
此區域是活動創建的位置。客戶端需要選擇在此集合內唯一的名字,然后向該URL發送一個MKACTIVITY。然后,客戶端就可以使用該活動做進一步交互。
$svn/act/內的資源不能使用方法.
提示: 實際上我們可以使用帶Depth:1頭的PROPFIND來允許客戶端遍歷當前所有活動。
只有一個方法子集可以操作該集合下的活動。它們是:PROPFIND, MERGE (提交活動), and DELETE (終止活動).
根據Delta-V規范,所有的活動資源在DAV:activity下都有DAV:resourcetype屬性。
-
$svn/his/
-
本節需要改進;事實上,我們沒有使用版本歷史資源,將來,它們可能被設計成類似下面的模型:
此集合包含一個項目下的文件和目錄的版本歷史資源。其內部布局完全由服務器定義。客戶端將通過多個響應獲取此集合及其子集合的URL。
$svn/his/內的資源不能使用方法。
URL的命名空間被設計成如下的URL形式:
$svn/his/node-id
node-id是Subversion用來引用單獨文件和目錄的內部值,是由Subversion倉庫定義的單個整數值。注意此node-id是非點狀節點ID(undotted node id ?),倉庫中給定節點的全部歷史的基礎。
node-id的DAV:resourcetype的集合是DAV:version-history.
提示: 上文信息可能不太準確。鏈接一個版本歷史到其他版本歷史的問題仍然存。進一步,我認為node 73 和 node 73.4.1是各自的版本歷史(后者鏈接到了前者)。73.x 和73.4.1.x 是版本歷史內的版本。
-
$svn/ver/
-
這個集合包含項目的版本資源。
$svn/ver/內的資源不能使用方法。
這個集合的布局由服務器定義。為了引用(以及描述實現)的需要,它被設計為:
$svn/ver/node-id/path
只有只讀的方法才能用在這些資源上,如 GET, PROPFIND, REPORT;其他方法都是不合法的。
版本資源的DAV:resourcetype是檢入時資源的值。(如 <D:resourcetype/> 或 <D:resourcetype><D:collection/></D:resourcetype>).
-
$svn/wrk/
-
此集合包含所有通過CHECKOUT方法被檢出的資源的當前工作資源。集合的形式和結構也由服務器定義,也是明確定義的,這樣客戶端才可以與被檢出的集合資源進行適當交互。
$svn/wrk/內的資源不能使用方法。
為了引用目的,當前工作資源的URL被設計成:
$svn/wrk/activity/path
所有方法都能用在當前工作資源上,但是不能用在其父資源上。
當前工作資源的 DAV:resourcetype遵循一般資源命名方式:<D:resourcetype/>代表經常性的當前工作資源,<D:resourcetype><D:collection/></D:resourcetype>代表當前工作集。
-
$svn/vcc/
-
本節還不完整。
版本控制的配置(version-controlled configuration)...
$svn/vcc/root是個單例(singleton)
-
$svn/bln/
-
本節還不完整。
基線(baselines)...
$svn/bln/rev/
-
$svn/wbl/
-
本節還不完整。
當前工作基線(working baseline)...
-
$svn/bc/
-
本節還不完整。.
基線集合(baseline collection)...
屬性管理(以及歷史/日志報告)
本節需要修訂。屬性發生在FS修訂版中(通過基線公開)。
之前也提到過,Subversion的屬性會映射到WebDAV的屬性。對歷史/日志報告,下面的WebDAV屬性適用于每個基線(Subversion修訂版)和每一個修訂版創建的版本資源。由于這些資源都是版本資源,因此下面的屬性都是只讀的。
-
DAV:comment
用于指定檢入評論的標準的(過期的)屬性 -
DAV:creator-displayname
Subversion的“用戶”一次特定修改后生成的(已過期的)屬性 -
DAV:creationdate
提交時服務器生成的只讀(未過期的)屬性
一個特定文件的歷史將會通過REPORT方法和DAV:property-report報告生成。一個典型的歷史將會獲取每個文件或目錄版本的以上三個屬性。
基于客戶端的設計,指定關于版本信息的其他只讀屬性可能很重要。例如,一個文件檢入時,有多少行增加/刪除?生成這些屬性將會相當直接,并會隨著時間由客戶端的設計推動。
提示: 如果我們這樣做,我們將會把客戶端捆綁于服務器。如果客戶端與其他不報告這些屬性的Delta服務器交互,我們簡單地在UI中不顯示它們就可以了(如優雅的功能退化,graceful degradation of functionality)。
獲取狀態和更新
初始檢出后,客戶端就可以請求狀態報告(客戶端的變更,會掛起提交,服務器的變更,會掛起更新)。更新過程是類似的,但還會獲取服務器上的變更。
本地的變更將全部由客戶端處理。當前工作拷貝(the Working Copy)庫會很容易地檢測和報告這些變更。我們只需要關心,如何高效地檢測服務器上的變更。
雖然可以遍歷倉庫,獲取當前狀態,然后與客戶端狀態進行比較,但是這樣做不是高效的。Subvesion的設計允許服務器在獲知客戶端狀態的情況下,輕松地計算出變更(相對于客戶端)。
status和update命令的核心是基于自定義的、Subversion特定的WebDAV報告。這份自定義的報告將會通知服務器當前工作拷貝的狀態,服務器的響應將會指定哪些資源需要被更新。
這種請求是個包含自定義XML結構的標準REPORT請求。這個結構體,將利用Subversion報告頂層修訂版號的方法,只報告修訂版不同的子節點。報告的響應也會使用相同的方式報告有變更的資源。如果有變更,服務器將會提供一個供獲取已變更資源的URL。服務器也會報告當前修訂版號。
請求和響應的XML DTD都是TBD。
自定義報告將只適用于支持此報告的服務器,但是將來的軟件版本可能包含一個回退的代碼路徑(優雅的退化)來支持其他DeltaV服務器。
更新時,客戶端將會獲取(使用GET請求)每個服務器響應提供的URL。
可能的話,GET(和PUT)操作將會使用diff格式傳遞內容。該機制遵循名為HTTP的Delta編碼的因特網草案。
實體標簽 (etags)
etag需要在一個資源的所有版本中保持唯一。幸好,對版本管理系統來說,這很容易。每個etag可以簡單地為資源所在的倉庫節點ID(node-id)
etag通常用于生成diff(差異),可以參考上文提及的草案 HTTP中的Delta編碼。現在問題是如果獲取存儲在客戶端的每個文件(不需要文件夾的etag,因為我們從不讀取)的etag。在檢出或更新過程中,很簡單:etag包含在所獲取的每個文件的HTTP響應頭里。
問題的另一個方面是如何獲取一次提交后的etag。版本資源是在活動檢入時創建的,而MERGE響應頭提供了一種獲取版本資源屬性的方法,etag以及其他屬性可以通過此機制獲取。
標簽和分支
在Subversion中標簽和分支被復制從一個區域到另一個區域被執行。例如:
[.../src/my-project]$ svn cp trunk tags/1.0.3-rc4 [.../src/my-project]$ svn commit
在上面的例子中,tags/1.0.3-RC4 現在應該考慮只讀并時刻反映trunk的狀態。
這些副本就像一個普通的提交處理。 activity 用MKACTIVITY創建,工作資源通過CHECKOUT 創建(例如上面在我們的例子中 目標目錄;tags/),然后執行復制操作。該activity然后合并到有MERGE要求的信息庫。
服務器需求
警告: 本節已過期。DeltaV草案已經歷了多個修訂版,我們使用的版本變更了一部分。
DAV方法
為了能正常操作,服務器需要實現以下WebDAV方法:
-
OPTIONS
-
GET
-
DELETE
-
COPY
-
PROPPATCH
-
PROPFIND
-
MKACTIVITY
-
CHECKOUT
-
MERGE
-
REPORT
當前Subversion需要下面的方法:
-
CHECKIN
-
UNCHECKOUT
-
UPDATE
-
LABEL
-
VERSION-CONTROL
-
BASELINE-CONTROL
-
MKWORKSPACE
DAV屬性
以下DeltaV屬性需要被實現:
-
DAV:comment
-
DAV:creator-displayname
-
DAV:supported-method-set
-
DAV:supported-live-property-set
-
DAV:supported-report-set
-
DAV:version-controlled-configuration
-
DAV:checked-in
-
DAV:auto-version,是個只讀的空元素(不支持自動版本化/auto-versioning)
-
DAV:checked-out
-
DAV:predecessor-set
提示:在多個前驅版本如何合并生成單個新修訂版機制上,Subversion的設計文檔表述不是很清楚。搞明白之后發現,DAV:predecessors可能最終包含多余零個或一個前驅URL
-
DAV:version-name, (全局)修訂版本號
-
DAV:checkout-fork
-
DAV:checkin-fork
-
DAV:auto-update
-
DAV:subbaseline-set,只讀空屬性(不支持子基線/sub-baselines)
-
DAV:unreserved,被設成F
-
DAV:baseline-controlled-collection
-
DAV:baseline-collection
-
DAV:subactivity-set,只讀空屬性(不支持子活動/sub-activities)
-
DAV:eclipsed-set,總是空(內部成員不能被隱藏)
與DeltaV規范相反,下面的必須屬性沒有被實現:
-
DAV:successor-set,獲取該值計算量很大
-
DAV:checkout-set,事實上我們沒有被檢出的記錄,而是使用工作資源URL來提供必要的信息;因此我們沒有記錄數據來填充該屬性
-
DAV:merge-set, MERGE只支持一次提交。并不支持規范里定義的任意合并
-
DAV:auto-merge-set ,等同DAV:merge-set.
-
DAV:activity-version-set,僅用于工作資源的活動,這樣版本不能是活動的一部分
也許應該被定義為空集?
-
DAV:activity-checkout-set,僅用于工作資源的活動,我們也不記錄哪些工作資源存在
-
DAV:activity-set,僅用于工作資源的活動,這樣版本不能是活動的一部分
也許應該被定義為空集?
-
DAV:version-controlled-binding-set,我們沒有版本歷史資源賦給此屬性
OPTIONS
OPTIONS請求表示支持下文的DAV特性:
-
1
-
2
-
版本控制/version-control
-
檢出/checkout
-
工作資源working-resource
-
合并/merge
-
基線/baseline
-
活動/activity
-
版本控制集/version-controlled-collection
報告(reports)
DAV:supported-report-set屬性表示支持以下報告:
-
svn:update-report
-
svn:log-report
這些報告僅可用在公共資源(版本控制資源, VCRs)上。$svn/內的資源不可用。
注意事項,提醒
討論超時和自動清洗的活動(以及相關工作資源)。
討論通過的mod_dav_svn維護熱數據庫。
討論ra_dav和mod_dav_svn的其他實施細則。
附錄A:基本原理
有好幾次,人問,“為什么選擇HTTP/ WebDAV/ DeltaV系統?這似乎是非常臃腫,不適合。你為什么不設計一個定制的,精心調校的協議?或者,使用cvs協議?”下面列出的是一些我們選擇WebDAV作為我們的網絡協議的原因。
雖然這個名單當然可以有更多的理由去擴展(為了公平,列出為何WebDAV的是一個糟糕的選擇的原因),但同時那肯定證明了我們的選擇它的基本原因。
注:此表來自電子郵件,所以語氣和觀點可能有點過。而且文字推敲也這樣。
內置網頁瀏覽的資料庫
例如,一起來看看:http://svn.apache.org/repos/asf/subversion/trunk/README(這是概述,我們還對以前版本每個文件的網址)
基于DAV瀏覽
使用Web文件夾或WebDrive或類似在Windows中(適用于Windows XP的原生DAV坐騎)瀏覽SVN倉庫與Windows資源管理器。 Mac OS X中有內置的DAV服務器的安裝。Nautilus 擁有DAV功能。然后,你有你的開源工具,如cadaver,Goliath等
人們可以利用現有的庫
我甚至不能開始計算的HTTP工具和可用的庫的數量。如果我們設計我們自己的協議,那么我們將得不到任何好處。兩個HTTP庫的實現(Joe Orton of Neon, and Daniel Stenberg of CURL)都是這樣。我用Python的httplib的(和我自己的davlib)做了很多我們的服務器的測試。沒有必要去和推出新的協議庫。
現有的工具
一個字:虛: - )當我們捕獲網絡跟蹤,粗略的了解HTTP。這是相當不錯的,但我知道有更棒的。不過我們也有其他的工具,比如squid 和其他(高速緩存)代理(見下一條)。
緩存代理
Subversion與緩存代理一起會工作得更有效。沒有必要再使用特殊的工具如cvsup。只要訪問緩存代理,你就擁有了一個分布式的只讀倉庫。那個歐洲開發小組只要訪問他們與美國服務器間的緩存,他們的檢出和更新就會被緩存下來,以方便小組內的其他成員。而提交將會流經緩存,發回美國服務器。
復雜和多選認證
我們沒必要為新協議重新實現一個認證模式,因為已經可以使用為HTTP定義的一簇模式。看過CVS協議嗎?見過“我愛你”或者“我恨你”吧(表示重新實現協議過程中,程序員的愛恨情緒)?:-) 這就是創建新的認證模式的全部。但是只要我們愿意,我們就可以使用SSL和基于證書的認證。還有Kerberos, NTLM, 甚至是簡單的Basic或者摘要(Digest)。我們的用戶可以來自文本文件,數據庫,LDAP, 或PAM。我們不必重新發明輪子,因為這些Apache都可以用。
超棒的網絡服務器
我們不必擔心如何設置可移植TCP_CORK以提供最佳的網絡數據包。我們不必擔心何時使用sendfile()是有道理的,或者何時它是可用的。我們不必擔心斷開的客戶端連接,如何充分利用線程和進程如何縮放,請求管理,監視,日志記錄等。Apache給了我們這些所有或者更多。我"真的"不希望通過 xinetd這樣做。我的意思是...在標準輸出上設置TCP_CORK?怪異:-)
明確定義在線壓縮
我們已經使用了在線壓縮,類似于CVS的“-z#”開關。而其他我們什么也沒做。客戶端庫和服務器,對于我們來說只是根據 RFC2616 使用了自動支持。
未來互操作性
在未來,我們將能夠實現與眾多IDE和其他WebDAV/ DeltaV客戶端互操作。由于DeltaV的日益流行,集成開發環境可以很好地使用它的源代碼管理,而不需要寫一些MS/ SCC庫接口的工具。