Apache Subversion 常見問題集

翻譯:日本語簡體中文

這些問題與目前 支援的版本 相關。對於較舊的問題,請參閱 下方

目錄

一般問題

操作指南

疑難排解

開發人員問題

參考資料


一般問題:

Subversion 是什麼?它為什麼存在?

Subversion 是開源的集中式版本控制系統。請參閱我們首頁的 願景,以了解 Subversion 存在的理由。想快速瀏覽嗎?請參閱 快速入門

Subversion 是專有軟體嗎?

不,Subversion 是開源/免費軟體。幾家公司(CollabNet、WANdisco、VisualSVN、elego,...)支付或曾支付一些全職開發人員的薪水,但軟體採用 Apache 授權,完全符合 Debian 自由軟體準則。換句話說,你可以自由下載、修改和重新分發 Subversion,無需任何公司或個人的許可。

Subversion 的穩定性如何?

Subversion 非常穩定。它是一款成熟的軟體,具有強大的 相容性保證。Subversion 開發社群非常重視其穩定性和健壯性。

Subversion 自 2000 年開始開發,並於一年後成為自託管。一年後,當我們宣佈「alpha」時,Subversion 已被數十位私人開發人員和商店用於實際工作。在那之後,我們又花了兩年的時間修復錯誤和穩定程式,才達到 1.0。大多數其他專案可能早就將產品稱為「1.0」,但我們故意決定盡可能延後這個標籤。我們知道許多人都在等待 1.0 才使用 Subversion,而且對這個標籤的意義有非常具體的期望。因此,我們堅持相同的標準。

Subversion 的用戶端/伺服器互通性政策是什麼?

用戶端和伺服器設計為只要它們的版本號不超過一個主要版本,就能一起運作。例如,任何 1.X 用戶端都能與 1.Y 伺服器一起運作。但是,如果用戶端和伺服器版本不匹配,某些功能可能無法使用。此類限制總是記錄在我們發行的 發行說明 中。

我們的用戶端/伺服器互通性政策記載於 Subversion 社群指南 的「相容性」區段中。

Subversion 能在哪些作業系統上執行?

所有現代版本的 Unix、Windows、BeOS、OS/2、macOS。

Subversion 以 ANSI C 編寫,並使用 Apache Portable Runtime 函式庫 APR 作為可攜層。Subversion 用戶端可以在 APR 能執行的任何地方執行,也就是大多數地方。Subversion 伺服器(即儲存庫端)也是一樣,但它不會在 Win9x 平台(Win95/Win98/WinME)上主機 Berkeley DB 儲存庫,因為 Berkeley DB 在 Win9x 上有共用記憶體區段的問題。FSFS 儲存庫(在版本 1.1 中引入)沒有這個限制;但是,由於 Win9x 的檔案鎖定支援有限,它們也不適用於 Win9x。

重申一次,Subversion 客户端可以在任何运行 APR 的平台上运行。Subversion 服务器也可以在任何运行 APR 的平台上运行,但不能在 Win95/Win98/WinMe 上托管存储库。

关于新文件系统的一切是什么?它像 ext2 吗?

不。Subversion 文件系统不是内核层文件系统,人们会将其安装在操作系统中。相反,它是 Subversion 的存储库界面,它是一个版本化文件系统,因为它存储了一个目录树,其状态从一个版本记住到另一个版本。编写程序来访问存储库类似于编写使用其他文件系统 API 的程序。主要区别在于此特定文件系统在写入时不会丢失数据;可以像检索最新状态一样轻松地检索旧树状态。

我需要什么样的硬件来运行 Subversion 服务器?

服务器需求取决于许多因素,例如用户数量、提交频率和其他服务器相关操作、存储库大小以及自定义存储库钩子产生的负载。在使用 Apache 时,Apache 本身很可能是内存使用量最大的因素。

请记住考虑在同一服务器上运行的其他应用程序;例如,存储库浏览器也会使用资源,而与 Subversion 本身无关。

一般来说,您可以预期需要的服务器内存比同等 CVS 存储库少得多。

我听说 Subversion 是 Apache 扩展?它用于服务器什么?

編號。Subversion 是一組函式庫。它附帶一個使用它們的命令列用戶端。有兩個不同的 Subversion 伺服器程序:svnserve,這是一個類似於 cvs pserver 的小型獨立程式,或使用特殊 mod_dav_svn 模組的 Apache httpd-2.0svnserve 使用自訂協定,而 mod_dav_svn 使用 WebDAV 作為其網路協定。請參閱 Subversion 書籍中的 第 6 章 以進一步了解。

這是否表示我必須設定 Apache 才能使用 Subversion?

簡短的答案:否。

詳細的答案:如果您只想存取儲存庫,那麼您只需要建置一個 Subversion 用戶端。如果您想主機一個網路儲存庫,那麼您需要設定 Apache2 或「svnserve」伺服器。

有關設定網路可存取 Subversion 伺服器的更多詳細資訊,請參閱 Subversion 書籍中的 第 6 章

我現在執行 Apache 1.x,而且無法切換到 Apache 2.0 只是為了提供 Subversion 儲存庫。這是否表示我無法執行 Subversion 伺服器?

否,您可以執行 svnserve 作為 Subversion 伺服器。它運作得非常好。

如果您想要 WebDAV 和 Apache 伺服器附帶的所有其他「好處」,那麼是的,您將需要 Apache 2.0。在繼續於埠 80 上執行 Apache 1.x 的同時,在不同的埠上執行 Apache 2.0 始終是一個選項。不同版本的 Apache 可以愉快地共存在同一台機器上。只要將 httpd.conf 中的 Listen 指令從「Listen 80」變更為「Listen 8080」或您想要的任何埠號,並確保在發佈儲存庫 URL 時指定該埠(例如,http://svn.mydomain.com:8080/repos/blah/trunk/)。

為何您不執行 X,就像 SCM 系統 Y 一樣?

Subversion 沒有嘗試模仿所有現有 SCM 系統的功能。請參閱 我們的願景

為何整個儲存庫共用相同的版本號碼?我希望我的每個專案都有自己的版本號碼。

首先,請注意 Subversion 沒有專案的概念。儲存庫僅儲存版本化的目錄樹 — 您可能會將某些子樹視為專案,但 Subversion 並不會將它們與其他子樹區別對待。因此,儲存庫中專案的解釋完全取決於使用者。(這類似於 分支標籤 是建立在複製之上的慣例,而不是 Subversion 本身內建的基本概念。)

每次您提交變更時,儲存庫會儲存該整體儲存庫樹的新版本,並標記新樹為新的版本號碼。當然,除了您變更的部分之外,大部分樹與之前的版本相同。

新的版本號碼是適用於整個新樹的順序標籤,而不仅仅是您在該版本中觸及的檔案和目錄。然而,在口語中,版本號碼用於指稱在該版本中提交的變更;例如,「r588 中的變更」(「r588」是「版本 588」的簡稱)實際上表示「儲存庫樹 587 和 588 之間的差異」,或換句話說,「對樹 587 進行的變更以產生樹 588」。

因此,前進的版本號標記了整個儲存庫的進度;您通常無法透過觀察版本號來評估儲存庫中特定專案的進度。此外,版本號不應當作儲存庫中特定專案的公開可見發布號碼。對於這一點,您應設計其他機制來區分發布,例如使用 標籤

Subversion 有變更集嗎?

這個問題有點沉重,因為每個人似乎對於「變更集」都有略微不同的定義,或至少對於版本控制系統擁有「變更集功能」的意義有略微不同的期待。

為了這個討論的目的,以下是變更集的簡單定義:它是一個具有唯一名稱的變更集合。變更可能包括檔案內容的文字編輯、樹狀結構的修改或元資料的調整。用更通俗的說法,變更集只是一個您可以引用的具有名稱的修補程式。

Subversion 將版本化樹狀結構管理為一階物件(儲存庫是樹狀結構陣列),而變更集是衍生的東西(透過比較相鄰樹狀結構)。Arch 或 Bitkeeper 等系統則是以相反的方式建構:它們被設計為將變更集管理為一階物件(儲存庫是一袋修補程式),而樹狀結構則透過將修補程式集合組合在一起而衍生出來。

這兩種哲學在絕對意義上都沒有比較好:這場辯論至少已經持續 30 年。這兩種設計對於不同類型的軟體開發來說各有優劣。我們在此不討論這個問題。相反地,以下是您可以使用 Subversion 執行的說明。

在 Subversion 中,全域版本號碼「N」會為儲存庫中的樹狀結構命名:這是儲存庫在第 N 次提交後的樣貌。它也是隱含變更集的名稱:如果你將樹狀結構 N 與樹狀結構 N-1 進行比較,你可以導出已提交的確切修補程式。

基於這個原因,很容易將「版本 N」視為不只是樹狀結構,也是變更集。如果你使用問題追蹤器來管理錯誤,你可以使用版本號碼來參考修正錯誤的特定修補程式,例如「此問題已由版本 9238 修復」。然後,有人可以執行「svn log -r9238」來閱讀已修正錯誤的確切變更集,並執行「svn diff -r9237:9238」來查看修補程式本身。而 svn 的合併指令也使用版本號碼。你可以透過在合併參數中命名特定變更集,將它們從一個分支合併到另一個分支:'svn merge -r9237:9238 branchURL' 會將變更集 #9238 合併到你的工作副本中。

這遠遠不及建構在變更集作為主要物件的系統那麼複雜,但它仍然比 CVS 方便許多。

下一個版本何時發布?

請參閱我們的 路線圖頁面

我還有其他問題。可以在哪裡取得更多資訊?

如果您瀏覽完此常見問題集後仍找不到答案,還有其他幾項可用的資源

為什麼我的文章沒有顯示在郵件清單上?

我們的郵件清單會進行審核以防止垃圾郵件通過,因此您第一次發文到任何清單時可能會延遲,直到審核人員有機會讓它通過。一旦該文章被允許通過,來自同一個地址的所有後續文章都會自動核准,因此您應該不會再遇到延遲。當然,如果您的寄件地址變更,則必須再次通過審核。

夏令時間 (DST) 的變更如何影響 Subversion?

DST 的變更不需要對 Subversion 程式碼進行任何特別的變更或修正。Subversion 主要使用日期/時間來記錄變更已提交到儲存庫的時間。此程式碼在伺服器上執行,並從作業系統取得目前的日期/時間,並使用作業系統提供的常式將其轉換為 UTC。Subversion 用戶端從伺服器接收這些日期,並使用用戶端作業系統提供的常式將其轉換為當地時區以顯示。因此,您應該只需要安裝作業系統提供的修補程式,而且您真的只需要確保伺服器上的時間已針對 DST 進行適當調整。

SHA-1 雜湊碰撞如何影響 Subversion?

Google 和 CWI 發表了已知的首個 SHA-1 衝突,揭露了 Subversion 使用 SHA-1 的幾個相關問題。Subversion 的核心並未依賴 SHA-1 進行內容索引,但它在以下補充功能中用於此類目的

  • 儲存庫資料重複刪除功能(「rep 快取」),以及
  • 工作副本中的內容重複刪除功能。

談到儲存庫資料重複刪除功能,這可能會導致無法存取具有衝突 SHA-1 值的檔案,或造成此類檔案的資料遺失。若要防止具有相同 SHA-1 的不同內容儲存在儲存庫中,請升級到 1.9.6 或 1.8.18,預設情況下,這會防止儲存具有此類衝突的資料。有關詳細資訊,請參閱我們的 SHA-1 建議

在升級到這些新版本之前,基於 Unix 的伺服器可以使用在 這裡 找到的提交前掛鉤。順便一提,我們歡迎 Windows 開發人員提交 Windows 平台的提交前腳本。有關提交的更多資訊,請參閱 這裡

工作副本使用 SHA-1 對儲存的內容進行重複刪除,並且出於效能原因,客戶端將避免擷取具有相同 SHA-1 檢查碼的內容。此問題的解決方法是從一開始就防止儲存衝突的物件,方法是升級到 1.9.6 或安裝上述提交前腳本。

儲存具有 SHA-1 衝突的內容並非受支援的使用案例。如果您有具有衝突 SHA-1 hash 值的內容,我們建議您在提交之前透過 gzip 轉換它,以完全避免衝突。此外,強烈建議升級到 1.9.6 以防止未來插入重複資料。

操作方法:

我如何查看 Subversion 程式碼?

使用 Subversion 軟體用戶端

	$ svn co https://svn.apache.org/repos/asf/subversion/trunk subversion

這將在您的本機上檢出 Subversion 原始碼樹的副本,並儲存在名為 subversion 的目錄中。

我如何建立儲存庫?我如何匯入資料到儲存庫中?

請參閱 快速入門。如需更多詳細資訊,請參閱 Subversion Book 中的快速入門說明

如需有關儲存庫設定和管理的更多詳細資訊,請閱讀 Subversion Book 中的第 5 章

我如何將現有的 CVS 儲存庫轉換為 Subversion 儲存庫?

cvs2svn 轉換工具似乎是大多數人使用的工具。原始碼寄存於 https://github.com/mhagger/cvs2svn。如果您執行的是 Linux 或 BSD 系統,您的發行版可能會有 cvs2svn 套件。

如果 cvs2svn 無法滿足您的需求,您可以嘗試 Lev Serebryakov 在 http://lev.serebryakov.spb.ru/refinecvs/ 編寫的 refinecvs。

如果我在代理伺服器之後怎麼辦?

Subversion 客戶端可以透過代理伺服器,如果您設定它這麼做。首先,編輯您的「伺服器」設定檔,以指出要使用哪個代理伺服器。檔案位置取決於您的作業系統。在 Linux 或 Unix 上,它位於「~/.subversion」目錄中。在 Windows 上,它位於「%APPDATA%\Subversion」中。(嘗試「echo %APPDATA%」,請注意這是一個隱藏目錄。)

檔案中有說明如何執行的註解。如果您沒有該檔案,請取得最新的 Subversion 客戶端並執行任何命令;這將導致建立設定目錄和範本檔案。

接下來,您需要確保代理伺服器本身支援 Subversion 使用的所有 HTTP 方法。預設情況下,某些代理伺服器不支援這些方法:PROPFIND、REPORT、MERGE、MKACTIVITY、CHECKOUT。一般而言,解決此問題取決於特定的代理軟體。對於 Squid,設定選項為

   #  TAG: extension_methods
   #       Squid only knows about standardized HTTP request methods.
   #       You can add up to 20 additional "extension" methods here.
   #
   #Default:
   # none
   extension_methods REPORT MERGE MKACTIVITY CHECKOUT

(Squid 2.4 和更新版本已經知道 PROPFIND。)

另請參閱「Subversion 使用的所有 HTTP 方法是什麼?」以取得有關允許透過代理伺服器傳輸其他 HTTP 方法的建議。

如果讓代理伺服器允許 Subversion 流量很困難或不可能,但您想要檢視 Subversion 原始碼,您可能可以繞過代理伺服器。某些過濾埠 80 的代理伺服器仍然允許埠 81 上的任何內容。在許多其他情況下,代理伺服器不會像過濾 http 那樣嚴格地過濾 https。 svn.apache.org 儲存庫伺服器在 https 和 http 上都會監聽。嘗試

   svn checkout https://svn.apache.org/repos/asf/subversion/trunk subversion

代理伺服器可能會讓您通過。

當然,您的 svn 客戶端必須使用 ssl 支援來建置。您可以透過執行 svn --version 來檢查是否支援「https」架構。

我需要將 Subversion 放在反向代理伺服器之後

如果 Subversion 伺服器未直接連接到網際網路,可以使用反向代理伺服器。它會將 HTTP/HTTPS 流量從公開伺服器轉發到 Subversion 伺服器,可能會移除 HTTPS 加密。如果必須在同一個埠上提供多個不同的 HTTP 伺服器,它也可能很有用。

Subversion 使用 WebDAV/DeltaV 協定的子集;請參閱 此常見問題解答項目 以取得詳細資訊。就代理伺服器而言,Subversion 使用純粹的 WebDAV 協定。對於 svn copysvn move 指令,會使用額外的 HTTP_DESTINATION 標頭;這必須另外改寫。

針對幾個不同的代理伺服器提供詳細說明。從這些範例複製構想應該相當容易。

Apache HTTPD 的詳細說明

以下資訊根據 Konrad Rosenbaum 所撰寫的文章,最初在 http://silmor.de/proxysvn.php 上找到。經許可複製。

Apache 的代理端需要 mod_proxy 才能運作。在許多 Linux 發行版中,有可以啟用的現成組態檔,否則請在 httpd.conf 中插入此組態。

#load the module
LoadModule proxy_module modules/mod_proxy.so
#per default disallow all requests (for security)
ProxyRequests Off
<Proxy *>
  Order deny,allow
  Deny from all
</Proxy>
ProxyVia On

在代理虛擬主機的 VirtualHost 指令中,將對 Subversion 目錄的請求 (我們假設稱為 svn) 組態為中繼到實際的 Subversion 伺服器

ProxyPass /svn/ http://realsvnserver/svn/
<Location /svn/>
        ProxyPassReverse /svn/ http://realsvnserver/svn/
        <Limit OPTIONS PROPFIND GET REPORT MKACTIVITY PROPPATCH PUT CHECKOUT
               MKCOL MOVE COPY DELETE LOCK UNLOCK MERGE>
          Order Deny,Allow
          Allow from all
          Satisfy Any
        </Limit>
        
        RewriteCond %{HTTP:Destination} .+/(svn/.*$)
        RewriteRule ^/svn/.* - [E=MyDestination:http://realsvnserver/%1,PT]
        RequestHeader set Destination %{MyDestination}e env=MyDestination
</Location>

ProxyPass 指令指示 Apache 將 /svn 下方的請求重新導向到 Subversion-Apache (http://realsvnserver/svn)。ProxyPassReverse 指令指示它變更請求標頭 (位置、內容位置和 URI) 以符合目標伺服器 — 視 Apache 的版本及其組態而定,您可能需要略過 /svn/ 或 http://realsvnserver/svn/。如果可能,應在兩個伺服器上使用相同的路徑 (否則 DAV 可能會造成問題)。Limit 指令指示 Apache 允許所有來自所有用戶端的 DAV 請求 (允許) 通過,並讓實際的 Subversion 伺服器處理驗證 (滿足)。Rewrite 規則將 HTTP_DESTINATION 標頭更新為正確的伺服器/協定。

Microsoft IIS 的詳細說明

首先從 iis.net 下載並安裝 URL 重寫模組。以下範例已在 IIS 10 和 URL 重寫 2.1 中測試過。
接下來,將 URL 重寫組態為允許 HTTP_DESTINATION 伺服器變數:在 URL 重寫下的 IIS 管理員中,在右窗格中按一下「檢視伺服器變數」並新增 HTTP_DESTINATION。
最後建立一些改寫規則

  • 「ToHttps」,如果您想確保所有 Subversion 流量都已加密,如果請求未加密,這會傳送 HTTP 重新導向至用戶端。
  • 「ProxyWithDestination」,擷取所有具有 HTTP_DESTINATION 伺服器變數的請求(例如所有 svn copysvn move 請求)。HTTP_DESTINATION 標頭會重新撰寫,而且流量會轉送至 Subversion 伺服器。
  • 「ProxyRest」,將所有其他流量轉送至 Subversion 伺服器。
以下範例可以複製至 web.config。它假設 Subversion 伺服器在與 IIS 相同的電腦上,於埠 81 上執行。

<system.webServer>
 <rewrite>
  <rules>
   <clear />
   <rule name="ToHttps" stopProcessing="true">
    <match url="(.*)" />
    <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
     <add input="{HTTPS}" pattern="^OFF$" />
    </conditions>
    <action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}"/>
   </rule>
   <rule name="ProxyWithDestination" enabled="true" patternSyntax="ECMAScript" stopProcessing="true">
    <match url="(.*)" />
    <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
     <add input="{HTTP_DESTINATION}" pattern="https://(.*)"/>
    </conditions>
    <serverVariables>
     <set name="HTTP_DESTINATION" value="http://{C:1}" />
    </serverVariables>
    <action type="Rewrite" url="http://127.0.0.1:81/{R:0}" logRewrittenUrl="true" />
   </rule>
   <rule name="ProxyRest" patternSyntax="ECMAScript" stopProcessing="true">
    <match url="(.*)" negate="false" />
    <conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
    <action type="Rewrite" url="http://127.0.0.1:81/{R:0}" logRewrittenUrl="true" />
   </rule>
  </rules>
 </rewrite>
 <security>
  <requestFiltering allowDoubleEscaping="true" />
 </security>
</system.webServer>

我的管理員不希望我為 Subversion 建立 HTTP 伺服器。如果我仍然想要遠端使用,我該怎麼辦?

一個簡單的選項是使用 svnserve 伺服器,而不是 Apache。請參閱 Subversion 書籍中的 第 6 章,以取得詳細資料。

不過,如果您的管理員不希望您執行 Apache,他們很可能也不希望您在埠 3690 上執行自訂伺服器程序!因此,本答案的其餘部分假設您的管理員同意您使用現有的 SSH 基礎架構。

如果您先前曾使用 CVS,您可能已使用 SSH 登入 CVS 伺服器。ra_svn Subversion 存取方法是使用 Subversion 執行此項操作的等效方式。只要對您的 Subversion 儲存庫 URL 使用「svn+ssh」前置詞即可。

$ svn checkout svn+ssh://your.domain.com/full/path/to/repository

這會讓您的 SSH 程式在遠端方塊上啟動一個私人「svnserve」程序,該程序會以您的 UID 存取儲存庫,並透過加密連結將資訊傳輸回來。

不過,可以使用的另一種解決方案是利用 SSH 埠轉送,透過 ra_dav 連線至受保護的伺服器。您會透過 SSH 連線至防火牆後方,可以存取您的 Subversion 伺服器的機器。請注意,此 SSH 伺服器一定與安裝 Subversion 的位置相同。可以相同,但不必相同。

然後,您建立連接到放置 Subversion 儲存庫的 HTTP 伺服器的本機埠轉送。然後,您會透過這個本機埠「連線」到 Subversion 儲存庫。然後,要求會透過 SSH 伺服器「隧道路由」傳送到您的 Subversion 伺服器。

範例:Subversion ra_dav 設定位於公司防火牆後方的 10.1.1.50(稱為 svn-server.example.com)。您的公司允許透過公開可存取的 ssh-server.example.com 存取 SSH。在內部,您可以透過 http://svn-server.example.com/repos/ours 存取 Subversion 儲存庫。

範例:透過埠轉送連線到 ssh-server 的用戶端,並透過埠轉送查看

% ssh -L 8888:svn-server.example.com:80 me@ssh-server.example.com
% svn checkout https://127.0.0.1:8888/repos/ours

請注意,您的 svn-server.example.com 也可以讓其 httpd 執行個體由非受信任使用者在非特權埠上執行。這將允許您的 Subversion 伺服器不需要 root 存取權。

Joe Orton 筆記

The server is sensitive to the hostname used in the Destination header
in MOVE and COPY requests, so you have to be a little careful here - a
"ServerAlias localhost" may be required to get this working properly.

一些關於 SSH 埠轉送的連結

如何在 Subversion 中管理多個不同的專案?

這取決於所涉及的專案。如果專案相關,且可能會共用資料,那麼最好建立一個儲存庫,並包含多個子目錄,如下所示

	$ svnadmin create /repo/svn
	$ svn mkdir file:///repo/svn/projA
	$ svn mkdir file:///repo/svn/projB
	$ svn mkdir file:///repo/svn/projC

如果專案完全無關,且不太可能在它們之間共用資料,那麼最好建立獨立且無關的儲存庫。

	$ mkdir /repo/svn
	$ svnadmin create /repo/svn/projA
	$ svnadmin create /repo/svn/projB
	$ svnadmin create /repo/svn/projC

這兩種方法之間的差異如下(由 Ben Collins-Sussman <sussman@collab.net> 解釋)

  • 在第一種情況下,程式碼可以輕鬆地在專案之間複製或移動,且會保留記錄。(「svn cp/mv」目前僅在單一儲存庫中運作。)
  • 由於版本號碼是儲存庫範圍的,因此第一個案例中對任何專案的提交都會導致全球版本升級。因此,如果有人已簽出「projB」,注意到已發生 10 次版本變更,但 projB 完全沒有變更,這可能看起來有點奇怪。這其實不是什麼大問題。一開始只是有點奇怪而已。當 rapidsvn 在同一個儲存庫中時,每次有人提交 rapidsvn,這都會發生在 svn 中。 :-)
  • 第二個案例可能更容易保護;使用 Apache 的存取控制可以更輕鬆地將專案彼此隔離(就使用者和權限而言)。在第一個案例中,您需要在儲存庫中使用精巧的掛鉤指令碼來區分專案(「這個使用者是否允許提交到這個特定子目錄?」)。當然,我們已經有這樣的指令碼,您可以隨時使用。

如何合併兩個完全分開的儲存庫?

如果您不在乎保留其中一個儲存庫的所有歷史記錄,則可以只在一個專案的儲存庫下建立一個新目錄,然後匯入另一個專案。

如果您在乎保留兩個專案的歷史記錄,則可以使用「svnadmin dump」將一個儲存庫轉儲,並使用「svnadmin load」將其載入另一個儲存庫。版本號碼會不同,但您仍然會擁有歷史記錄。

Peter Davis <peter@pdavis.cx> 也說明了一種使用 svn 等效於 CVS 模組的方法

只要合併發生在不同的目錄樹中,您就可以使用 svn 版本的 CVS 模組。

在目錄上設定 svn:externals 屬性,以在每次簽出原始目錄時,從其他儲存庫簽出目錄。儲存庫仍然是分開的,但在工作副本中,它們看起來像是已經合併。如果您提交到匯入的目錄,這將會影響外部儲存庫。

合併並不完全乾淨:匯入只會影響工作副本,因此您無法使用第一個儲存庫中的 URL 來存取從第二個儲存庫匯入的模組。它們仍然是分開的 URL。

網路上也有一些有用的工具,可以在合併多個儲存庫時選擇和重新排序版本。例如,svn-merge-repos.pl perl 腳本用於基本操作,而 SvnDumpTool python 類別用於進階重新組織。

我應該將我的儲存庫/工作副本儲存在 NFS 伺服器上嗎?

如果您使用的是 FSFS 儲存庫後端(從 Subversion 1.2 開始就是預設值),那麼將儲存庫儲存在現代的 NFS 伺服器上(也就是支援鎖定的伺服器)應該是沒問題的。

如果您使用的是具有 Berkeley DB 後端 的儲存庫(使用 Subversion 1.0 和 1.1 建立的儲存庫的預設值,之後不再是預設值),我們建議不要將儲存庫儲存在遠端檔案系統(例如 NFS)上。雖然 Berkeley DB 資料庫和日誌檔可以儲存在遠端檔案系統上,但 Berkeley DB 共享區域檔無法儲存在遠端檔案系統上,因此只有單一檔案系統用戶端可以安全地存取儲存庫,而且甚至連那個用戶端都無法使用所有 Subversion 功能。

工作副本可以儲存在 NFS 上(一個常見的場景是您的家目錄在 NFS 伺服器上)。在 Linux NFS 伺服器上,由於 Subversion 在簽出檔案時內部使用大量的重新命名,一些使用者回報「子樹檢查」應該停用(預設為啟用)。請參閱 NFS Howto 伺服器指南exports(5) 以取得更多關於如何停用子樹檢查的資訊。

我們曾收到至少一份回報,指出工作副本在透過 SMB 存取後發生卡住。問題伺服器執行的是相當舊版的 Samba(2.2.7a)。問題沒有在較新的 Samba(3.0.6)中再次發生。

我如何正確設定儲存庫權限?

嘗試讓存取儲存庫的使用者數目盡量少。例如,以特定使用者身分執行 apache 或「svnserve -d」,並讓該使用者完全擁有儲存庫。不要允許任何其他使用者透過 file:/// 網址存取儲存庫,並務必僅以擁有儲存庫的使用者身分執行「svnlook」和「svnadmin」。

如果您的客戶端透過 file:///svn+ssh:// 存取,則無法避免多個使用者存取。在這種情況下,請閱讀 第 6 章的最後一節,並特別注意底部的「檢查清單」側邊欄。它概述了多項步驟,讓這個場景更安全。

SELinux / Fedora Core 3+ / Red Hat Enterprise 使用者注意事項

除了常規的 Unix 權限外,在 SELinux 下,每個檔案、目錄、程序等都有一個「安全性內容」。當一個程序嘗試存取一個檔案時,除了檢查 Unix 權限外,系統還會檢查程序的安全性內容是否與檔案的安全性內容相容。

Fedora Core 3 等系統預設安裝 SELinux,並將 Apache 設定為在相當受限的安全環境中執行。要在 Apache 中執行 Subversion,您必須設定儲存庫的安全環境,以允許 Apache 存取(或停用 Apache 的限制,如果您認為這太過頭)。chcon 指令用於設定檔案的安全環境(類似於 chmod 設定傳統 Unix 權限的方式)。例如,一位使用者必須執行此指令

   $ chcon -R -h -t httpd_sys_content_t PATH_TO_REPOSITORY

才能設定安全環境,以順利存取儲存庫。

如何從儲存庫的歷程記錄中完全移除檔案?

在特殊情況下,您可能想要銷毀檔案或提交的所有證據。(也許有人不小心提交了機密文件。)這不容易,因為 Subversion 是經過特別設計,絕不遺失資訊。版本是不可變的樹狀結構,彼此建立在彼此之上。從歷程記錄中移除版本會造成骨牌效應,在所有後續版本中造成混亂,並可能使所有工作副本無效。

不過,這個專案計畫未來實作 svnadmin obliterate 指令,用於永久刪除資訊。(請參閱 問題 516。)

在此同時,您唯一的方法是 svnadmin dump 儲存庫,然後將 dumpfile 透過 svndumpfilter(排除不良路徑)傳遞到 svnadmin load 指令。請參閱 Subversion 書籍的 第 5 章,以取得相關詳細資訊。

另一種方法是在設定 基於路徑的授權規則後,使用 svnsync 複製儲存庫,拒絕讀取存取權給任何需要從歷程記錄中篩選的路徑。與 svndumpfilter 不同,svnsync 會自動將來源路徑不可讀取的複製作業轉換為一般新增,如果需要篩選包含複製作業的歷程記錄,這會很有用。

如何變更已提交的版本記錄訊息?

記錄訊息會儲存在存放庫中,作為附加到每個版本的屬性。預設情況下,記錄訊息屬性 (svn:log) 一經提交即無法編輯。這是因為變更 版本屬性 (其中一個為 svn:log) 會導致屬性的前一個值永久丟棄,而 Subversion 會試圖防止您意外執行此操作。不過,有幾種方法可以讓 Subversion 變更版本屬性。

第一種方法是讓存放庫管理員啟用版本屬性修改。這是透過建立稱為「pre-revprop-change」的掛勾來完成的 (有關如何執行此操作的詳細資訊,請參閱 Subversion 書籍中的 此區段)。「pre-revprop-change」掛勾可以在變更前存取舊的記錄訊息,因此它可以透過某種方式保留訊息 (例如,透過傳送電子郵件)。一旦啟用版本屬性修改,您可以透過將 --revprop 開關傳遞給 svn propeditsvn propset 來變更版本的記錄訊息,如下列任一範例所示

$ svn propedit -r N --revprop svn:log URL
$ svn propset -r N --revprop svn:log "new log message" URL

其中 N 是您想變更其記錄訊息的版本號碼,而 URL 是存放庫的位置。如果您從工作副本中執行此命令,則可以省略 URL。

變更記錄訊息的第二種方法是使用 svnadmin setlog。這必須透過參照檔案系統中存放庫的位置來完成。您無法使用此命令修改遠端存放庫。

$ svnadmin setlog REPOS_PATH -r N FILE

其中 REPOS_PATH 是存放庫位置,N 是您想變更其記錄訊息的版本號碼,而 FILE 是包含新記錄訊息的檔案。如果「pre-revprop-change」掛勾未就緒 (或您想基於某種原因略過掛勾指令碼),您也可以使用 --bypass-hooks 選項。不過,如果您決定使用此選項,請務必小心。您可能會略過變更的電子郵件通知或追蹤版本屬性的備份系統等事項。

如何提交 Subversion 的程式碼補丁?

首先,請閱讀 Subversion 社群指南

在消化完指南後,請寄送一封郵件到開發人員清單,在主旨中加上 [PATCH] 字樣和一行描述,並將程式碼補丁內嵌在郵件中(除非您的郵件使用者代理程式會將其完全搞亂)。然後,提交者會接收您的郵件,套用程式碼補丁(進行必要的格式或內容變更),並將其簽入。

基本流程如下:

	$ svn co https://svn.apache.org/repos/asf/subversion/site subversion-site
	$ cd subversion-site/publish

		[ make changes to faq.html ]
	
	$ svn diff faq.html > /tmp/foo

	$ Mail -s "[PATCH] FAQ updates" < /tmp/foo

當然,您寄送的電子郵件應包含對程式碼補丁功能的詳細說明,如 Subversion 社群指南 所述,但您已經知道這一點,因為您在實際修改程式碼之前就已經閱讀並完全理解指南,對吧? :)

正在尋找事情做嗎?請查看我們的 構想頁面

如何進行原址「匯入」(例如,將樹狀結構新增到 Subversion 中,使原始資料直接成為工作副本)?

例如,假設您想要將 /etc 的部分內容置於儲存庫內的版本控制中

     # svn mkdir file:///root/svn-repository/etc \
         -m "Make a directory in the repository to correspond to /etc"
     # cd /etc
     # svn checkout file:///root/svn-repository/etc ./
     # svn add apache samba alsa X11 
     # svn commit -m "Initial version of my config files"

這利用了 svn checkout 一個不立即顯而易見的功能:您可以直接從儲存庫中簽出目錄到現有目錄。在此,我們首先在儲存庫中建立一個新的空目錄,然後將其簽出到 /etc,將 /etc 轉換為工作副本。完成後,您可以使用正常的 svn add 指令來選擇要新增到儲存庫的檔案和子樹。

如果要匯入目錄的全部內容,而不是內容的子集,可以使用較短的命令序列來執行匯入,然後將目錄轉換為 Subversion 工作副本

     # cd /etc
     # svn import file:///root/svn-repository/etc
     # svn checkout --force file:///root/svn-repository/etc .

已提交一個問題,以增強 svn import,使其能夠自動將匯入的樹狀結構轉換為工作副本;請參閱 問題 1328

升級 Subversion 伺服器時,人們有時會談論的「傾印/載入週期」是什麼?

在開發過程中,Subversion 的儲存庫資料庫架構偶爾會變更。若要利用新功能,您可能必須傾印並載入儲存庫,以重新建立後端資料庫。然而,大多數 Subversion 升級不會涉及傾印和載入。當需要時,新版本的發行說明和 CHANGES 檔案會載有關於它的顯著公告。如果您沒有看到此類公告,則表示沒有架構變更,也不需要傾印/載入。

傾印/載入的替代方法是使用 svnsync 將儲存庫複製到新的儲存庫中。這會稍微慢一些,但更靈活,並具有一些額外的正規化功能,而傾印/載入(目前)不具備這些功能(svnsync 會動態地將屬性正規化為 LF 行尾,並有一個 --source-prop-encoding 選項,可將它們轉換為 UTF-8,這在較新的儲存庫格式中是必需的 --- 請參閱下文,了解如何使用傾印/載入來處理此問題)。

注意:傾印/載入和 svnsync 都只涵蓋儲存庫資料庫,而不涵蓋儲存庫掛勾指令碼、組態檔案和鎖定。這些需要從來源手動複製到目標(請參閱下文中的「複雜程序」)。如果您需要複製完整的儲存庫,而不重新建置後端資料庫,svnadmin hotcopy 可能是更好的選擇。

對於負擔得起一些停機時間的小型儲存庫,這是一個從 Subversion 版本 X 升級到 Y 的簡單傾印/載入程序(請參閱下文,了解針對停機時間最少的較大型儲存庫的更複雜程序)

  1. 關閉 svnserve、Apache,以及任何可能正在存取儲存庫的程式。
  2. svnadmin dump /path/to/repository > dumpfile.txt ,使用 svnadmin 的 X 版。
  3. mv /path/to/repository /path/to/saved-old-repository
  4. 現在升級到 Subversion Y(即,建置並安裝 Y,取代 X)。
  5. svnadmin create /path/to/repository,使用 svnadmin 的 Y 版。
  6. svnadmin load /path/to/repository < dumpfile.txt ,再次使用 svnadmin 的 Y 版。
  7. 從舊儲存庫複製鉤子腳本等至新儲存庫。
  8. 重新啟動 svnserve、Apache 等。

對於較大的儲存庫,若要將維護時間縮到最短,可以使用稍為複雜的程序。訣竅是將資料傾印並載入至新位置,同時舊儲存庫仍可存取(用於簽出和提交)。完成後(可能需要數小時,甚至數天、數週),請記下已載入的最後版次(或使用「svnlook youngest newrepos」檢查版次號碼),然後開始另一個傾印並載入,其中使用「--incremental -rNEXTREV:HEAD」傾印(NEXTREV 是需要傾印的下一版次)。只要舊儲存庫保持開放,便可重複此步驟 ... 最後,讓原始儲存庫無法存取幾分鐘,同時啟用新儲存庫(注意事項:若將新儲存庫移至與舊儲存庫相同的磁碟位置,且使用 Apache httpd 提供服務,請務必重新啟動 httpd 以重設其快取)。

提示:對於大型儲存庫,我強烈建議在非常快速的儲存空間上建置新儲存庫(「svnadmin load」的目標),如果可能,甚至使用 ramdisk,並在快速儲存空間上執行「svnadmin pack」(然後複製至最終磁碟)。目前「svnadmin load」部分非常耗時(這在 svn 1.10 中可能會大幅改善,因為「svnadmin load」有 --no-flush-to-disk 選項)。

您的指令看起來會像以下

  1. svnadmin create NEWREPOS
    (或許在 ramdisk 上建立)
  2. 如果您在 OLDREPOS/hooks 中有自訂的 hook 程式碼 (所有不是以 .tmpl 結尾的檔案,因為那些是預設範本),請檢閱它們,並將它們複製到 NEWREPOS/hooks。檢查與您的自訂 hook 程式碼相對應的新範本,以查看是否有新的選項和註解 (您可能想要將較新的註解從範本複製到您的自訂 hook 程式碼中,以保持最新)。請確定在整個程序結束之前檔案不再變更 (或在最後進行額外的變更)。
  3. 檢閱並將設定檔從 OLDREPOS/conf 複製到 NEWREPOS/conf (在這裡,也要查看新的「預設設定檔」,以查看是否有新的有趣選項或註解)。請確定在整個程序結束之前檔案不再變更 (或在最後進行額外的變更)。
  4. svnadmin dump -M 1024 OLDREPOS | svnadmin load -M 1024 NEWREPOS
    (初始傾印+載入;您可能想要傳遞 -q 給 dump 和/或 load 以使其更安靜)
    ( -M 1024 給予程序 1024 MB 的額外 ram 用於快取)
  5. svnlook youngest NEWREPOS
    (已載入的最後版本 -> NEXTREV 是此最後版本 + 1)
  6. svnadmin dump --incremental -rNEXTREV:HEAD -M 1024 | svnadmin load -M 1024 NEWRPOS
  7. 使 OLDREPOS 為唯讀或完全不可用 <-- 維護視窗的開始
  8. 可能重複步驟 5 和 6 的增量傾印+載入 (如果您在開始 6 之後有新的提交)。
  9. 將鎖定從 OLDREPOS/db/locks 複製到 NEWREPOS/db/locks。類似 'cp -rp SOURCE TARGET' 的指令對此很有效。注意:此步驟在您的維護視窗中可能需要幾分鐘,具體取決於目錄樹的大小和磁碟的速度。如果您想要確定,請事先測試 (但請確保原始儲存庫在您進行最後複製/同步時為唯讀,否則鎖定可能會在您複製後變更)。
  10. 讓 NEWREPOS 上線 <-- 維護時段結束

一些需要注意的事項

  • 在開始初始傾印和載入後,並在鎖定舊儲存庫前,注意 日誌訊息的變更(或其他版本屬性)。這些不會透過增量傾印和載入傳輸。因此,在執行初始傾印和載入時,請確定 pre-revprop-change 勾選為「關閉」,或記錄所有已變更的版本屬性(例如,從 post-revprop-change 勾選寫入至日誌檔),並在之後傳輸至新儲存庫(例如,使用「svnlook log」和「svnadmin setlog」)。
  • 您可能會遇到
    svnadmin: E125005: Invalid property value found in dumpstream; consider repairing the
    source or using --bypass-prop-validation while loading.
    
    svnadmin: E125005: Cannot accept non-LF line endings in 'svn:log' property
    
    這表示版本中的 svn:log 訊息具有非 LF 行尾(舊伺服器接受這些,但 Subversion 1.6 之後不再接受)。您可以透過在「svnadmin load」指令中加入 --bypass-prop-validation 來忽略此輕微損毀(您隨時可以在新儲存庫中 修復 此問題)。或者,您可以在執行傾印和載入之前嘗試在原始儲存庫中 修復 此問題(由於 svn:log 是版本屬性,因此可以輕易修復,而不需「重寫歷史記錄」)。
  • 您可能會遇到
    svnadmin: E125005: Invalid property value found in dumpstream; consider repairing the
    source or using --bypass-prop-validation while loading.
    
    svnadmin: E125005: Cannot accept non-LF line endings in 'svn:ignore' property
    
    這比較難修復,因為「svn:ignore」並非修訂屬性(不像 svn:log,可以用 svnadmin setrevprop 處理),而是一個版本化屬性(因此是歷史的一部分)。同樣地,你可以用 --bypass-prop-validation 忽略它。但是,由於這是「歷史中的」損毀,因此只能用傾印加載來修復,所以這可能是嘗試修復的好時機(否則你以後還會再遇到這個問題)。你可以使用像 svndumptool 這樣的工具來修復。但它只能用於傾印檔案,不能用於管道的一部分。因此,一種可能的方法是:將那個單一的(損毀的)修訂傾印到一個檔案,修復它(「svndumptool.py eolfix-prop svn:ignore svn.dump svn.dump.repaired」),載入那個單一的傾印檔,然後使用一個新的「管道」命令繼續(就像上面的步驟 (6))。

請參閱 Subversion 手冊的這一部分,以瞭解傾印和載入的更多詳細資訊。

執行「svnadmin load」時,我該如何處理「svnadmin: E125005: 無法接受「svn:log」屬性中的非 LF 行尾」?

這個錯誤表示傾印檔 / 傾印串流中修訂的 svn:log 訊息有非 LF 行尾(舊伺服器接受這些行尾,但 Subversion 1.6 之後就不再接受了)。你可以透過在「svnadmin load」命令中加入 --bypass-prop-validation 來忽略載入到新儲存庫中的這個小損毀(你以後隨時可以在新儲存庫中修復它)。或者,你可以在執行傾印加載之前嘗試在原始儲存庫中修復它(因為 svn:log 是修訂屬性,所以可以輕鬆修復它,而不用「重寫歷史」)。另外請注意,svnsync 會動態正規化這個屬性,因此它可能比傾印加載更簡單。

沒有正規化 svn:log 屬性中行尾的標準程序,但可以使用管理命令「svnlook propget」、「svnlook log」和「svnadmin setlog」來完成。

  • svnlook propget -r$REV --revprop $REPOS svn:log 會取得原始的 svn:log 修訂屬性(沒有正規化,結尾沒有額外的換行符)。你可以用它來驗證它並搜尋「非 LF 行尾」。
  • svnlook log -r$REV $REPOS 會取得它的標準化版本(LF-eols,標準化為 UTF8(如果你的區域設定已設定正確的「來源編碼」),以及最後面多一個換行符號)。如果你移除最後一個換行符號,這會提供一個良好的標準化版本,可提供給日誌訊息...
  • svnadmin setlog -r$REV $REPOS --bypass-hooks(或是在你想要執行掛鉤時,不使用 --bypass-hooks 選項)會將它從 stdin 讀取的值設定為新的日誌訊息。

你可以將它們縫合到腳本中,以處理儲存庫中的所有版本,就像在這些 bash 一行指令中一樣

Find the "broken" revisions and echo the revision numbers:

bash$ YOUNGEST=`svnlook youngest $REPOS`; for (( i=1; i<=$YOUNGEST; i++ )); \
do svnlook propget -r $i --revprop $REPOS svn:log | xxd -ps -c1 | fgrep '0d' > /dev/null \
&& echo "$i" ; done; echo "Verified until revision $YOUNGEST"

Find and immediately fix the "broken" revisions with 'svnadmin setlog':

bash$ YOUNGEST=`svnlook youngest $REPOS`; for (( i=1; i<=$YOUNGEST; i++ )); \
do svnlook propget -r $i --revprop $REPOS svn:log | xxd -ps -c1 | fgrep '0d' > /dev/null \
&& echo "Fixing r$i" && svnadmin setlog $REPOS --bypass-hooks -r$i \
<( svnlook log -r$i $REPOS | sed '$d' ); done; echo "Verified until revision $YOUNGEST"

(the "sed '$d'" strips off the extra newline that's added by "svnlook log")

我該如何允許客戶端使用 SSPI 驗證對抗 Windows 網域控制器?

此常見問題解答條目自 2003 年起便未更新,且已知包含不再準確或相關的資訊。

TortoiseSVN 有一份說明如何在 Windows 上設定 Subversion 伺服器的優秀文件。前往 https://tortoisesvn.dev.org.tw/docs/release/TortoiseSVN_en/tsvn-serversetup.html#tsvn-serversetup-apache-5,查看有關 SSPI 驗證的區段。

設定中的一個重要部分是這行

   SSPIOfferBasic On

沒有這行,支援 SSPI 的瀏覽器會提示輸入使用者的憑證,但像 Subversion 這樣不支援 SSPI 的客戶端不會提示輸入。(Neon 的目前版本 - Subversion 的 HTTP 函式庫 - 只處理基本驗證。)由於客戶端從未要求輸入憑證,因此任何需要驗證的動作都會失敗。加入這行會告訴 mod_auth_sspi 使用基本驗證與客戶端,但使用 Windows 網域控制器來驗證憑證。

我不喜歡「.svn」目錄名稱,比較喜歡「SVN」或其他名稱。我該如何變更?

我們建議你盡可能使用「.svn」。不過,如果你在 Windows 上使用 Visual Studio 2002 或 2003,你可能需要設定環境變數 SVN_ASP_DOT_NET_HACK,如 此處 所述。

或者,您可以為管理目錄使用一個完全自訂的名稱。我們不建議這麼做,因為您的工作副本可能無法與您自訂的 Subversion 以外的其他用戶端一起使用。不過,如果您真的必須這麼做,只要將 subversion/include/svn_wc.h 中的這行從

#define SVN_WC_ADM_DIR_NAME   ".svn"

變更為(例如)

#define SVN_WC_ADM_DIR_NAME   "SVN"

然後重新編譯您的用戶端。

如何變更檔案名稱的大小寫?

這個問題會在兩種情況下發生。如果您在檔案系統不區分大小寫的操作系統(例如 Windows)上新增檔案,您可能會發現您不小心新增了一個檔案名稱大小寫錯誤的檔案。或者,您可能只是決定變更儲存庫中現有檔案的大小寫。

如果您使用的是區分大小寫的檔案系統,這完全不是問題。只要將檔案移至新名稱即可,例如,

svn mv file.java File.java

從 Subversion 1.7 開始,這也適用於 Windows,即使它使用的是不區分大小寫的檔案系統。

如果您在 Windows 上使用 Subversion 1.6 或更舊版本,或者您在 Windows 以外的操作系統上使用不區分大小寫的檔案系統,這個技術將無法使用。在這種情況下,您可以透過將檔案複製到某個暫時位置、從 Subversion 中刪除檔案,然後新增大小寫正確的副本來達成這個目的。或者,一個更好的方法是使用 Subversion URL 執行移動操作。建議使用 URL,因為它會保留檔案的歷程記錄,而且會立即生效。

不過,這兩種方法都會讓 Windows 工作副本出現問題,因為 Windows 在嘗試更新有衝突的文件名稱時仍然可能會混淆。(您會收到類似 svn: Failed to add file 'File.java': object of the same name already exists 的訊息)。解決問題的方法之一是刪除您的工作副本,然後再次簽出。如果您不想要這樣做,您必須執行兩步驟更新。

對於每個大小寫錯誤的文件,以下指令會變更大小寫

svn mv svn://svnserver/path/to/file.java svn://svnserver/path/to/File.java

若要更新工作副本,請變更至相關目錄並執行

svn update file.java
svn update

第一次更新會從您的工作副本中移除 file.java,第二次更新會加入 File.java,讓您擁有正確的工作副本。或者,如果您有許多有問題的文件,您可以用這種方式更新工作副本

svn update *
svn update

如您所見,在檔案系統不區分大小寫的操作系統中,加入大小寫錯誤的文件很難修正。請在第一次加入文件時就盡量正確!若要從一開始就避免問題發生,您可以建立一個呼叫文件 check-case-insensitive.pl 的提交前掛勾。該文件位於 Subversion 原始碼 tarball 中的目錄 contrib/hook-scripts

我無法使用標籤將變更從分支合併到主幹,就像我以前使用 CVS 那樣,對嗎?

如下所示,可以在不記住一個修訂編號的情況下,從分支合併到主幹。或反之亦然(範例中未顯示)。

以下範例假設在 /home/repos 中有一個現有的儲存庫,您想要在其中啟動一個名為 bar 的分支,其中包含一個您將編輯的名為 foo 的文件。

為了追蹤分支合併,此儲存庫已設定 tags/branch_traces/ 來保留標籤。

# setup branch and tags
$ svn copy file:///home/repos/trunk \
           file:///home/repos/branches/bar_branch \
           -m "start of bar branch"
$ svn copy file:///home/repos/branches/bar_branch \
           file:///home/repos/tags/branch_traces/bar_last_merge \
           -m "start"

# checkout branch working copy
$ svn checkout file:///home/repos/branches/bar_branch wc
$ cd wc

# edit foo.txt file and commit
$ echo "some text" >>foo.txt
$ svn commit -m "edited foo"

# switch to trunk and merge changes from branch
$ svn switch file:///home/repos/trunk
$ svn merge file:///home/repos/tags/branch_traces/bar_last_merge \
            file:///home/repos/branches/bar_branch

# Now check the file content of 'foo.txt', it should contain the changes.

# commit the merge
$ svn commit -m "Merge change X from bar_branch."

# finally, update the trace branch to reflect the new state of things
$ svn delete -m "Remove old trace branch in preparation for refresh." \
             file:///home/repos/tags/branch_traces/bar_last_merge
$ svn copy file:///home/repos/branches/bar_branch                     \
           file:///home/repos/tags/branch_traces/bar_last_merge       \
           -m "Reflect merge of change X."

$Revision$ 關鍵字為何無法執行我想要的操作?它會擴充為檔案最後變更的版本,但我想要的是擴充為檔案目前的版本。

Subversion 會遞增整個儲存庫的版本號碼,因此它無法將任何關鍵字擴充為該號碼 - 它必須在每次更新和提交時搜尋並修改工作副本中的每個檔案。

您要的資訊(工作副本的版本)可透過命令 svnversion 取得;它會提供給您工作副本版本層級的資訊(請參閱 svnversion --help 以取得詳細資料)。

您可以將它納入您的建置或發行程序,以取得您需要的資訊並放入來源本身。例如,在基於 GNU make 的建置環境中,將 類似這樣的內容 加入您的 Makefile

##
## To use this, in yourfile.c do something like this:
## printf("this program was compiled from SVN revision %s\n",SVN_REV);
##

SVNDEF := -D'SVN_REV="$(shell svnversion -n .)"'
CFLAGS := $(SVNDEF) ... continue with your other flags ...

(請注意,這在非 GNU 版本的 make 中無法運作。如果您的建置程序需要可攜式,請勿使用它。)

或嘗試此配方

##
## on every build, record the working copy revision string
##
svn_version.c: FORCE
    echo -n 'const char* svn_version(void) { const char* SVN_Version = "' \
                                       > svn_version.c
    svnversion -n .                   >> svn_version.c
    echo '"; return SVN_Version; }'   >> svn_version.c

##
## Then any executable that links in svn_version.o will be able
## to call the function svn_version() to get a string that
## describes exactly what revision was built.
##

Windows 使用者可能想要使用 SubWCRev.exe,可從 TortoiseSVN 下載頁面 取得;它會將給定檔案中的所有 $WCREV$ 標籤替換為目前的工作副本版本。

另一種替代方案是為 'svn commit' 建立一個包裝器,它會在提交前自動替換檔案中的內容(但請小心不要搞亂檔案 - 在提交前靜默地處理檔案對使用者來說可能會很可怕)。這樣您就可以注入您要的任何元資料(而且它會與檔案的常規內容一起提交到儲存庫中)。

Subversion 是否有像 CVS 中 $Log$ 那樣運作的關鍵字?

沒有。CVS 中的 $Log$ 關鍵字沒有等效項。如果您想要擷取特定檔案的記錄,您可以執行 'svn log your-file-name' 或 'svn log url-to-your-file'。從郵件清單中說明了為何 $Log$ 不好的原因

"$Log$ is a total horror the moment you start merging changes
between branches. You're practically guaranteed to get conflicts there,
which -- because of the nature of this keyword -- simply cannot be
resolved automatically."

而且

Subversion log messages are mutable, they can be changed by setting
the svn:log revision property. So the expansion of $Log:$ in any
given file could be out of date. Update may well need to retrieve the
appropriate log message for each occurrence of the $Log:$ keyword,
even if the file that contained it was not otherwise updated.

我不在乎。無論如何,我都想使用它。你會實作它嗎?

不會。我們沒有計畫自行實作或接受實作此功能的修補程式。如果你想散布包含某種變更日誌的檔案,你或許可以在你的建置系統中解決此限制。

我的專案中有一個檔案,每個開發人員都必須變更,但我不想提交這些本機模組。我如何讓「svn commit」忽略該檔案?

答案是:不要將該檔案置於版本控制之下。相反地,將該檔案的範本置於版本控制之下,例如「file.tmpl」。

然後,在初始「svn checkout」之後,讓你的使用者(或你的建置系統)將範本的正常 OS 複製到正確的檔名,並讓使用者自訂複製。該檔案未經過版本控制,因此永遠不會提交。如果你願意,你可以將該檔案新增至其父目錄的 svn:ignore 屬性,這樣它就不會在「svn status」指令中顯示為「?」。

當我使用 svn+ssh 存取儲存庫時,我的密碼不會快取在 ~/.subversion/auth/ 中。我如何避免這麼常輸入密碼?

ssh 有自己的密碼和自己的驗證快取機制。它的驗證快取是 Subversion 的外部,而且必須獨立於 Subversion 設定。

OpenSSH 包含 ssh-keygen 以建立金鑰、ssh-agent 以快取密碼,以及 ssh-add 以將密碼新增至代理快取。一個簡化 ssh-agent 使用的熱門指令碼是 keychain。在 Windows 上,PuTTY 是熱門的替代 ssh 客戶端;請參閱 PuTTYgen 以匯入 OpenSSH 金鑰,以及 pageant 以快取密碼。

設定 ssh-agent 超出本文檔的範圍,但 Google 搜尋「ssh-agent」 將會快速提供您答案。

我的 svnserve 二進制檔案位於不在使用者預設 PATH 中的目錄,他們使用 svn+ssh,而且我無法找出如何修改他們的 PATH 以便他們可以執行 svnserve

注意:這一切假設您使用的是 OpenSSH。還有其他 ssh 實作,而且假設它們會允許您執行類似的事情,但我們目前還不知道詳細資訊。

您已嘗試修改他們的各種登入檔案,例如 .bash_profile,但都沒有用!這是因為當 Subversion 呼叫它時,ssh 會忽略這些檔案。但不需要修改 PATH;相反地,您可以直接提供 ssh svnserve 命令的全名。以下是如何執行

對於需要 svn+ssh 存取權的每個使用者,產生一組新的 ssh 公開金鑰對,他們將用於 Subversion,而不是用於一般登入。請他們為金鑰對取一個有特色的名稱,例如 ~/.ssh/id_dsa.subversion。將金鑰的公開部分新增到伺服器電腦上的 ~/.ssh/authorized_keys 檔案,首先在 ssh-rsassh-dss 字詞前的行開頭插入一點魔法,如下所示

之前
ssh-dss AAAAB3Nblahblahblahblah
之後
command="/opt/subversion/bin/svnserve -t" ssh-dss AAAAB3Nblahblahblahblah

顯然地,將 /opt/subversion/bin/svnserve 替換為適合您系統的任何內容。您可能還想在命令中指定 Subversion 儲存庫的完整路徑(透過使用 -r 選項),以節省您的使用者一些輸入。

即使您的使用者嘗試執行其他指令,command= 魔術會導致遠端機器上的 sshd 呼叫 svnserve。請參閱 sshd(8) 手冊頁(AUTHORIZED_KEYS 檔案格式 章節)以取得詳細資料。

現在,當您的使用者執行 Subversion 伺服器時,請確定他們有一個 SVN_SSH 環境變數,該變數「指向」其金鑰對的私密部分,方法如下(適用於 Bourne Again shell):

SVN_SSH="ssh -i $HOME/.ssh/id_dsa.subversion"
export SVN_SSH

此檔案 更詳細地討論此主題。

我想允許透過 svn+ssh:// 存取,但我很偏執。我討厭讓每個使用者登入的想法;我必須擔心他們在我的機器上可以存取什麼以及不能存取什麼。

請參閱 此其他問題 的解答中關於破解 ~/.ssh/authorized_keys 檔案的區段;忽略關於在 PATH 中取得 svnserve 的內容。

我如何在儲存庫中的所有項目上設定特定屬性?此外,我如何確保進入儲存庫的每個新檔案都有這些屬性?

Subversion 預設不會變更檔案內容;您必須刻意設定檔案上的 svn:eol-stylesvn:keywords 屬性才能執行此動作。這使得 Subversion 比 CVS 的預設行為安全許多,但此安全性帶來了一些不便。

回答第一個問題:若要設定儲存庫中所有檔案的屬性,您需要用困難的方式執行。您能做的就是對每個檔案(在工作副本中)執行 svn propset,然後 svn commit。指令碼可能會對您有所幫助。

但未來的檔案呢?很遺憾地,伺服器機制無法自動設定提交檔案的屬性。這表示所有使用者在執行 svn add 加入檔案時,都必須記得設定特定屬性。很幸運地,有一個用戶端工具可以協助處理這項工作。請參閱書中的 auto-props 功能。您需要確定所有使用者都適當地設定其用戶端 auto-props 設定。

您可以撰寫一個提交前掛勾指令碼,以拒絕任何忘記新增屬性至新檔案的提交(例如,請參閱 https://svn.apache.org/repos/asf/subversion/trunk/contrib/hook-scripts/check-mime-type.pl)。不過,這種方法可能會過於繁瑣。例如,如果有人忘記設定 svn:eol-style,那麼當其他人使用不同的作業系統開啟檔案時,就會立即發現。一旦發現,很容易就能修正:只要設定屬性並提交即可。

注意:許多使用者要求提供一個功能,讓伺服器自動「廣播」執行時間設定至用戶端,例如 auto-props 設定。已經有人針對此功能提出功能要求(問題 1974),不過開發人員仍在討論此功能,尚未開始進行。

我該如何處理編輯器路徑中的空白?此外,我該如何為編輯器定義命令列選項?

Subversion 命令列用戶端會呼叫環境變數 SVN_EDITOR 中定義的編輯器。這個環境變數會連同用於輸入/編輯記錄訊息的暫時檔案名稱,直接傳遞至作業系統。

由於 SVN_EDITOR 字串會原樣傳遞至系統的命令殼層,因此編輯器名稱或編輯器路徑名稱中的空白,除非編輯器名稱加上引號,否則無法使用。

例如,如果 Windows 中的編輯器位於 C:\Program Files\Posix Tools\bin\vi,您會希望將變數設定如下

   set SVN_EDITOR="C:\Program Files\Posix Tools\bin\vi"

請注意,Windows shell 中不需要跳脫引號,因為它們並非 set 指令的語法的一部分。

在 UNIX 系統中,您需要遵循 shell 的特定方法來設定變數。例如,在 bash shell 中,下列指令應可運作

   SVN_EDITOR='"/usr/local/more editors/bin/xemacs"'
   export SVN_EDITOR

如果編輯器的呼叫需要命令列選項,請在 SVN_EDITOR 環境變數中的編輯器名稱後面加上該選項,就像您在命令列中使用的方式一樣。例如,如果上述編輯器需要選項 -nx -r,下列指令將提供這些選項

適用於 Windows

   set SVN_EDITOR="C:\Program Files\Posix Tools\bin\vi" -nx -r

適用於 UNIX/bash

   SVN_EDITOR='"/usr/local/more editors/bin/xemacs" -nx -r'
   export SVN_EDITOR

請注意,SVN_EDITOR 是 Subversion 特有的環境變數設定,用於編輯器選取。Subversion 也支援使用更通用的 EDITOR 變數,但如果您需要 Subversion 的特殊行為,最好使用 SVN_EDITOR 變數。

我在存放庫中管理一個網站。如何讓實時網站每次提交後自動更新?

這項工作一直都在進行,而且只要在您的存放庫中新增提交後掛鉤指令碼,就能輕鬆達成。在本書的 第 5 章 中閱讀有關掛鉤指令碼的資訊。基本概念是讓「實時網站」只是一個普通的作業副本,然後讓您的提交後掛鉤指令碼在其中執行「svn update」。

實際上,有幾件事需要注意。執行提交的伺服器程式 (svnserve 或 apache) 與執行提交後掛鉤指令碼的程式相同。這表示此程式必須具有適當的權限才能更新作業副本。換句話說,作業副本必須由與 svnserve 或 apache 相同的使用者擁有 - 或至少作業副本必須設定適當的權限。

如果伺服器需要更新它不擁有的工作副本(例如,使用者 joe 的 ~/public_html/ 區域),一種方法是建立一個 +s 二進位程式來執行更新,因為 Unix 不允許指令碼執行 +s。編譯一個微小的 C 程式

#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
  execl("/usr/local/bin/svn", "svn", "update", "/home/joe/public_html/",
        (const char *) NULL);
  return(EXIT_FAILURE);
}

... 然後 chmod +s 二進位程式,並確保它由使用者 'joe' 擁有。然後在提交後掛鉤中,新增一行來執行二進位程式。

如果您在讓掛鉤運作時遇到問題,請參閱 "我的儲存庫掛鉤為何無法運作?"

此外,您可能希望防止 apache 匯出實際工作副本中的 .svn/ 目錄。將此新增至您的 httpd.conf

# Disallow browsing of Subversion working copy administrative dirs.
<DirectoryMatch "^/.*/\.svn/">
    Order deny,allow
    Deny from all
</DirectoryMatch>

最後,如果要更新的工作副本與 Subversion 伺服器不在同一台機器上,svnpubsub 可用於 Subversion 伺服器,以向 Web 伺服器上的監聽 svnwcsub 客戶端宣告提交。

我如何檢出單一檔案?

Subversion 不支援檢出單一檔案,它只支援檢出目錄結構。

但是,您可以使用 'svn export' 來匯出單一檔案。這將擷取檔案的內容,它只是不會建立版本化的工作副本。

在工作副本中,我如何偵測在它們已經發生後的新增、刪除、複製和重新命名?

您無法。嘗試這樣做是個壞主意。

工作副本的基本設計有兩個規則:(1) 隨意編輯檔案,以及 (2) 使用 Subversion 客戶端進行任何樹狀結構變更(新增、刪除、移動、複製)。如果遵循這些規則,客戶端可以成功管理工作副本。如果在 Subversion 外部發生重新命名或其他重新排列,則表示已違反使用者介面,而工作副本可能會損毀。客戶端無法猜測發生了什麼事。

人們有時會遇到這個問題,因為他們想要讓版本控制「透明化」。他們誘騙使用者使用工作副本,然後執行一個腳本,試著猜測發生了什麼事,並執行適當的客戶端指令。不幸的是,這個技術只能走一小段距離。'svn status' 會顯示遺失的項目和未版本化的項目,腳本接著可以自動執行 'svn rm' 或 'svn add'。但是如果發生了移動或複製,你就倒楣了。即使腳本有萬無一失的方法來偵測這些事情,'svn mv' 和 'svn cp' 也無法在動作發生後執行。

總之:工作副本完全在 Subversion 的控制之下,而 Subversion 並非設計成透明的。如果你正在尋找透明化,請嘗試設定一個 apache 伺服器,並使用本書附錄 C 中所述的「SVNAutoversioning」功能。這將允許使用者將儲存庫掛載為網路磁碟,對磁碟區所做的任何變更都會導致伺服器上自動提交。

我如何在 Windows 上以服務方式執行 svnserve?

對於 1.4.0 和更新的版本,你可以在此找到說明。

我如何將我的儲存庫從使用 BDB 轉換為 FSFS,或從 FSFS 轉換為 BDB?

有三個步驟

  1. 從舊格式傾印/載入到新格式。
  2. 複製掛勾腳本。
  3. 複製組態檔。

假設你有一個儲存庫 /svn/myrepos,它使用 BDB 後端,而你想要切換到使用 FSFS 後端

  1. 關閉你的伺服器,以便資料在這個程序期間不會變更。
  2. 建立一個新的儲存庫,指定 fsfs 後端(從 1.2 版開始為預設),例如,svnadmin create /svn/myreposfsfs --fs-type fsfs
  3. /svn/myrepos 中的傾印輸出導向到 /svn/myreposfsfs 中載入的輸入,例如,svnadmin dump /svn/myrepos -q | svnadmin load /svn/myreposfsfs。Windows 使用者應將傾印導向到一個檔案,並在兩個不同的步驟中從該檔案載入。
  4. /svn/myrepos/hooks 中所有作用中的掛鉤指令碼複製到 /svn/myreposfsfs/hooks 中。不要不假思索地複製所有內容,Subversion 所產生的範本可能已經變更。
  5. svnadmin create 指令放在 /svn/myreposfsfs/hooks 中的範本指令碼與 /svn/myrepos/hooks 中的範本指令碼進行比較,並將您想要納入作用中掛鉤指令碼的任何變更納入其中。
  6. 將組態檔從 /svn/myrepos/conf 複製到 /svn/myreposfsfs/conf 中(如果您使用密碼檔,請不要忘記它)。或者,您可能想要將您對組態檔所做的變更合併到新的預設組態檔中。
  7. /svn/myrepos 重新命名為 /svn/myreposbdb,然後將 /svn/myreposfsfs 重新命名為 /svn/myrepos,確保檔案權限與 BDB 版本的相同。
  8. 重新啟動伺服器。

一旦您對新的儲存庫感到滿意,請刪除舊的儲存庫。

若要執行相反的動作,並從 FSFS 遷移到 BDB,請變更 svnadmin create 指令以指定 BDB。

Subversion 如何處理二進位檔案?

當您第一次將檔案新增或匯入到 Subversion 中時,系統會檢查檔案以確定它是否為二進位檔案。目前,Subversion 只會檢視檔案的前 1024 個位元組;如果任何一個位元組為零,或者超過 15% 不是 ASCII 可列印字元,則 Subversion 會將檔案稱為二進位檔案。

如果 Subversion 判斷檔案是二進位,檔案會收到一個 svn:mime-type 屬性,設定為「application/octet-stream」。(您隨時可以使用 自動屬性功能 或使用 svn propset 手動設定屬性來覆寫此設定。)

Subversion 1.7 和更新版本可以選擇編譯,支援 libmagic,以偵測加入版本控制的二進位檔案的 MIME 類型。此功能僅用於未透過自動屬性或 mime-types-file 組態選項找到 MIME 類型的二進位檔案。如果 libmagic 識別檔案為文字檔案,Subversion 預設會將檔案視為文字檔案。

Subversion 將下列檔案視為文字

  • 沒有 svn:mime-type 的檔案
  • svn:mime-type 開頭為「text/」的檔案
  • svn:mime-type 等於「image/x-xbitmap」的檔案
  • svn:mime-type 等於「image/x-xpixmap」的檔案

所有其他檔案都視為二進位,表示 Subversion 會

  • svn updatesvn merge 期間,不會嘗試將接收到的變更與本機變更自動合併
  • 不會將差異顯示為 svn diff 的一部分
  • 不會為 svn blame 顯示逐行註解

在其他所有方面,Subversion 將二進位檔案視為與文字檔案相同,例如,如果您設定 svn:keywords 或 svn:eol-style 屬性,Subversion 會對二進位檔案執行關鍵字替換或換行符號轉換。

請注意,檔案是否為二進位檔案不會影響用於儲存檔案變更的儲存庫空間量,也不會影響用戶端和伺服器之間的流量量。對於儲存和傳輸目的,Subversion 使用在二進位檔案和文字檔案上都能正常運作的差異化方法;這與「svn diff」指令使用的差異化方法完全無關。

如何讓 svn diff 僅向我顯示已變更檔案的名稱,而不是其內容?

svn diff 沒有選項可以執行此操作,但

  • 如果您只對差異感興趣,例如第 10 版與其前一版之間的差異,
    svn log -vq -r10
    就能完全符合您的需求;
  • 否則,如果您使用 Unix,這適用於任何版本的範圍
        svn log -vq -r123:456 | egrep '^ {3}[ADMR] ' | cut -c6- | sort | uniq 
svn diff 命令的 1.4 版將有「--summarize」選項。

如何使用萬用字元或 glob 一次移動多個檔案?

您想執行類似下列動作

svn mv svn://server/trunk/stuff/* svn://server/trunk/some-other-dir

但會失敗,並顯示

svn: Path 'svn://server/trunk/stuff/*' does not exist in revision 123

... 或其他難以理解的錯誤訊息。

Subversion 沒有擴充 URL 引數中的萬用字元,例如「*」。 (技術上來說,Subversion 也不會擴充本地路徑中的萬用字元,但在大多數作業系統中,shell 會在將產生的清單傳遞給 Subversion 之前,先擴充命令列中本地路徑中的萬用字元。)

您必須自行產生來源 URL 清單。您可以使用下列方式(在 Bash 中)執行此動作

        s=svn://server/trunk/stuff
        items=$(svn ls "$s")
        urls=$(for item in $items; do echo $s/$item; done)
        svn mv $urls svn://server/trunk/some-other-dir -m "Moved all at once"

在 Subversion v1.4 及更早版本中,Subversion 不允許您在一個命令中「cp」和「mv」多個路徑或 URL。您必須發出多個命令。如果您碰巧有一個工作副本,其中包含所有來源檔案以及目標目錄,則可以利用 shell 的萬用字元功能執行移動,如下所示(針對 Bash)

        for i in stuff/*; do svn mv $i some-other-dir; done
        svn ci -m "moved all the stuff into some other dir"

在任何情況下,您都可以隨時累積來源檔案名稱的清單,然後對清單中的每個項目執行「svn mv」,如下所示

        s=svn://server/trunk/stuff
        svn ls "$s"  | \
        while read f
           do svn mv "$s/$f" svn://server/trunk/some-other-dir -m "Moved just one file"
        done

不過請注意,這會為每個來源檔案產生一個提交;這與上述方法(使用工作副本)形成對比,後者只會產生一個提交總計。

有一個稱為「svnmucc」(以前稱為「mucc」)的程式,其來源與 Subversion 一起發行,讓您可以將多個命令合併為一個提交。請參閱工具和貢獻頁面

如何使用 Subversion 維護協力廠商軟體的修改版本(「供應商分支」)?

人們經常想使用 Subversion 追蹤他們對第三方程式碼的本地變更,即使跨越第三方升級,也就是說,他們想維護自己的分歧分支,同時仍然納入上游來源的新版本。這通常稱為供應商分支(此術語早於 Subversion),而維護 Subversion 中一個分支的技術在此處說明

如果供應商程式碼是託管在遠端 Subversion 儲存庫中,則您可以使用 Piston 來管理您的供應商程式碼副本。

如何讓先前版本中的內容再次成為 HEAD?

使用「svn merge」或「svn copy」,如 Subversion 書籍中所述

疑難排解:

每次我嘗試執行 svn 命令時,它都會說我的工作副本被鎖定。我的工作副本是否已毀損?

您的工作副本並未毀損,您的資料也未遺失。Subversion 的工作副本是一個記錄系統,表示它會在執行任何動作之前記錄所有即將執行的動作。如果 svn 客戶端程式突然中斷(分段錯誤或終止,而不是使用 Control-C),則會留下一個或多個鎖定檔,以及描述未完成工作的記錄檔。(「svn status」命令會在鎖定的目錄旁邊顯示「L」。)任何嘗試存取工作副本的其他程序,在看到鎖定時都會失敗。若要喚醒您的工作副本,您需要告訴 svn 客戶端完成工作。只需執行

svn cleanup working-copy

我試著提交,但 Subversion 顯示我的工作副本已過時?

會造成此問題的三種情況

  1. 失敗提交的殘留檔案散落在您的工作副本中。

    您可能在伺服器新增新版次和您的用戶端執行提交後管理工作(包括更新您的文字基礎副本)之間,發生提交失敗的情況。這可能會因為各種原因發生,包括(很少見)資料庫後端的錯誤或(較常見)在不恰當的時間發生網路中斷。

    如果發生這種情況,您可能已經提交了您現在嘗試提交的變更。您可以使用「svn log -rHEAD」查看您假設失敗的提交是否實際上成功。如果成功了,請執行「svn revert」回復您的本機變更,然後執行「svn update」從伺服器取回您自己的變更。(請注意,只有「svn update」會將您的本機副本更新為最新;回復不會執行此動作。)

  2. 混合版次。

    當 Subversion 提交時,用戶端只會變更提交觸及的節點的版次號碼,而不是工作副本中的所有節點。這表示在單一工作副本中,檔案和子目錄的版次可能不同,這取決於您上次提交它們的時間。在某些作業中(例如目錄屬性修改),如果儲存庫有較新版本的節點,提交將會被拒絕,以防止資料遺失。請參閱 混合版次有其限制 中的 使用 Subversion 進行版本控制 一書,以取得詳細資訊。

    您可以透過在工作副本中執行「svn update」來修正此問題。

  3. 您可能真正過時了 — 也就是說,您嘗試提交變更到一個檔案,而自從您上次更新該檔案的副本後,該檔案已被其他人變更。同樣地,「svn update」是修正此問題的方法。

我已為專案貢獻一個修補程式,而該修補程式新增了一個新檔案。現在 svn update 無法運作。

為了將你的新檔案包含在修補程式中,你可能執行 svn add 指令,以便 svn diff 指令將新檔案包含在修補程式中。如果你的修補程式提交至程式碼庫,而你執行 svn update,則你可能會收到錯誤訊息:「svn:無法新增檔案 'my.new.file':同名物件已存在」。

你收到此錯誤訊息的原因是你的工作副本中仍有檔案的本機副本。修正此問題的步驟為:

  1. 執行 svn revert 指令,以移除 Subversion 中已排程的加入。
  2. 刪除檔案或將其移至工作副本以外的位置。
  3. 現在你應該能夠執行 svn update 指令。

你可能想要將儲存庫中的新檔案與你的原始檔案進行比較。

我剛建置發行版二進位檔,當我嘗試檢出 Subversion 時,我收到關於「無法辨識的 URL 架構」的錯誤。這是怎麼回事?

Subversion 使用外掛程式系統允許存取儲存庫。目前有三個此類外掛程式:ra_local 允許存取本機儲存庫,ra_neon 或 ra_serf 允許透過 WebDAV 存取儲存庫,而 ra_svn 允許透過 svnserve 伺服器進行本機或遠端存取。當你嘗試在 Subversion 中執行作業時,程式會根據 URL 架構嘗試動態載入外掛程式。`file://' URL 會嘗試載入 ra_local,而 `http://' URL 會嘗試載入 ra_neon 或 ra_serf。

您看到的錯誤表示動態連結器/載入器找不到要載入的插件。對於 `http://' 存取,這通常表示您在編譯 Subversion 時未將其連結到 neon 或 serf(請查看組態指令碼輸出和 config.log 檔案以取得相關資訊)。當您使用共用函式庫建置 Subversion,然後嘗試在未先執行「make install」的情況下執行 Subversion 時,也會發生這種情況。另一個可能的原因是您執行了 make install,但函式庫安裝在動態連結器/載入器無法辨識的位置。在 Linux 中,您可以透過將函式庫目錄新增至 /etc/ld.so.conf 並執行 ldconfig,讓連結器/載入器找到函式庫。如果您不希望執行此動作,或者您沒有 root 存取權,您也可以在 LD_LIBRARY_PATH 環境變數中指定函式庫目錄。

我在尋找或開啟儲存庫時遇到錯誤,但我確定我的儲存庫 URL 正確。出了什麼問題?

請參閱 此常見問題集。

當我執行 `configure' 時,我收到有關 subs-1.sed line 38: Unterminated `s' command 的錯誤。出了什麼問題?

您的系統中可能還有 /usr/local/bin/apr-config/usr/local/bin/apu-config 的舊副本。請將它們移除,確認您建置的 apr/apr-util/ 已完全更新,然後再試一次。

我在使用 MSVC++ 6.0 在 Windows 中建置 Subversion 時遇到問題。我該怎麼辦?

您可能只需要取得最新的平台 SDK。隨附 VC++ 6.0 的 SDK 不夠新。

如何在 file: URL 中指定 Windows 磁碟機代號?

像這樣

svn import file:///d:/some/path/to/repos/on/d/drive

請參閱 Subversion Repository URLs 以取得更多詳細資訊。

Microsoft Visual Studio 2002 和 2003 似乎對「.svn」目錄名稱有問題。我該怎麼辦?

Visual Studio 可以使用 ASP.Net 的 Web 子系統,它使用 FrontPage 伺服器延伸模組透過 IIS 進行遠端發佈。這個子系統會拒絕任何以「.」開頭的路徑名稱。這會造成問題,因為當您嘗試遠端發佈 Subversion 工作副本時,會出現「.svn」子目錄。錯誤訊息會顯示類似「無法讀取專案資訊」的內容。

若要解決這個問題,請將環境變數 SVN_ASP_DOT_NET_HACK 設為任何值,這會指示 Windows 用戶端在您的工作副本中使用「_svn」作為目錄名稱。請參閱 Subversion 1.3 發行說明中的相關區段 以取得更多詳細資訊,並參閱 這個問題 以取得自訂管理目錄名稱的其他方法。

我在透過網路對 Subversion 儲存庫進行寫入作業時遇到問題。

例如,一位使用者回報說匯入在本地端存取時運作良好

  $ mkdir test
  $ touch test/testfile
  $ svn import test file:///var/svn/test -m "Initial import"
  Adding         test/testfile
  Transmitting file data .
  Committed revision 1.
但從遠端主機則不行
  $ svn import http://svn.sabi.net/test testfile -m "import"
  nicholas's password: xxxxxxx

  svn_error: #21110 : <Activity not found>

  The specified activity does not exist.

當 REPOS/dav/ 目錄無法由 httpd 程序寫入時,我們看過這個問題。請檢查權限以確保 Apache 可以寫入 dav/ 目錄(當然還有 db/)。

在 Subversion 用戶端和伺服器之間的對話中,執行網路追蹤的最佳方法是什麼?

請參閱 /docs/community-guide/debugging.html#net-trace

為什麼 svn revert 需要明確的目標?為什麼它預設不是遞迴的?這些行為與幾乎所有其他子指令都不同。

簡短的回答:這是為了您自己好。

Subversion 非常重視保護您的資料,而不仅仅是您的版本化資料。您對已版本化檔案所做的修改,以及排定新增至版本控制系統的新檔案,都必須小心處理。

svn revert 指令需要明確的目標,即使該目標只是「.」—這是達成此目的的方法之一。此需求(以及要求您提供 --recursive (-R) 旗標,如果您想要該行為)的用意是讓您真正思考您正在做的事,因為一旦您的檔案還原,您的本地修改將永遠消失。

為什麼 SVN 記錄會對透過 Apache (ra_dav) 提交或匯入的檔案顯示「(無作者)」?

如果您允許透過 Apache 匿名寫入存儲庫,Apache 伺服器絕不會向 SVN 客戶端索取使用者名稱,而是允許在未驗證的情況下執行寫入操作。由於 Subversion 不知道是誰執行操作,因此會產生類似這樣的記錄

$ svn log
------------------------------------------------------------------------
rev 24:  (no author) | 2003-07-29 19:28:35 +0200 (Tue, 29 Jul 2003)

請參閱 Subversion 書籍,以了解如何在 Apache 中設定存取限制。

我在 Windows 上偶爾會收到「存取遭到拒絕」的錯誤。它們似乎是隨機發生的。為什麼?

這些錯誤似乎是由於各種監視檔案系統變更的 Windows 服務(防毒軟體、索引服務、COM+ 事件通知服務)所造成。這並非 Subversion 中的錯誤,因此我們很難修復它。調查的目前狀態摘要可在此處取得 這裡。一個應可為大多數人降低發生率的解決方法已在版本 7598 中實作;如果您有較早的版本,請更新至最新版本。

在 FreeBSD 上,某些操作(特別是 svnadmin create)有時會當機。為什麼?

這通常是因為系統上缺乏可用的熵。您可能需要設定系統從硬碟和網路中斷等來源收集熵。請參閱您的系統手冊頁,特別是 random(4) 和 rndcontrol(8),了解如何進行此變更。

我可以在 Web 瀏覽器中看到我的儲存庫,但「svn checkout」會給我一個關於「301 永久搬移」的錯誤。出了什麼問題?

這表示您的 httpd.conf 設定錯誤。通常,當您定義 Subversion 虛擬「位置」時,同時存在於兩個不同的範圍內,就會發生此錯誤。

例如,如果您已將儲存庫匯出為 <Location /www/foo>,但您也將 DocumentRoot 設定為 /www,那麼您就有麻煩了。當請求進入 /www/foo/bar 時,apache 不知道是否要在 DocumentRoot 中找到名為 /foo/bar實際檔案,或要求 mod_dav_svn 從 /www/foo 儲存庫中擷取檔案 /bar。通常前者會獲勝,因此會出現「永久搬移」錯誤。

解決方案是確保您的儲存庫 <Location> 不會 重疊或存在於已作為一般 Web 共享匯出的任何區域內。

您在 Web 根目錄中有一個物件與您的儲存庫 URL 同名,這也是可能的。例如,假設您的 Web 伺服器的文件根目錄是 /var/www,而您的 Subversion 儲存庫位於 /home/svn/repo。然後,您將 Apache 設定為在 https://127.0.0.1/myrepo 提供儲存庫服務。如果您接著建立目錄 /var/www/myrepo/,這將導致發生 301 錯誤。

在 AIX 上使用 xlc 編譯時,我得到編譯錯誤。出了什麼問題?

在設定和建置的環境變數 CFLAGS 中加入 -qlanglvl=extended,將使 xlc 更具彈性,而且程式碼應可編譯而不會出錯。請參閱 https://svn.haxx.se/dev/archive-2004-01/0922.shtml 及其相關執行緒,以取得更多詳細資料。

我非遞迴地檢出一個目錄(使用 -N),現在我想讓某些子目錄「出現」。但 svn up subdir 不起作用。

請參閱 問題 695svn checkout -N 的目前實作相當不穩定。它會產生一個工作副本,其中缺少項目,卻不了解其「不完整」。顯然,許多 CVS 使用者相當依賴此範例,但沒有任何 Subversion 開發人員會這麼做。目前,除了變更您的流程之外,並沒有任何解決方法:嘗試檢出儲存庫的個別子目錄,並手動嵌套您的工作副本。

我嘗試在 Win32 上使用 Apache 的 mod_dav_svn,但出現一個錯誤,表示找不到模組,但 mod_dav_svn.so 檔案就在 \Apache\modules 中。

在此情況下,錯誤訊息有點誤導人。Apache 很可能無法載入 mod_dav_svn.so 所依賴的一個或多個 DLL。如果 Apache 以服務方式執行,它不會與一般使用者擁有相同的 PATH。請確定 libdb4*.dllintl3_svn.dlllibeay32.dllssleay32.dll 存在於 \Apache\bin\Apache\modules 中。如果它們不存在,您可以從您的 Subversion 安裝目錄中複製它們。

如果這仍然無法解決問題,您應該對 mod_dav_svn.so 使用類似 Dependency Walker 的工具,以查看是否有任何其他未解決的相依性。

為什麼我的儲存庫掛勾無法運作?

它們應該呼叫外部程式,但呼叫似乎永遠不會發生。

在 Subversion 呼叫掛勾指令碼之前,它會從環境中移除所有變數,包括 Unix 上的 $PATH 和 Windows 上的 %PATH%。因此,您的指令碼只能在您拼寫出該程式的絕對名稱時,才能執行另一個程式。

請確定掛勾指令碼已正確命名:例如,在 Unix 上,提交後掛勾應命名為 post-commit(無副檔名),而在 Windows 上應命名為 post-commit.batpost-commit.exe

除錯提示

如果您使用 Linux 或 Unix,請嘗試透過下列步驟「手動」執行指令碼

  1. 使用「su」、「sudo」或類似指令,變更為通常會執行指令碼的使用者。例如,如果您使用 Apache,可能是 httpdwww-data;如果您執行 svnserve 且存在特殊 Subversion 使用者,可能是 svn 等使用者。這將清楚顯示指令碼可能遇到的任何權限問題。
  2. 使用「env」程式,以空環境呼叫指令碼。以下是提交後掛勾的範例
                      $ env - ./post-commit /var/lib/svn-repos 1234
    
    請注意「env」的第一個引數為破折號;這會確保環境為空。
  3. 檢查主控台是否有錯誤。

為什麼我的 --diff-cmd 會抱怨「-u」?我嘗試使用 --extensions 覆寫它,但不起作用。

使用外部 diff 指令時,Subversion 會建構相當複雜的命令列。首先是指定的 --diff-cmd。接下來是指定的 --extensions(不過會忽略空的 --extensions),或未指定 --extensions(或指定為 '')時為「-u」。第三和第四,Subversion 會傳遞「-L」和第一個檔案的標籤(例如「project_issues.html(版本 11209)」)。第五和第六是另一個「-L」和第二個標籤。第七和第八是第一個和第二個檔案名稱(例如「.svn/text-base/project_issues.html.svn-base」和「.svn/tmp/project_issues.html.tmp」)。

如果您的偏好 diff 指令不支援這些引數,您可能需要建立一個小型包裝指令碼,以捨棄引數並僅使用最後幾個檔案路徑。

警告:請注意,Subversion 不希望外部 diff 程式變更其接收的檔案,否則可能會打亂工作副本。

如需進一步資訊,請參閱問題 #2044

Subversion 如何快取認證資料(純文字和已加密)?

為了避免每次伺服器操作都必須輸入密碼,Subversion 可以快取認證資料。

舊版本的 Subversion 可能已快取未加密的密碼(「已納入」),而 Subversion 始終支援讀取這些密碼。Subversion 是否快取新認證資料以及如何快取,取決於多項因素,包括存取方法、作業系統、編譯時選項,以及用戶端執行時期設定檔中的設定。

若要顯示快取中的認證資料,請使用 svn auth。認證資料絕不會自動移除,但可以使用 svn auth --remove 手動移除。

Windows

在 Windows 上,Subversion 使用標準 Windows API 加密資料,因此只有使用者可以解密快取的密碼。(自 Subversion 1.2 起)

macOS(以前稱為 Mac OS X)

在 macOS 上,Subversion 使用系統 Keychain 設施加密/儲存使用者的 svn 密碼。(自 Subversion 1.4 起)

UNIX/Linux

在 UNIX/Linux 上,Subversion 支援最多四個認證資料快取

  • GNOME Keyring
  • KWallet
  • GPG-Agent
  • ~/.subversion/auth/svn.simple/ 中的純文字快取

若要確定 Subversion 用戶端支援哪些認證資料快取,請執行 svn --version 命令,並在輸出的尾端尋找「可用下列驗證認證資料快取」。

GNOME Keyring 和 KWallet 都能協助在磁碟上儲存已加密的密碼。Subversion 要支援這些程式(自 Subversion 1.6 起),它們必須在編譯時和執行時都可用。

待辦事項:討論 GPG-Agent。

根據編譯時期選項 (--enable-plaintext-password-storage) 和執行時期設定 (見下方),Subversion 可能會 回退至將密碼儲存在純文字快取中。

--enable-plaintext-password-storage 的預設值在 Subversion 1.12 中已從 True 變更為 False,因此除非明確啟用,否則會停用純文字快取。

包含快取純文字密碼的目錄 (通常為 ~/.subversion/auth/) 具有 700 的權限,表示只有使用者 (和 root) 可以讀取。

「Subversion 已編譯並支援純文字密碼快取,但我想要避免將密碼寫入純文字快取。」

以下選項可在您的執行時期設定檔中使用 (每個使用者 ~/.subversion/config 和 ~/.subversion/servers,系統範圍 /etc/subversion/config 和 /etc/subversion/servers)

  • 若要允許使用 GNOME Keyring 和 KWallet 等加密儲存,但不允許使用純文字快取,請設定 store-plaintext-passwords = no
  • 若要允許快取伺服器憑證但不允許密碼 (加密或未加密),請設定 store-passwords = no
  • 若要停用儲存任何類型的憑證 (加密或未加密),請設定 store-auth-creds = no

「我想要使用純文字快取,但它並未在編譯時期啟用。」

為了回應各種問題和要求,Subversion 開發人員已撰寫一個 Python 腳本,可將純文字密碼儲存至快取中。如果您了解安全性影響,已排除其他替代方案,而且仍然想要將密碼以純文字快取在磁碟上,您可以在我們主幹的 tools/client-side/ 目錄中找到腳本 (截至撰寫本文為止)

其他資訊

有關密碼快取的更多資訊,請參閱 Subversion 書籍 的第 6 章,在 "Client Credentials Caching"。

我無法熱備份我的儲存庫,svnadmin 對於大於 2Gb 的檔案會失敗!

APR 0.9 分支的早期版本(Apache 2.0.x 和 Subversion 1.x 使用)不支援複製大型檔案(2Gb 以上)。已套用修正程式來解決「svnadmin hotcopy」問題,並包含在 APR 0.9.5+ 和 Apache 2.0.50+ 中。此修正程式並非適用於所有平台,但適用於 Linux。

我無法看到我剛提交的檔案的記錄項目。為什麼?

假設您在儲存庫上執行「svn checkout」,並在版本 7(又稱 r7)收到一個工作副本,其中有一個檔案稱為 foo.c。您花了一些時間修改檔案,然後成功提交。會發生兩件事

  • 儲存庫移至伺服器上的新 HEAD 版本。新 HEAD 版本的編號取決於自檢出工作副本以來已提交的版本數。例如,新的 HEAD 版本可能是 r20。
  • 在您的工作副本中,只有檔案 foo.c 移至 r20。工作副本的其餘部分仍保留在 r7。

您現在擁有所謂的混合版本工作副本。一個檔案位於 r20,但所有其他檔案仍保留在 r7,直到它們也提交,或執行「svn update」。

   $ svn -v status
    7         7 nesscg       .
   20        20 nesscg       foo.c
   $

如果您在沒有任何參數的情況下執行「svn log」指令,它會列印目前目錄的記錄資訊(在上述清單中稱為「.」)。由於目錄本身仍位於 r7,因此您看不到 r20 的記錄資訊。

若要查看最新記錄,請執行下列其中一項操作

  1. 執行「svn log -rHEAD」。
  2. 執行 'svn log URL',其中 URL 是儲存庫 URL。如果目前的目錄是工作副本,您可以將 URL 縮寫成儲存庫根目錄,例如 ^/,以節省一些輸入。請注意,在 Windows 中,'^' 符號是特殊符號,必須加上引號。例如:svn log "^/" --limit 10
  3. 執行 'svn log URL',其中 URL 是您想要查看其記錄的子目錄的 URL,例如:svn log ^/trunk
  4. 透過執行 'svn log foo.c' 來詢問該檔案的記錄資訊。
  5. 更新您的工作副本,使其全部位於 r20,然後執行 'svn log'。

為何我在從執行於 MacOS X 10.4 (Tiger) 的儲存庫透過 http:// 進行簽出時,會偶爾收到看似不一致的錯誤?

注意:這假設儲存庫是由 Apache 2.0.x 提供服務。

在 APR 0.9.6 中 有一個錯誤,當它執行於 Tiger 時會發生,而且當您嘗試簽出大於 64Kb 的檔案時會出現。產生的簽出會失敗,通常會顯示無法預測的錯誤訊息。以下是您在用戶端可能會看到的一些範例,您遇到的特定錯誤可能有所不同

   svn: Invalid diff stream: [tgt] insn 1 starts beyond the target view position
   svn: Unexpected end of svndiff input
   svn: REPORT request failed on '/path/to/repository'
   svn: REPORT of '/path/to/repository/!svn/vcc/default': Chunk delimiter was invalid

Apache error_log 中也可能會有錯誤,例如

   [error] Provider encountered an error while streaming a REPORT response.  [500, #0]
   [error] A failure occurred while driving the update report editor [500, #190004]

要確認此錯誤的存在  —  假設您可以存取提供儲存庫服務的機器  —  請嘗試使用 file:// URL 進行簽出,這將直接存取檔案系統,而不是透過 Apache。如果產生的簽出順利完成,那麼幾乎可以確定這就是問題所在。

目前,最好的解決方案是升級到 APR 1.2.0+。

或者,您可以從各自的原始碼重新建置 Apache 和 Subversion,在為 Apache 執行 configure 之前設定下列環境變數

   setenv ac_cv_func_poll no

或以 Bourne shell 語法,如下所示

   ac_cv_func_poll=no; export ac_cv_func_poll

如果您是分別建置 APR/APRUTIL(亦即,您並未使用 Apache tarball 中附帶的 APR/APRUTIL),您必須在執行 APR 的 configure 之前設定該環境變數,因為問題就出在這裡。

我無法在 Debian GNU/Linux 上從工作副本來源建置 Subversion;我在最後的連結階段遇到錯誤。出了什麼問題?

如果您在 Subversion trunk 來源建置的最後連結階段看到類似這樣的錯誤

   /usr/local/apache2/lib/libaprutil-0.so.0: undefined reference to `db_create'
   /usr/local/apache2/lib/libaprutil-0.so.0: undefined reference to `db_strerror'

這可能是因為您使用的是 Debian GNU/Linux 系統,且需要升級「libtool」。(我也聽說 Debian 套件管理員必須調整「libtool」,這可能會對 Subversion 建置造成一些問題。但那只是道聽塗說 — 在撰寫此常見問題解答條目之前,我沒有時間驗證細節。不過,請參閱 https://svn.haxx.se/dev/archive-2006-02/1214.shtml 和它引發的討論串,以取得詳細說明。)

無論如何,在 2005 年 11 月 15 日於執行新發行升級「測試」版的 Debian GNU/Linux 系統上遇到此問題後,解決方案是使用標準的「./configure && make && sudo make install」範例,從來源建置 libtool 1.5.20。之後,我在 Subversion 工作副本樹中執行「make clean」、「./autogen.sh」、「./configure」、「make」,一切運作正常。

請注意,在 https://svn.haxx.se/dev/archive-2003-01/1125.shtml 出現了另一份關於這些症狀的報告,不過該討論串中並未提及在此說明的解決方案。

我已啟動 svnserve,但它似乎未在埠 3690 上監聽。

使用 --listen-host=0.0.0.0 選項呼叫 svnserve。Svnserve 無法正確支援 IPv4/IPv6 雙堆疊操作。請參閱 問題 #2382

我無法新增目錄,因為 Subversion 顯示「已在版本控制中」。

您嘗試新增的目錄已包含 .svn 子目錄,它是工作副本,但它來自與您嘗試新增到的目錄不同的儲存庫位置。這可能是因為您使用作業系統的「複製」指令(而非 svn copy)來複製此工作副本中的子目錄,或將其他工作副本複製到此工作副本中。

快速且粗略的解決方案是刪除您嘗試新增的目錄中包含的所有 .svn 目錄;這將讓「新增」指令完成。如果您使用 Unix,此指令將刪除 dir 下的 .svn 目錄

  find dir -type d -name .svn -exec rm -rf {} \;

不過,如果複製來自同一個儲存庫,您理想上應該刪除或移開複製,並使用 svn copy 進行正確的複製,這將知道其歷史記錄並在儲存庫中節省空間。

如果複製來自不同的儲存庫,您應該自問為何進行此複製;您應該確保透過新增此目錄,您不會在儲存庫中製作它的不需要的副本。

有時透過 svnserve 存取非公開儲存庫會非常慢。

這通常發生於 APR 編譯為使用 /dev/random,而伺服器無法收集足夠的熵。如果 Subversion 是伺服器上唯一使用 APR 的應用程式,您可以安全地重新編譯 APR,並將 --with-devrandom=/dev/urandom 選項傳遞給 configure。不過,這不應在使用 APR 進行其他程序的系統上執行,因為這可能會使其他服務不安全。

在執行涉及大量資料的 Subversion 作業時,我收到錯誤訊息 SSL 協商失敗:SSL 錯誤:解密失敗或記錄 MAC 錯誤

這可能是因為 OpenSSL 0.9.8 有問題。已知降級到舊版本(或升級到新版本)可以解決此問題。

我收到一則錯誤訊息,內容為「此用戶端太舊」。

您同時使用較舊版本(1.4 之前)的 Subversion 命令列用戶端和 Subclipse。您最近升級了 Subclipse,現在您的命令列用戶端會顯示
svn: This client is too old to work with working copy
'/path/to/your/working/copy'; please get a newer Subversion client
這是因為 Subversion 的工作副本格式發生不兼容的變更,新版本的 Subclipse 升級了您的工作副本,因此現在您舊版的命令列程式無法讀取它。(此問題不限於 Subclipse;如果您使用 1.4 或更新的命令列用戶端,以及舊版的命令列用戶端,也會發生此問題。)解決方法很簡單,只要將您的命令列用戶端升級到 1.4 或更新版本即可。從 Subversion 1.5 開始,提供了一個輔助指令碼,可將工作副本降級為與 Subversion 舊版本相容的格式;請參閱 此常見問題集。

為什麼 svn switch 在某些情況下無法運作?

在工作副本中存在未版本化(且可能被忽略)的項目時,svn switch 有時會產生錯誤。切換會停止,使工作副本處於半切換狀態。

不幸的是,如果您採取錯誤的修正措施,可能會導致工作副本無法使用。有時在這種情況下,使用者會被指示執行 svn cleanup。但 svn cleanup 也可能會遇到錯誤。請參閱 問題 #2505

使用者可以手動移除導致問題的目錄或檔案,然後執行 svn cleanup,並繼續切換,以從此情況中復原。

請注意,從原始乾淨的檢出切換永遠不會產生錯誤。如果您在開發過程中使用 svn switch,則有以下三種工作方式

  1. 在切換之前,徹底清除工作副本中未版本化的(包括被忽略的)檔案。
    警告!這會刪除所有未版本化的目錄/檔案。請務必確認您不需要任何將被移除的項目。
    
    # Check and delete svn unversioned files: 
    svn status --no-ignore | grep '^[I?]' | sed 's/^[I?]//'
    svn status --no-ignore | grep '^[I?]' | sed 's/^[I?]//' | xargs rm -rf
    
  2. 保持原始乾淨的檢出。更新該檢出,然後複製它,並在想要切換到另一個分支時切換複製的版本。
  3. 冒險行事 :)。在不清理的情況下在分支之間切換,但如果您遇到切換錯誤,請知道您必須適當地從此錯誤中復原。刪除未版本化的檔案和報告錯誤的目錄。然後在需要時執行「svn cleanup」,然後繼續切換。除非您刪除所有未版本化的檔案,否則您可能必須重複此程序多次。

一些範例在 問題 2505 中詳細說明。問題在於 svn 客户端採取安全措施,不想要刪除任何未版本化的項目。

這裡詳細說明兩個具體範例來說明這類問題。還有其他這裡未涵蓋的 svn 切換錯誤,您可以透過僅從原始簽出進行切換來避免這些錯誤。

  1. 如果任何目錄已在分支之間移動或重新命名,則任何未版本化的內容都會造成問題。在這種情況下,您會看到此錯誤
    
    wc/$ svn switch $SVNROOT/$project/branches/$ticket-xxx
    svn: Won't delete locally modified directory '<dir>'
    svn: Left locally modified or unversioned files
    

    移除所有未版本化的檔案,並繼續切換將從此復原。

  2. 如果曾經新增並移除臨時建置檔案,則在儲存庫中切換時,該未版本化的檔案(可能在建置後)會失敗。您會看到相同的錯誤
    
    wc/$ svn switch $SVNROOT/$project/branches/$ticket-xxx
    svn: Won't delete locally modified directory '<dir>'
    svn: Left locally modified or unversioned files
    

    在這種情況下,僅移除未版本化的項目並無法復原。清理失敗,但「svn 切換」會指示您執行「svn 清理」。

    
    wc/$ svn switch $SVNROOT/$project/branches/$ticket-xxx
    svn: Directory '<dir>/.svn' containing working copy admin area is missing
    wc/$ svn cleanup
    svn: '<dir>' is not a working copy directory
    wc/$ svn switch $SVNROOT/$project/branches/$ticket-xxx
    svn: Working copy '.' locked
    svn: run 'svn cleanup' to remove locks (type 'svn help cleanup' for details)
    

    移除目錄(以及所有其他未版本化的檔案,以防止「切換」在類似的錯誤上重複中斷),並繼續切換將從此復原。

TortoiseSVN 清理錯誤有點不同。您可能會遇到此問題


Subversion reported an error while doing a cleanup!
<dir>/<anotherdir> is not a working copy directory

在這裡的每種情況中,「svn 切換」都會中斷,讓您留下半切換的工作副本。「svn 狀態」會顯示已切換項目的項目 S(與頂層目錄不同)、有問題目錄的 !,以及問題檔案的 ~(可能還有鎖定的 L)。像這樣


wc/$ svn status 
!      .
!      <dir>
    S  <switched_things>
~      <dir>/<thing_that_is_now_unversioned>

在 Windows 中,使用命令列用戶端進行更新時,我收到一個錯誤訊息,指出「系統找不到指定的路徑」,並建議我的工作副本可能已損毀。但我可以用 TortoiseSVN 順利更新。這是怎麼回事?

仔細檢視有關 命名檔案 的 Windows API 文件,可以發現造成此問題的最常見原因。簡而言之,使用 Windows 路徑函式的 Unicode 版本,以及提供絕對路徑指定符而非相對路徑指定符,可以處理更長的檔案名稱。很幸運地,Subversion 使用的 Apache Portable Runtime (APR) 函式庫會透明地將絕對路徑(例如 C:\WorkingCopy\file.txt)轉換成 Windows API 所需的格式 (\\?\C:\WorkingCopy\file.txt),然後再轉換回來。很不幸地,只有在使用絕對路徑時,才能享有這些長路徑的優點。

若要查看路徑長度是否為您所見問題的原因,請嘗試提供絕對目標路徑給 Subversion 命令列用戶端,而非相對路徑(或完全不提供)。換句話說,請執行下列動作,而非執行


C:\> svn up WorkingCopy

或執行


C:\> cd C:\WorkingCopy
C:\WorkingCopy> svn up

執行


C:\> svn update C:\WorkingCopy

如果問題消失了,恭喜您 — 您已觸及 Windows 路徑長度限制。現在您已知道解決方法。

為何這個問題不會影響 TortoiseSVN?因為 TortoiseSVN 始終提供絕對路徑給 Subversion API。

那麼,為何 Subversion 命令列用戶端不會始終將其輸入轉換成絕對路徑並使用這些路徑?在 Subversion 1.7 之後,它會執行此動作。

我收到一則錯誤訊息,表示「此用戶端太舊,無法使用工作副本「...」」。如何在不升級 Subversion 的情況下修復它?

有時,工作副本的元資料格式會在次要版本之間發生不兼容的變更。例如,假設您有一個使用 Subversion 1.4.4 建立的工作副本,但某天您決定試用 Subversion 1.5.0。之後,您嘗試切換回 1.4.4,但它無法運作 — 它只會顯示上述錯誤。

這是因為 1.5.0 將您的工作副本格式升級為支援一些新功能(在本例中,變更清單、keep-local 旗標和變動深度目錄)。儘管 1.4.4 不知道這些新功能,但它至少可以辨識工作副本格式已升級為它無法處理的版本。

1.5.0 升級工作副本是有充分理由的:它知道 1.4.4 不知道這些新功能,而且如果 1.4.4 現在要干預工作副本的元資料,可能會遺失重要資訊,可能導致損毀(例如,請參閱 問題 #2961)。

Subversion 1.7.0 和更新版本不會升級工作副本,除非您明確要求它們這麼做。(不過,升級工作副本是必要的;Subversion 1.7.0 無法在較早的 Subversion 建立或使用的工作副本上執行。)

Subversion 1.6.x 和更早版本會在第一次接觸工作副本時自動升級工作副本。如果您只想試用 Subversion 的新版本,而不打算永久安裝它,這種行為可能會很煩人。因此,我們會散布一個腳本,可以在安全的情況下降級工作副本。

https://svn.apache.org/repos/asf/subversion/trunk/tools/client-side/change-svn-wc-format.py

使用「--help」選項執行該腳本,以了解如何使用它。(它可以將 1.6.x 工作副本降級為 Subversion 1.4.x 和 1.5.x 可用的格式,但無法降級 1.7.x 工作副本。)

隨著 Subversion 的未來版本發布,我們將盡量讓此常見問題解答條目保持最新,以提供潛在的降級情境及其影響。

在 64 位元 Linux 上建置 Neon 函式庫時,我收到一個錯誤訊息,指出「在建立共用物件時,無法使用針對 `a local symbol' 的重新定位 R_X86_64_32」。

Neon 函式庫用於透過 HTTP 在 Subversion 伺服器和用戶端之間進行通訊,通常會建置為靜態函式庫。但它會隨後連結到不同的共用函式庫。這會在 64 位元 AMD 系統上造成建置過程中的錯誤,類似於此


subversion-1.4.6/neon/src/.libs/libneon.a(ne_request.o): relocation R_X86_64_32
against `a local symbol' can not be used when making a shared object;
recompile with -fPIC
/home/jrandom/subversion/subversion-1.4.6/neon/src/.libs/libneon.a: could not
read symbols: Bad value

開發人員清單上有一個關於此問題的討論串

解決方案是將 "--enable-shared" 選項提供給 Subversion 的設定指令碼。

為何我在從 Apache 進行結帳時會收到「無法讀取回應主體:安全連線已截斷」的錯誤訊息?

簡而言之,此錯誤代表一類問題,當 Apache 錯誤地認為您的 Subversion 用戶端不再關注它與 Apache 建立的網路連線時,可能會發生此類問題。在類似情況下,已報告其他錯誤訊息,具體取決於連線是否使用 SSL,或 Apache 確切決定終止連線的時間。

Subversion 用戶端會嘗試隨時讓工作副本保持正常狀態。在結帳期間,它執行此項操作的方法之一是將已結帳檔案的原始版本隱藏起來,直到已擷取給定目錄的所有檔案和子目錄。一旦目錄的所有資料都已下載,用戶端會「完成」該目錄,將檔案的原始版本複製到工作區,修改管理資料,等等。在進行此目錄完成時,用戶端會專注於該任務,不會關注結帳網路串流。有時,通常在版本化目錄包含異常大量的檔案或大量異常大型檔案的情況下,用戶端可能會花費大量時間完成目錄(並忽略網路串流),以至於 Apache 認為用戶端已永久離開,因此 Apache 會終止連線。當用戶端最終將注意力轉回網路串流時,它會發現伺服器已放棄連線,並將此報告為錯誤。

解決此情況的一種方法是增加 Apache 願意等待用戶端證明其仍在監聽網路串流的時間。您可以透過調整 Apache Timeout 設定值向上調整。不過,建議您評估您的資料集。如果單一目錄中有大量檔案會在簽出期間造成問題,則很可能會在其他地方造成其他問題。如果您能將檔案集合分割成幾個檔案數較少的子目錄,這可能會普遍有益。

即使沒有其他人提交衝突變更,為什麼我在更新時會發生樹狀結構衝突?

當您提交時,只有實際上因為提交而變更的檔案/目錄會將其基本版本升級到工作副本中的 HEAD。其他檔案/目錄(可能包括您從中提交的目錄!)不會升級其基本版本,這表示 Subversion 仍將它們視為基於過時的版本。另請參閱 此問題Subversion 書籍的此區段

這可能會令人困惑,特別是因為您可能會對自己造成樹狀結構衝突。例如,如果您將檔案新增到目錄並提交,然後在本地將該目錄移到其他地方,然後嘗試提交,此第二次提交將因目錄本身仍基於過時版本而失敗,並出現過時錯誤。更新時,將標記樹狀結構衝突。

Subversion 目前無法得知您自己在第二次提交期間提交了導致目錄過時的變更。而且允許提交過時目錄可能會導致無法偵測到某些樹狀結構衝突,因此 Subversion 不允許您這麼做。

為避免此問題,請務必在進行刪除、新增或移動檔案或目錄等結構變更之前更新整個工作副本。

在透過 SSL 執行 Subversion 作業時,我收到錯誤訊息 SSL 握手失敗:SSL 錯誤代碼 -1/1/336032856

當伺服器報告的主機名稱與 SSL 憑證中提供的名稱不符時,可能會發生此情況。請確定伺服器設定檔對 ServerNameNameVirtualHost 使用正確的值。

客戶端方面的修正方法是將 OpenSSL 更新至 1.0.0d 版本。請參閱 這篇發佈至 Subversion 開發人員郵件清單的文章 以取得詳細資訊。

即使我在伺服器中正確設定 SSL 憑證,我仍收到 "驗證伺服器憑證時發生錯誤" 錯誤。

如果憑證發行者未被 SVN 客戶端認定為「受信任」,就會發生此錯誤。Subversion 會詢問您是否信任該憑證,以及是否要儲存此憑證。


$ svn info https://mysite.com/svn/repo
Error validating server certificate for 'https://mysite.com:443':
- The certificate is not issued by a trusted authority. Use the
fingerprint to validate the certificate manually!
Certificate information:
- Hostname: mysite.com
- Valid: from Wed, 18 Jan 2012 00:00:00 GMT until Fri, 18 Jan 2013
23:59:59 GMT
- Issuer: Google Inc, US
- Fingerprint:
34:4b:90:e7:e3:36:81:0d:53:1f:10:c0:4c:98:66:90:4a:9e:05:c9
(R)eject, accept (t)emporarily or accept (p)ermanently?

在某些情況下,即使您輸入「p」選項接受此憑證,下次存取 SVN 時,仍會再次出現相同的錯誤。原因可能有多種。問題可能是您的 ~/.subversion 目錄權限錯誤,因此每次您想要永久新增憑證時,svn 實際上無法執行此動作,也不會通知您無法執行此動作。

可以透過在

~/.subversion/auth/svn.ssl.server

目錄中使用 chmod 644 修復權限,或刪除目錄內容來解決此問題。如果刪除目錄內容,下次存取儲存庫時,目錄會自動填入內容。

將檔案匯入我的儲存庫後,我在儲存庫目錄中看不到這些檔案。它們在哪裡?

檔案位於儲存庫中;您可以透過執行 svn ls -R 等指令,或嘗試從儲存庫簽出工作副本來驗證這一點。

  $ pwd
  /var/srv/repositories/foo
  $ ls -1
  conf
  db
  format
  hooks
  locks
  README.txt
  $ svnlook youngest /var/srv/repositories/foo
  1
  $ svn ls file:///var/srv/repositories/foo
  trunk/
  tags/
  branches/

版本控制的文件和目錄並非儲存在磁碟的樹狀結構中(例如 CVS 儲存庫),而是儲存在資料庫檔案中。BDB 後端使用 Berkeley DB 資料庫,而 FSFS 後端使用自訂檔案格式,未來可能會使用 SQLite 資料庫。

何時 svn copy 會建立 svn:mergeinfo 屬性?

一般來說,為了避免某些類型的錯誤合併衝突,可以記住下列規則

  • 在主幹或分支內部複製/重新命名檔案或目錄時,請在工作副本中執行複製/重新命名。對於重新命名,工作副本不應混合版本工作副本
  • 在複製/重新命名整個分支時,請在儲存庫中執行複製/重新命名(例如透過 URL)。

在複製過程中,如果來源是 URL,而目標是 URL 或在工作副本中,則會在複製目標上建立明確的合併資訊。這樣做的目的是,當使用下列指令建立分支時

svn copy ^/trunk ^/branches/mybranch
稍後再使用類似下列指令將祖先無關的子樹複製到分支中
svn copy ^/branches/another-branch/foo ^/branches/mybranch/bar
目錄 /branches/mybranch/bar 不會從其父目錄 /branches/mybranch 繼承合併資訊。從父目錄繼承的合併資訊可能無法反映新子目錄實際正確的合併歷程。

在來源和目標都在工作副本中的拷貝期間,不會在拷貝目標上建立合併資訊(在 Subversion 1.5.5 中)。這假設在主幹(或分支)上新增一個新的子項,並且此新增項目已合併到另一個分支,而該分支會使用定期追趕合併來保持同步。在此情況下,分支的新子項的繼承合併資訊是正確的,而建立明確的合併資訊可能會導致虛假的合併衝突,這是因為子項和父項的合併歷程記錄有明顯但事實上不正確的差異。

如需有關此行為的更多詳細資料和討論,請參閱使用者郵件清單上的這篇文章

包含一些特殊字元的密碼似乎無法運作?

包含非 ASCII 字元的密碼可能無法與 Subversion 支援的基本驗證機制可靠地運作。這是因為用戶端和伺服器系統之間潛在的字元編碼差異。請參閱這篇郵件清單文章以取得詳細資料。

作為解決方法,您可以將 Subversion 伺服器設定為使用單一登入機制,例如 Kerberos 或 SSPI。請參閱Apache HTTPD 伺服器文件以取得詳細資料。如果您使用 svnserve,請參閱 Subversion 書籍中的「使用 svnserve 與 SASL」章節

使用 svnserve 與 SSH 驗證時,SSH 金鑰可用於解決密碼的此限制。

為什麼 HTTP(S) URL 對 URL 拷貝或分支/標籤操作需要很長的時間?

如果您看到透過 HTTP(S) 提供服務的 Subversion 儲存庫的伺服器端複製(又稱為分支或標記)速度很慢,您可能會遇到 問題 4531。此問題是由於伺服器上的 httpd 的 mod_dav 模組對「待複製樹狀結構」進行爬取所造成(讓複製的效能成本為 O(sizeof(tree)),而不是 Subversion 分支/標記通常的 O(1))。此行為出現在Apache httpd 版本 2.2.25(或更高版本)2.4.6(或更高版本)中,較舊版本的 httpd 不受影響。因此,對大型樹狀結構進行分支/標記可能需要花費數分鐘。

此問題已在 Subversion 1.8.14 的 mod_dav_svn 中修復。您也可以使用下列解決方法讓 mod_dav 略過不必要的作業;將下列指令新增到伺服器上的 Apache 設定檔中,最好只新增到為 SVN 設定的 Location 區塊內

SetEnvIf Request_Method COPY method_is_copy
RequestHeader set Depth 0 env=method_is_copy

這會在每個 COPY 要求中新增一個標頭「深度」,其值為 0。這會讓 mod_dav 避免爬取待複製的樹狀結構(但仍可讓 Subversion 執行正常的遞迴複製)。

請參閱 此郵件串以取得更多詳細資料。

在透過 SSL 執行 Subversion 作業時,我收到錯誤訊息 SSL 通訊期間發生錯誤

SSL 通訊錯誤可能有多種原因。您可以使用 openssl 二進位檔來偵錯 ssl 連線。

openssl s_client -connect example.com:443 -servername example.com
如果您使用用戶端憑證,則需要先將 Subversion 的用戶端憑證從 pkcs12 轉換為 pem
openssl pkcs12 -in path/to/svn/cert.p12 -out cert.pem
然後您可以使用
openssl s_client -connect example.com:443 -servername example.com -cert cert.pem
如果您在 .subversion/servers 中使用 ssl-authority-files 來驗證伺服器憑證,您可以讓 s_client 使用額外參數執行相同的動作
openssl s_client ... -CAfile path/to/authority.pem
s_client 輸出可能會指出發生什麼問題。

例如,如果 s_client 回報

error setting certificate
140258270184704:error:140AB18E:SSL routines:SSL_CTX_use_certificate:ca md too weak:../ssl/ssl_rsa.c:303:
則建立新的 CA 金鑰(使用 sha256 而非 md5)應可解決此問題。

開發人員問題:

如何在動態 Subversion 二進位檔上執行偵錯程式,而不需要安裝它們?

在 unix 系統上執行 make install 步驟之前,Subversion 原始程式碼樹中的動態建置「可執行檔」實際上是 libtool 所產生的 shell 腳本,會重新連結並執行真正的二進位檔。如下所示,這會讓偵錯變得複雜

subversion$ gdb subversion/svn/svn
... "/path/to/subversion/subversion/svn/svn": 非可執行格式:無法辨識檔案格式

您可以透過 libtool 指令執行 gdb 來解決此問題。執行模式中的 libtool 指令會偵測 svn 指令是 libtool 包裝器腳本,並處理設定適當的環境變數,以及在執行 gdb 之前將腳本替換為真正的檔案路徑。

您的命令列會類似這樣

$ libtool execute gdb subversion/svn/svn

如何在 Subversion 二進位檔上執行偵錯程式,而不會讓編譯器內嵌混淆原始程式碼?

預設情況下,gcc 通常會最佳化私有變數和函式,內嵌相關操作。這會讓在偵錯程式中逐步執行程式碼變得複雜。

透過在 unix 系統上執行 make 步驟時關閉最佳化來解決此問題

subversion$ make EXTRA_CFLAGS=-O0

(這是「dash ohh zero」。)或者,您可以透過執行下列指令,讓此變更更為永久

subversion$ ./configure --enable-debug

對於生產安裝,請記得在從原始碼安裝 Subversion 之前,透過重新執行沒有額外標記的 makeconfigure,來取消此操作。

參考:

Subversion 使用哪些 HTTP 方法?

Subversion 伺服器會對 mod_dav_svn 伺服器模組傳送 WebDAV/DeltaV 協定的子集。簡短的回答是

     OPTIONS, PROPFIND, GET, REPORT,
     MKACTIVITY, PROPPATCH, PUT, CHECKOUT, MKCOL,
     MOVE, COPY, DELETE, LOCK, UNLOCK, MERGE

請注意,這個清單可能會隨著時間而增加:Subversion 1.7+ 開始在與 1.7+ 伺服器通訊時使用 POST 方法,而且 Subversion 1.9+ 可能會在與 1.9+ 伺服器通訊時開始使用另一種方法。

協定的詳細資訊記載於此處

https://svn.apache.org/repos/asf/subversion/trunk/notes/http-and-webdav/webdav-protocol

什麼是「自行車棚」?

請參閱 Poul-Henning Kamp 發表在 freebsd-hackers 的文章:https://docs.freebsd.org/en/books/faq/#bikeshed-painting

您如何發音「Subversion」?

Jim Blandy 既為 Subversion 命名,也設計了它的存放庫,他發音「Subversion」為 "Subversion"

什麼是「baton」?

在 Subversion 的原始碼中,有許多地方提到「baton」物件。這些只是 void * 資料結構,它們為函式提供背景。在其他 API 中,它們通常稱為 void *ctxvoid *userdata,Subversion 開發人員稱這些結構為「baton」,因為它們會被傳遞很多次。

當您說存放庫「卡住了」時,您是什麼意思?

楔入的儲存庫

Subversion 儲存庫包含兩個不同的內部部分,一個工作隔間和一個儲存隔間。楔入的儲存庫是一個工作隔間因某些原因無法存取,但儲存隔間完好的儲存庫。因此,楔入的儲存庫並未遺失任何資料,但必須修正工作隔間,才能存取儲存庫。有關如何執行的詳細資訊,請參閱條目。

損毀的儲存庫

損毀的 Subversion 儲存庫是指儲存隔間已損毀的儲存庫,因此儲存庫中確實遺失了部分資料。

您可能也想要查看 The Jargon File 中「楔入」的定義。

什麼是 CVSSv3?分數和向量代表什麼意思?

Subversion 在我們的安全公告中使用 CVSSv3,因此您會在公告的嚴重性區段中看到 CVSSv3 基本分數和向量。CVSSv3 是常見漏洞評分系統的最新版本,這是一個用於評估電腦系統安全漏洞嚴重性的開放式產業標準。FIRST 維護此標準的文件

分數為 0 到 10 之間的數字,風險較低的漏洞分數較低,風險較高的漏洞分數較高。分數是透過確定漏洞的指標,然後根據這些指標計算分數來計算的。如果您想要了解分數如何確定,您需要向量和對標準中所指定的公式的了解。

向量是適用於漏洞的指標的簡要說明

CVSSv3 提供 3 種類型的指標和分數;基本、暫時和環境。Subversion 專案只會提供基本分數和指標。作為一個專案,我們無法確定各種安裝的環境風險,因此我們無法計算環境指標。暫時指標是針對可能隨時間改變的因素。我們不會在公告發布後更新公告,因此我們無法追蹤這些變動的值。

某些漏洞需要特定的組態或環境因素才能被利用。CVSSv3 規定存取複雜度指標應考慮此類組態的普遍性。因此,需要異常組態的漏洞將會有較低的分數。這些分數可以幫助您優先處理您需要對公告做出反應的速度,但由於存取複雜度指標,您仍應考慮漏洞如何影響您的安裝。

在計算伺服器漏洞的可用性影響指標時,Subversion 專案將使用 Subversion 中的「完成」值,而不是主機系統。例如,在考慮拒絕服務攻擊時,如果漏洞允許攻擊者讓 Subversion 伺服器完全無法存取,則可用性影響指標將計算為「高」。另一方面,如果攻擊只讓 Subversion 伺服器變慢或限制成功連線的數量,則會評為「低」。

在計算伺服器漏洞的完整性影響指標時,當 Subversion 儲存庫的歷程可能被變更或當主機系統上任何檔案的修改能力發生時,Subversion 專案將使用高值。在違反任何驗證或授權需求的情況下,變更任何檔案(同時保留適當的歷程追蹤)的能力將被視為低。

在計算伺服器漏洞的機密性影響指標時,當儲存庫中的所有檔案都可以讀取,而不論任何驗證或授權需求時,Subversion 專案將使用高值。如果只有部分檔案可以讀取,則將被視為低。

由於我們計算這些影響指標的方式,您可能會在漏洞資料庫或廠商公告中看到具有不同評分的公告。例如,提供 Subversion 二進制套件的 Linux 發行版可能會將系統上所主機的 Subversion 儲存庫內容的完全公開評分為僅為低機密性影響,導致較低的評分。


已棄用的常見問題


疑難排解(已棄用):

為什麼 HTTP Digest 驗證無法運作?

這可能是 Apache HTTP Server(版本 2.0.48 及更早版本)中已知錯誤所致,已提供修補程式,請參閱 https://bz.apache.org/bugzilla/show_bug.cgi?id=25040。您可能也想閱讀 https://issues.apache.org/jira/browse/SVN-1608,看看說明是否符合您的症狀。

在 Windows XP 中,Subversion 伺服器有時似乎會傳送損毀的資料。這真的會發生嗎?

您需要安裝 Windows XP Service Pack 1。

BDB 問題:

如何判斷儲存庫使用哪個版本的 Berkeley DB?

如果是即時儲存庫,那麼簡單的答案就是「您已安裝的 Berkeley DB 版本」。然而,如果它是來自備份或未知來源的儲存庫,而且您不知道它是由哪個版本的 Berkeley DB 建立的,以下是找出方法

執行一些指令,以查看儲存庫中編號最高的 db/log.* 檔案中,偏移量 12 和 16(十進位)的兩個 4 位元組整數。以下是使用 GNU od 的範例:「od -j12 -N8 -tx4 log.<number>」。以下是使用 Mac OS X hexdump 的範例:「hexdump -s12 -n8 -x log.<number>」。第一個整數應該是魔術數字 0x00040988,它將檔案識別為 Berkeley DB 日誌檔。第二個數字是日誌格式版本 - 使用下表將它與 Berkeley DB 版本配對

日誌格式版本Berkeley DB 版本
5 (0x00000005)4.0
7 (0x00000007)4.1
8 (0x00000008)4.2
10 (0x0000000a)4.3
11 (0x0000000b)4.4
12 (0x0000000c)4.5
13 (0x0000000d)4.6

為什麼我的儲存庫佔用這麼多磁碟空間?

儲存庫在 repos/db/ 子目錄中的 Berkeley DB「環境」中儲存所有資料。該環境包含一組表格和一堆記錄檔 (log.*)。Berkeley DB 會記錄對表格進行的所有變更,以便在中斷時可以將表格復原為一致的狀態 (更多資訊)。

記錄檔會無限增長,耗盡磁碟空間,除非您 (作為儲存庫管理員) 採取一些措施。在任何特定時刻,Berkeley DB 僅使用少數記錄檔 (請參閱 這篇文章 及其相關討論串);其餘的可以安全刪除。如果您永遠保留所有記錄檔,理論上 Berkeley DB 可以從儲存庫建立之日起重播對其進行的每項變更。但在實際上,如果您正在進行備份,那麼這可能不值得花費磁碟空間。

使用 svnadmin 來查看可以刪除哪些記錄檔。您可能需要建立一個 cron 工作來執行此操作。

$ svnadmin list-unused-dblogs /repos
/repos/db/log.000003
/repos/db/log.000004
[...]

$ svnadmin list-unused-dblogs /repos | xargs rm
# disk space reclaimed!

您也可以使用 Berkeley DB 的 db_archive 指令

$ db_archive -a -h /repos/db | xargs rm
# disk space reclaimed!

另請參閱 svnadmin hotcopyhotbackup.py

注意:如果您使用 Berkeley DB 4.2,Subversion 會建立啟用自動記錄檔移除功能的新儲存庫。您可以透過傳遞 --bdb-log-keep 選項給 svnadmin create 來變更此設定。請參閱 Berkeley DB 4.2.x 下載套件 中 docs/api_c/env_set_flags.html#DB_LOG_AUTOREMOVE 下的 Berkeley DB 手冊中的 DB_LOG_AUTOREMOVE 旗標。

我的儲存庫似乎一直卡住,並顯示需要復原 (DB_RUNRECOVERY) 的錯誤。可能的原因是什麼?

儲存庫中的 Berkeley DB 資料庫對中斷很敏感。如果存取資料庫的程序在沒有「乾淨」關閉環境的情況下結束,則資料庫會處於不一致的狀態。造成此問題的常見原因包括

  • 處理程序在遇到權限問題時會退出
  • 處理程序崩潰/分段錯誤
  • 處理程序被強制終止
  • 磁碟空間不足

對於大多數情況,您應該執行「svnadmin recover」,這會將儲存庫倒回至一致的狀態;請參閱此問題以取得詳細資料。請注意,磁碟空間不足,加上頻繁的簽出或更新,可能會導致儲存庫以無法復原的方式崩潰(因此請保持備份)。

分段錯誤、強制終止和磁碟空間不足相當罕見。權限問題更為常見:一個處理程序存取儲存庫並意外變更擁有權或權限,然後另一個處理程序嘗試存取並因權限而中斷。

預防此問題的最佳方式是正確設定您的儲存庫權限和擁有權。請參閱此處以取得我們的建議。

每次我嘗試存取我的儲存庫時,處理程序都會掛起。我的儲存庫是否已損毀?

您的儲存庫並未損毀,您的資料也未遺失。如果您的程序直接存取儲存庫(mod_dav_svn、svnlook、svnadmin,或如果您存取 `file://' URL),則它使用 Berkeley DB 存取您的資料。Berkeley DB 是一個記錄系統,表示它會在執行任何動作前記錄所有動作。如果您的程序中斷(Control-C 或區段錯誤),將會留下一個鎖定檔,以及描述未完成工作的記錄檔。任何嘗試存取資料庫的其他程序都只會暫停,等待鎖定檔消失。若要喚醒您的儲存庫,您需要要求 Berkeley DB 完成工作,或將資料庫倒轉至已知的一致狀態。

警告:如果您執行復原而另一個程序存取儲存庫,您可能會嚴重損毀您的儲存庫。

在執行此動作前,請務必完全停用對儲存庫的所有存取(關閉 Apache,從「svn」移除可執行權限)。請務必以擁有並管理資料庫的使用者身分執行此命令,而非以 root 身分執行,否則它會在 db 目錄中留下 root 擁有的檔案,而管理資料庫的非 root 使用者(通常是您或您的 Apache 程序)無法開啟這些檔案。在執行復原時,也請務必設定正確的 umask,否則會鎖定允許存取儲存庫的群組中的使用者。

只要執行

   svnadmin recover /path/to/repos

命令完成後,請檢查儲存庫的 db 目錄中的權限。

有時「svnadmin 復原」無法運作。您可能會看到它顯示類似下列的錯誤

  Repository lock acquired.
  Please wait; recovering the repository may take some time...
  svnadmin: DB_RUNRECOVERY: Fatal error, run database recovery
  svnadmin: bdb: Recovery function for LSN 175 7066018 failed on backward pass
  svnadmin: bdb: PANIC: No such file or directory
  svnadmin: bdb: PANIC: fatal region error detected; run recovery

或類似下列的錯誤

  Repository lock acquired.
  Please wait; recovering the repository may take some time...
  svn: DB_RUNRECOVERY: Fatal error, run database recovery
  svn: bdb: DB_ENV->log_flush: LSN of 115/802071 past current end-of-log
  of 115/731460
  svn: bdb: Database environment corrupt; the wrong log files may have
  been removed or incompatible database files imported from another
  environment
  [...]
  svn: bdb: changes: unable to flush page: 0
  svn: bdb: txn_checkpoint: failed to flush the buffer cache Invalid argument
  svn: bdb: PANIC: Invalid argument
  svn: bdb: PANIC: fatal region error detected; run recovery
  svn: bdb: PANIC: fatal region error detected; run recovery
  [...]

在這種情況下,請嘗試使用 Berkeley DB 原生的 db_recover 實用程式(請參閱位於 Berkeley DB 4.2.x 下載套件 的 docs/utility/db_recover.html 下的 Berkeley DB db_recover 文件)。它通常位於 Berkeley DB 安裝的「bin/」子目錄中,例如,如果您從來源安裝 Berkeley DB,它可能是 /usr/local/BerkeleyDB.4.2/bin/db_recover;或者在 Berkeley DB 預先封裝的系統上,它可能只是 /usr/bin/db_recover。如果您已安裝多個版本的 Berkeley DB,請確保您使用的 db_recover 版本與建立存放庫時所使用的 Berkeley DB 版本相符。

使用「-c」(「災難性復原」)旗標執行 db_recover。您也可以新增「-v」以增加詳細資料,以及「-h」加上一個引數,告訴它要復原哪個 db 環境(因此您不必 cd 進入該目錄)。因此

   db_recover -c -v -h /path/to/repos/db

使用擁有存放庫的同一個使用者執行此指令,而且再次絕對確定在您執行此指令時,沒有其他程序正在存取存放庫(例如,關閉 svnserve 或 Apache)。

我的存放庫持續顯示「無法配置記憶體」的錯誤訊息。我該怎麼辦?

如果您使用 http:// 存取,則「無法配置記憶體」錯誤會顯示在 httpd 錯誤記錄中,而且看起來像這樣

[Wed Apr 07 04:26:10 2004] [error] [client 212.151.130.227] (20014)
Error string not specified yet: Berkeley DB error while opening 
'strings' table for filesystem /usr/local/svn/repositories/svn/db: 
Cannot allocate memory
[Wed Apr 07 04:26:10 2004] [error] [client 212.151.130.227] 
Could not fetch resource information.  [500, #0]
[Wed Apr 07 04:26:10 2004] [error] [client 212.151.130.227] 
Could not open the requested SVN filesystem  [500, #160029]     
[Wed Apr 07 04:26:10 2004] [error] [client 212.151.130.227] (17) 
File exists: Could not open the requested SVN filesystem  [500, #160029]

這通常表示 Berkeley DB 存放庫已用盡資料庫鎖定(這不會發生在 FSFS 存放庫中)。這不應該在正常操作過程中發生,但如果發生,解決方案是執行資料庫復原,如 此處 所述。如果它經常發生,您可能需要提高 db/DB_CONFIG 檔案中的預設鎖定參數(set_lk_max_locksset_lk_max_lockersset_lk_max_objects)。在現有存放庫中變更 DB_CONFIG 時,請記得在之後執行復原。

當我啟動 Apache 時,mod_dav_svn 抱怨「資料庫版本錯誤」,它找到的是 db-3.X,而不是 db-4.X。

您的 apr-util 連結到 DB-3,而 svn 連結到 DB-4。很不幸的是,DB 符號並不相同。當 mod_dav_svn 載入到 Apache 的處理程序空間時,它最後會針對 apr-util 的 DB-3 函式庫解析符號名稱。

解決方案是確定 apr-util 編譯時連結到 DB-4。您可以透過傳遞特定開關到 apr-util 或 apache 的 configure 來執行此動作:"--with-dbm=db4 --with-berkeley-db=/the/db/prefix"。

我在 Red Hat 9 上收到「函式未實作」錯誤,而且什麼都不管用。我該如何修正這個問題?

這並不是 Subversion 的問題,但它經常影響 Subversion 使用者。

Red Hat 9 和 Fedora 附帶的 Berkeley DB 函式庫仰賴核心支援 NPTL(原生 Posix 執行緒函式庫)。

Red Hat 提供的核心內建此支援,但如果您編譯自己的核心,則您可能沒有 NPTL 支援。如果是這種情況,您會看到類似這樣的錯誤

svn: Berkeley DB error
svn: Berkeley DB error while creating environment for filesystem tester/db:
Function not implemented

這可以用下列幾種方式之一來修正

  • 針對您使用的核心重新建置 Berkeley DB。
  • 使用 Red Hat 9 核心。
  • 將 NPTL 修補程式套用至您使用的核心。
  • 使用包含 NPTL 支援的最新核心 (2.5.x)。
  • 檢查環境變數 LD_ASSUME_KERNEL 是否設定為 2.2.5,如果是,請在啟動 Subversion (Apache) 之前取消設定。(您通常會設定此變數在 Red Hat 9 上執行 Wine 或 Winex)

若要使用 Berkeley DB 的 NPTL 版本,您還需要使用具有 NPTL 支援的 glibc 函式庫,這可能表示 i686 版本。請參閱 https://svn.haxx.se/users/archive-2004-03/0488.shtml 以取得詳細資料。

我收到錯誤訊息「svn: bdb: 呼叫暗示與先前呼叫不一致的存取方法」。我該如何修正?

Berkeley DB 4.1 已顯示出相當不穩定,4.0 和 4.2 都較佳。此錯誤訊息是 4.1 有時會中斷的獨特方式的徵兆。

問題在於,使用 Berkeley DB 後端的 Subversion 儲存庫所組成的其中一個資料表的資料庫格式欄位已損毀。由於不明原因,這幾乎總是「copies」資料表,它從「btree」類型切換到「recno」類型。以下是簡單的復原程序,如果它們沒有成功,您應該聯絡 Subversion 使用者 郵件清單

  • 確保沒有其他程序會嘗試存取您的儲存庫。
  • 現在,備份您的儲存庫到 tar 或 zip 檔案或類似檔案。
  • 變更到儲存庫的 db 子目錄。
  • rm __db.* log.*
  • db_dump -p -r copies > copies.dump
  • 現在編輯 copies.dump。在接近頂端的區段中,將「type=recno」變更為「type=btree」,並刪除以「re_len=」開頭的行。
  • rm copies
  • db_load copies < copies.dump
  • svnadmin dump .. > ../../my-recovered.svndump
  • 現在建立新的儲存庫,重新載入剛剛產生的傾印檔,並複製所有自訂掛勾或組態。驗證新儲存庫中的最高版次號碼是否符合您的預期。

升級到 Berkeley DB 4.3 或更新版本後,我看到儲存庫錯誤。

在 Berkeley DB 4.3 之前,svnadmin recover 可用於就地升級 Berkeley DB 儲存庫。但是,由於 Berkeley DB 在版本 4.3 中的行為改變,這現在會失敗。

使用此程序將您的儲存庫原地升級至 Berkeley DB 4.3 或更新版本

  • 請確定沒有程序正在存取儲存庫(停止 Apache、svnserve,限制透過 file://、svnlook、svnadmin 等存取)
  • 使用較舊的 svnadmin 二進位檔(即連結至較舊的 Berkeley DB)
    1. 復原儲存庫:'svnadmin recover /path/to/repository'
    2. 備份儲存庫。
    3. 刪除所有未使用的記錄檔。您可以透過執行 'svnadmin list-unused-dblogs /path/to/repeository' 來查看它們
    4. 刪除共用記憶體檔案。這些檔案位於儲存庫的 db/ 目錄中,格式為 __db.00*

現在儲存庫可以使用 Berkeley DB 4.3。

為何唯讀操作仍需要儲存庫寫入存取權?

某些用戶端操作為「唯讀」,例如檢出和更新。從存取控制的觀點來看,Apache 會將它們視為唯讀。但 libsvn_fs(儲存庫檔案系統 API)仍必須寫入暫時資料才能產生樹狀增量。因此,存取儲存庫的程序始終需要對 Berkeley DB 檔案同時具有讀取寫入存取權才能運作。

特別是,儲存庫會透過比較兩個樹狀結構來回應許多「唯讀」操作。其中一個樹狀結構通常是 HEAD 修訂版本,而另一個通常是暫時交易樹狀結構,因此需要寫入存取權。

此限制僅適用於 Berkeley DB 後端;FSFS 後端 沒有此行為。