我們已經詳細講述了Subversion存儲和檢索版本庫中不同版本的文件和目錄的細節,並且用了好幾個章節來論述這個工具的基本功能。如果對於版本化的支持到此為止,從版本控制的角度來看Subversion已經完整了。
但不僅僅如此。
作為目錄和文件版本化的補充,Subversion提供了對每一個版本化的目錄和文件添加、修改和刪除版本化的元數據的接口,我們用屬性來表示這些元數據。我們可以認為它們是一個兩列的表,附加到你的工作拷貝的每個條目上,映射屬性名到任意的值。一般來說,屬性的名稱和值可以是你希望的任何值,限制就是名稱必須是可讀的文本,並且最好的一點是這些屬性也是版本化的,就像你的文本文件內容,你可以像提交文本修改一樣修改、提交和恢復屬性修改,當你更新時也會接收到別人的屬性修改—你不必為適應屬性改變你的工作流程。
Subversion自己保留了一組名稱以svn:
開頭的屬性,現在已經有了一些在用的屬性,所以在你根據需要創建自定義屬性時,需要避免這些前綴開頭的名稱,否則,Subversion的新版本可能會采用同名的屬性來滿足新的特性,而其含義可能會完全不同。
Subversion的屬性也可以在別的地方出現,就像文件和目錄可能附加有任意的屬性名和值,每個修訂版本作為一個整體也可以附加任意的屬性,也有同樣的限制—可讀的文本名稱和任何你希望的二進制值,主要的區別是修訂版本屬性不是版本化的,換句話說,如果你修改,刪除一個修訂版本屬性,在Subversion領域內沒有辦法恢復到以前的值。
Subversion不關心如何使用屬性,但是要求你不要使用svn:
為前綴的屬性名,這是Subversion自己使用的命名空間,Subversion使用了版本化的和未版本化的屬性。文件和目錄上的特定版本化屬性都有特別的意義或效果,或者是提供了修訂版本的一些信息。一些修訂版本屬性會在提交時自動附加到修訂版本上,包含了修訂版本的信息。大多數這些屬性會作為普通的主題在后面提及,關於Subversion預定義的屬性的詳細列表可以看“Subversion屬性”一節。
在本小節,我們將會檢驗這個工具—不僅是對Subversion的用戶,也對Subversion本身—對於屬性的支持。你會學到與屬性相關的svn子命令,和屬性怎樣影響你的普通Subversion工作流,希望你會感到Subversion的屬性可以提高你的版本控制體驗。
就像Subversion使用屬性保存其包含的文件、目錄和修訂版本的附加信息,你也會發現屬性有一些類似的使用,你會發現如果在數據附近有個地方保存自定義元數據會非常有用。
假設你希望設計一個存放許多數碼照片的網站,會顯示標題和縮略圖。現在你的圖片會經常修改,所以你希望能夠讓這個站點盡量自動處理這些事情,這些照片會很大,所以作為網站,你希望為訪問者提供相似的縮略圖。
現在,你可以利用這些功能使用傳統文件。你可以有一個image123.jpg
和一個對應的image123-thumbnail.jpg
在同一個目錄里,有時候你希望保持文件名相同,你可以使用不同的目錄,如thumbnails/image123.jpg
。你可以用一種相似的樣式來保存你的標題和時間戳,同原始圖像文件分開。每個新圖片的添加都會成倍的增加混亂,很快你的目錄樹會是一團糟。
現在考慮使用Subversion文件的屬性的方式來管理這個站點,想象我們有一個單獨的圖像文件image123.jpg
,然后這個文件的屬性集包括caption
、datestamp
甚至thumbnail
。現在你的工作拷貝目錄看起來更容易管理—實際上,它看起來只有圖像文件,但是你的自動化腳本知道得更多,它們知道可以用svn(更好的選擇是使用Subversion的語言綁定—見“使用API”一節)來挖掘更多的站點顯示需要的額外信息,而不必去閱讀一個索引文件或者是玩一個路徑處理的游戲。
自定義修訂版本屬性也經常被使用,一個常見的用法是一個包含問題跟蹤ID的屬性,可能是因為這個修改修正了這個ID的問題。另外一些人用屬性來存放更容易記的修訂版本名稱—記住修訂版本1935是一個完全測試的版本是很困難的,但是如果在修訂版本上設置一個值為all passing
的test-results
屬性,這就有了一個有用的信息。
可搜索性(或者,為什么不使用屬性)
對於Subversion屬性的所有功能—或者更准確的講,對於屬性的所有接口—都有一些主要的應用會削弱他們的應用。設置一個自定義屬性后,很容易發現屬性完全變成另外一會兒事。
為了定位一個自定義屬性通常要線形訪問版本庫的所有修訂版本,向每個修訂版本詢問,“你們有我找的屬性嗎?”嘗試查找自定義版本化屬性也是同樣的痛苦,通常需要在整個工作拷貝遞歸調用svn propget。在你的情況下,可能不會比遍歷所有修訂版本差。但也在性能和成功可能性里留下了許多懸念,特別是當你需要從版本庫的根開始搜索時。
因為這個原因,你會選擇—特別是在修訂版本屬性用例—簡單的添加你的元數據到修訂版本日志信息,使用一些政策驅動(並且是編程強制的)且可以通過svn log快速解析的格式。如下的Subversion日志信息會很常見:
Issue(s): IZ2376, IZ1919 Reviewed by: sally This fixes a nasty segfault in the wort frabbing process …
但是現在依然有一些不幸,Subversion不支持日志信息模版機制,雖然這樣對用戶與日志嵌入的修訂版本元數據保持一致有很大幫助。
Manipulating Properties
The svn program affords a few ways to add or modify file and directory properties. For properties with short, human-readable values, perhaps the simplest way to add a new property is to specify the property name and value on the command line of the svn propsetsubcommand:
svn命令提供一些方法來添加和修改文件或目錄的屬性,對於短的,可讀的屬性,最簡單的添加方法是在propset子命令里指定正確的名稱和值
$ svn propset copyright '(c) 2006 Red-Bean Software' calc/button.c //red-bean之所以要加‘ ’,是應為有空格。空格會顯示在屬性里。查看value時會顯示 '(c) 2006 Red-Bean Software'
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 $
remember those unversioned revision properties?還記的這些未版本化的修訂版本屬性?你也可以使用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。然而這兩個命令的結果是相同的,前一個會允許他們查看修改以前的內容,可以幫助用戶驗證,實際上,作出他們所期望的修改,當修改未版本化修訂版本屬性時,這一點特別需要。另外,這個命令也可以通過文本編輯器或命令行輕松的修改多行屬性。
屬性和 Subversion 工作流程
現在你已經熟悉了所有與屬性相關的svn子命令,讓我們看看屬性修改如何影響Subversion的工作流。我們前面提到過,文件和目錄的屬性是版本化的,這一點類似於版本化的文件內容。后果之一,就是Subversion具有了同樣的機制來合並—用干凈或者沖突的方式—其他人的修改應用到你的修改。Subversion provides the same opportunities for merging—cleanly or with conflicts—someone else's modifications into your own.
就像文件內容,你的屬性修改是本地修改,只有使用svn commit命令提交后才會保存到版本庫中,屬性修改也可以很容易的取消—svn revert命令會恢復你的文件和目錄為編輯前狀態,包括內容、屬性和其它的信息。另外,你可以使用svn status和svn diff接受感興趣的文件和目錄屬性的狀態信息。
$ svn status calc/button.c M calc/button.c //M在第二列,就是說前面有一個空格 $ svn diff calc/button.c Property changes on: calc/button.c ___________________________________________________________________ Name: copyright + (c) 2006 Red-Bean Software $
注意status子命令顯示的M
在第二列而不是在第一列,這是因為我們修改了calc/button.c
的屬性,而不是它的文本內容,如果我們都修改了,我們也會看到M
出現在第一列(見“查看你的修改概況”一節)。如果屬性和內容都修改了,會顯示MM。
屬性沖突
與文件內容一樣,本地的屬性修改也會同別人的提交沖突,如果你更新你的工作拷貝目錄並且接收到有資源屬性修改與你的修改沖突,Subversion會報告資源處於沖突狀態。
% svn update calc M calc/Makefile.in C calc/button.c Updated to revision 143. $
Subversion也會在沖突資源的同一個目錄創建一個.prej
擴展名的文件,保存沖突的細節。你一定要檢查這個文件的內容來決定如何解決沖突,在你解決沖突之前,你會在使用svn status時看到這個資源的輸出的第二列是一個C
,提交本地修改的嘗試會失敗。
$ svn status calc C calc/button.c ? calc/button.c.prej $ cat calc/button.c.prej prop 'linecount': user set to '1256', but update set to '1301'. $
為了解決屬性沖突,只需要確定沖突的屬性保存了它們應該的值,然后使用svn resolved命令告訴Subversion你已經手工解決了問題。
你也許已經注意到了Subversion在顯示屬性時的非標准方式。你還可以運行svn diff並且重定向輸出來產生一個有用的補丁文件,patch程序會忽略屬性補丁—作為規則,它會忽略任何不理解的噪音。很遺憾,這意味着完全應用svn diff產生的補丁時,任何屬性修改必須手工實施。
屬性是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工具箱中屬性相關最垂手可得的工具,見“配置”一節來查看更多的配置支持
參考:http://svnbook.red-bean.com/en/1.5/svn-book.html#svn.advanced.props
http://www.subversion.org.cn/svnbook/1.4/svn.advanced.props.html