我們已經詳細講述了Subversion儲存和檢索版本庫中不同版本的文件和目錄的細節,並且用了好幾個章節來論述這個工具的基本功能。如果對於版本化的支持到此為止,從版本控制的角度來看Subversion已經完整了。
但不僅僅如此。
作為目錄和文件版本化的補充,Subversion提供了對每一個版本化的目錄和文件新增、修改和刪除版本化的Meta資料的介面,我們用屬性來表示這些Meta資料。我們可以認為它們是一個兩列的表,附加到你的工作副本的每個條目上,映射屬性名到任意的值。一般來說,屬性的名稱和值可以是你希望的任何值,限制就是名稱必須是可讀的文字,並且最好的一點是這些屬性也是版本化的,就像你的文字文件內容,你可以像提交文字修改一樣修改、提交和恢復屬性修改,當你更新時也會接收到別人的屬性修改—你不必為適應屬性改變你的工作流程。
Subversion自己保留了一組名稱以svn:開頭的屬性,現在已經有了一些在用的屬性,所以在你根據需要建立自行定義屬性時,需要避免這些前綴開頭的名稱,否則,Subversion的新版本可能會採用同名的屬性來滿足新的特性,而其含義可能會完全不同。
Subversion的屬性也可以在別的地方出現,就像文件和目錄可能附加有任意的屬性名和值,每個修訂版本作為一個整體也可以附加任意的屬性,也有同樣的限制—可讀的文字名稱和任何你希望的二進制值,主要的區別是修訂版本屬性不是版本化的,換句話說,如果你修改,刪除一個修訂版本屬性,在Subversion領域內沒有辦法恢復到以前的值。
Subversion不關心如何使用屬性,但是要求你不要使用svn:為前綴的屬性名,這是Subversion自己使用的命名空間,Subversion使用了版本化的和未版本化的屬性。文件和目錄上的特定版本化屬性都有特別的意義或效果,或者是提供了修訂版本的一些訊息。一些修訂版本屬性會在提交時自動附加到修訂版本上,包含了修訂版本的訊息。大多數這些屬性會作為普通的主題在後面提及,關於Subversion預定義的屬性的詳細列表可以看「Subversion屬性」一節。
在本小節,我們將會檢驗這個工具—不僅是對Subversion的用戶,也對Subversion本身—對於屬性的支持。你會學到與屬性相關的svn子命令,和屬性怎樣影響你的普通Subversion工作流,希望你會感到Subversion的屬性可以提高你的版本控制體驗。
就像Subversion使用屬性保存其包含的文件、目錄和修訂版本的附加訊息,你也會發現屬性有一些類似的使用,你會發現如果在資料附近有個地方保存自行定義Meta資料會非常有用。
假設你希望設計一個存放許多數位照片的網站,會顯示標題和縮略圖。現在你的圖片會經常修改,所以你希望能夠讓這個站點盡量自動處理這些事情,這些照片會很大,所以作為網站,你希望為訪問者提供相似的縮略圖。
現在,你可以利用這些功能使用傳統文件。你可以有一個image123.jpg和一個對應的image123-thumbnail.jpg在同一個目錄裡,有時候你希望保持文件名相同,你可以使用不同的目錄,如thumbnails/image123.jpg。你可以用一種相似的樣式來保存你的標題和時間戳,同原始圖像文件分開。每個新圖片的新增都會成倍的增加混亂,很快你的目錄樹會是一團糟。
現在考慮使用Subversion文件的屬性的方式來管理這個站點,想像我們有一個單獨的圖像文件image123.jpg,然後這個文件的屬性集包括caption、datestamp甚至thumbnail。現在你的工作副本目錄看起來更容易管理—實際上,它看起來只有圖像文件,但是你的自動化腳本知道得更多,它們知道可以用svn(更好的選擇是使用Subversion的語言綁定—見「使用 API」一節)來挖掘更多的站點顯示需要的額外訊息,而不必去閱讀一個索引文件或者是玩一個路徑處理的遊戲。
自行定義修訂版本屬性也經常被使用,一個常見的用法是一個包含問題追蹤ID的屬性,可能是因為這個修改修正了這個ID的問題。另外一些人用屬性來存放更容易記的修訂版本名稱—記住修訂版本1935是一個完全測試的版本是很困難的,但是如果在修訂版本上設定一個值為all passing的test-results屬性,這就有了一個有用的訊息。
svn命令提供一些方法來新增和修改文件或目錄的屬性,對於短的,可讀的屬性,最簡單的新增方法是在propset子命令裡指定正確的名稱和值。
$ svn propset copyright '(c) 2006 Red-Bean Software' calc/button.c property 'copyright' set on 'calc/button.c' $
但是我們已經吹捧了Subversion提供的屬性功能的靈活性,如果你計劃使用多行文字,或者是二進制屬性值,你可能不會希望通過指令列提供這些值,所以propset子命令提供的--file (-F)選項可以指定包含屬性值的文件。
$ svn propset license -F /path/to/LICENSE calc/button.c property 'license' set on 'calc/button.c' $
對於屬性名稱也有一些限制,屬性名必須以一個字元、一個冒號(:)或下劃線(_)開始,之後你可以使用數字,橫線(-)和句號(.)。 [9]
作為propset命令的補充,svn提供了一個propedit命令,這個命令使用客製化的編輯器程序(見「設定」一節)來新增和修改屬性。當你運行這個命令,svn調用你的編輯器程序打開一個臨時文件,文件中保存當前的屬性值(或者是空文件,如果你正在新增新的屬性)。然後你只需要修改為你想要的值,保存臨時文件,然後離開編輯器程序。如果Subversion發現你已經修改了屬性值,就會接受新值,如果你未作任何修改而離開,不會產生屬性修改操作:
$ svn propedit copyright calc/button.c ### exit the editor without changes No changes to property 'copyright' on 'calc/button.c' $
我們也應該注意到,像其它svn子命令一樣,這些關聯的屬性可以一次新增到多個路徑上,這樣就可以通過一個命令修改一組文件的屬性。例如,我們可以:
$ svn propset copyright '(c) 2006 Red-Bean Software' calc/* property 'copyright' set on 'calc/Makefile' property 'copyright' set on 'calc/button.c' property 'copyright' set on 'calc/integer.c' … $
如果不能方便的得到儲存的屬性值,那麼屬性的新增和編輯操作也不會很容易,所以svn提供了兩個子命令來顯示文件和目錄儲存的屬性名和值。svn proplist命令會列出路徑上存在的所有屬性名稱,一旦你知道了某個節點的屬性名稱,你可以用svn propget獲取它的值,這個命令獲取給定的路徑(或者是一組路徑)和屬性名稱,打印這個屬性的值到標準輸出。
$ svn proplist calc/button.c Properties on 'calc/button.c': copyright license $ svn propget copyright calc/button.c (c) 2006 Red-Bean Software
還有一個proplist變種命令會列出所有屬性的名稱和值,只需要設定--verbose(-v)選項。
$ svn proplist -v calc/button.c Properties on 'calc/button.c': copyright : (c) 2006 Red-Bean Software license : ================================================================ Copyright (c) 2006 Red-Bean Software. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the recipe for Fitz's famous red-beans-and-rice. …
最後一個與屬性相關的子命令是propdel,因為Subversion允許屬性值為空,所有不能用propedit或者propset命令刪除一個屬性。例如,這個命令不會產生預期的效果:
$ svn propset license '' calc/button.c property 'license' set on 'calc/button.c' $ svn proplist -v calc/button.c Properties on 'calc/button.c': copyright : (c) 2006 Red-Bean Software license : $
你需要用propdel來刪除屬性,語法與其它與屬性命令相似:
$ svn propdel license calc/button.c property 'license' deleted from 'calc/button.c'. $ svn proplist -v calc/button.c Properties on 'calc/button.c': copyright : (c) 2006 Red-Bean Software $
還記的這些未版本化的修訂版本屬性?你也可以使用svn子命令修改這些屬性。只需要新增--revprop命令參數,說明希望修改屬性的修訂版本。因為修訂版本是全域的,你不需要指定一個路徑,只要你已經位於你希望修改屬性的工作副本路徑,或者,你也可以提供版本庫的URL的任何路徑(也包括版本庫的根URL)。例如,[10]如果你當前的工作路徑是一個版本庫工作副本的一部分,你可以簡單的運行沒有目標路徑的svn propset命令:
$ svn propset svn:log '* button.c: Fix a compiler warning.' -r11 --revprop property 'svn:log' set on repository revision '11' $
但是即使你沒有從版本庫檢出一個工作副本,你仍然可以通過提供版本庫根URL來影響屬性修改。
$ svn propset svn:log '* button.c: Fix a compiler warning.' -r11 --revprop \
http://svn.example.com/repos/project
property 'svn:log' set on repository revision '11'
$
注意,修改這些未版本化的屬性的能力一定要明確的新增給版本庫管理員(見「修正提交消息」一節)。因為屬性沒有版本化,如果編輯的時候不小心,就會冒丟失訊息的風險,版本庫管理員可以設定方法來防範這種意外,預設情況下,修改未版本化的屬性是禁止的。
用戶必須在可能的情況下使用svn propedit,而不是svn propset。然而這兩個命令的結果是相同的,前一個會允許他們查看修改以前的內容,可以幫助用戶驗證,實際上,作出他們所期望的修改,當修改未版本化修訂版本屬性時,這一點特別需要。另外,這個命令也可以通過文字編輯器或指令列輕鬆的修改多行屬性。
現在你已經熟悉了所有與屬性相關的svn子命令,讓我們看看屬性修改如何影響Subversion的工作流。我們前面提到過,文件和目錄的屬性是版本化的,這一點類似於版本化的文件內容。後果之一,就是Subversion具有了同樣的機制來合併—用乾淨或者衝突的方式—其他人的修改應用到你的修改。
就像文件內容,你的屬性修改是本地修改,只有使用svn commit命令提交後才會保存到版本庫中,屬性修改也可以很容易的取消—svn revert命令會恢復你的文件和目錄為編輯前狀態,包括內容、屬性和其它的訊息。另外,你可以使用svn status和svn diff接受感興趣的文件和目錄屬性的狀態訊息。
$ svn status calc/button.c M calc/button.c $ svn diff calc/button.c Property changes on: calc/button.c ___________________________________________________________________ Name: copyright + (c) 2006 Red-Bean Software $
注意status子命令顯示的M在第二列而不是在第一列,這是因為我們修改了calc/button.c的屬性,而不是它的文字內容,如果我們都修改了,我們也會看到M出現在第一列(見「查看你的修改概況」一節)。
你也許已經注意到了Subversion在顯示屬性時的非標準方式。你還可以運行svn diff並且重定向輸出來產生一個有用的補綴(Patch)文件,patch程序會忽略屬性補綴(Patch)—作為規則,它會忽略任何不理解的噪音。很遺憾,這意味著完全應用svn diff產生的補綴(Patch)時,任何屬性修改必須手工實施。
屬性是Subversion一個強大的特性,成為本章和其它章討論的許多Subversion特性的關鍵組成部分—文字區別和合併支持、關鍵字替換、新行的自動轉換等等。但是為了從屬性得到完全的利益,他們必須設定到正確的文件和目錄。不幸的是,在日常工作中很容易忘記這一步工作,特別是當沒有設定屬性不會引起明顯的錯誤時(至少相對與未能新增一個文件到版本控制這種操作),為了幫助你在需要新增屬性的文件上新增屬性,Subversion提供了一些簡單但是有用的特性。
當你使用svn add或是svn import準備加入一個版本控制的文件時,Subversion會自動運行一個基本探測來檢查文件是包含了可讀還是不可讀的內容,首先,在支持執行允許位的操作系統,Subversion會自動會為設定執行位的文件設定svn:executable屬性(更多訊息見「文件的可執行性」一節)。第二,它會運行非常基礎的啟髮式檢查來檢測文件是否可讀,如果不是,Subversion會自動設定文件的svn:mime-type屬性為application/octet-stream(原始的「一組字節」的MIME類型)。如果Subversion猜測錯誤,或者是你希望使用svn:mime-type屬性更精確的設定—或許是image/png或者application/x-shockwave-flash—你可以一直刪除或編輯那個屬性(關於Subversion使用MIME類型的更多訊息,見「文件內容類型」一節。)
Subversion也通過運行設定系統(見「運行設定區」一節)提供了自動屬性特性,允許你建立文件名到屬性名稱與值影射,這個影射在你的運行設定區域設定,它們會影響新增和匯入操作,而且不僅僅會覆蓋Subversion所有預設的MIME類型判斷操作,也會設定額外的Subversion或者自行定義的屬性。舉個例子,你會建立一個影射文件說在任何時候你新增了一個JPEG文件—一些符合*.jpg的文件—Subversion一定會自動設定它們的svn:mime-type屬性為image/jpeg。或者是任何匹配*.cpp的文件,必須把svn:eol-style設定為native,並且svn:keywords設定為Id。自動屬性支持是Subversion工具箱中屬性相關最垂手可得的工具,見「設定」一節來查看更多的設定支持。