作者:Zoom.Quiet
本文包含了創建和使用Subversion 進行軟件開發的基本知識,為有志于使用Subversion 這一方便的版本管理工具來支持規范化團隊軟件開發的程序員,在進行分布式協同開發時,如何組織版本控制提供了基礎的建議和實用技巧;
當前最新版本是 1.5.5, SVN支持在各種操作系統中運行,安裝前請從官方網站下載對應版本; 本文將以 Ubuntu 系統為例進行說明.
一個 7.04 以上版本的Ubuntu 環境,有root 權限即可;
因為SVN 已經包含在 Ubuntu 軟件倉庫中,安裝SVN 僅需一個命令:
$ sudo apt-get install subversion
如果系統報告了依賴關系的錯誤,請找出相應的軟件包并安裝它們。如果存在其它問題,也請自行解決。如果您是再不能解決這些問題,可以考慮通過 Ubuntu 的網站、Wiki、論壇或郵件列表尋求支持。
SVN 可以提供多種協議的訪問渠道,以下是模式列表:
模式 | 訪問方法 |
---|---|
file:/// | 直接訪問本地硬盤上文件倉庫 |
http:// | 通過 WebDAV 協議訪問支持 Subversion 的 Apache 2 Web 服務器 |
https:// | 類似 http://,支持 SSL 加密 |
svn:// | 通過自帶協議訪問 svnserve 服務器 |
svn+ssh:// | 類似 svn://,支持通過 SSH 通道 |
$ svnadmin create /path/to/svn/myproj
$ svnserve -d -r /path/to/svn
# 本地訪問 $ svn co svn://localhost/myproj # 遠程訪問 $ svn co svn://host.example.org/myproj # 即刻下載,建立了本地工作復本,可以進行協同開發了
事實上在網絡中有很多SVN的免費空間可以使用,其中 http://code.google.com/intl/zh/ 是一個較輕便卻完備的的項目管理環境,只要注冊成功一個項目空間,就同時獲得了一個維基,一個Issue ~ 提案追蹤環境,和一個SVN倉庫;
# 項目成員可寫訪問命令是 $ svn co https://openbookproject.googlecode.com/svn/trunk/ openbookproject --username Zoom.Quiet # 外部匿名讀者只訪問命令是 $ svn co http://openbookproject.googlecode.com/svn/trunk/ openbookproject-read-only
如果沒有方便的主機資源,又想聯合分布在各地的朋友共同來進行協同式軟件項目開發的話,可以考慮使用 Google 公司貢獻的這一服務.
SVN 本身提供了豐富的管理工具, 在系統配置方面,僅僅有少量文件用以聲明關鍵信息.
在倉庫目錄的 conf 目錄中 svnserve.conf
是關鍵配置文件:
... [general] # 聲明匿名用戶權限 read|write anon-access = read # 聲明登錄用戶權限 read|write auth-access = write # 聲明登錄用戶口令信息文件 password-db = passwd.cfg # 聲明登錄用戶倉庫訪問權限 authz-db = authz.cfg ...
配合svnserve.conf
的聲明, SVN 通過理解兩個文件來對倉庫的訪問進行控制:
聲明的口令文件,定義了權限用戶和口令:
[users] # 用戶名=口令 的格式來逐行聲明用戶賬號 woodpecker = 1q2w3e4r@woodpecker.org ...
聲明的認證文件,定義了權限用戶組和倉庫不同部分的訪問控制:
[groups] # 聲明用戶組 repomana 包含了幾個用戶 repomana = woodpecker,zoomq # 倉庫目錄權限聲明 [倉庫名:目錄名] 格式引導多個權限聲明 [woodpecker:/] # * 代表任何人 * = r # repoman 組成員可以讀寫 @repomana = rw [woodpecker:/foo] # 任何人可寫 * = rw # river 用戶只讀 river = r ...
作為標準意義上的版本管理系統,SVN 和其它任何版本管理系統日常使用并沒有什么巨大的不同,是一個非常容易上手的工具系統;
以命令行形式說明日常通過SVN 進行協同開發時最常用的操作:
$ svn up
$ svn add
~ 增補文件/目錄
$ svn del
~ 刪除文件/目錄
$ svn cp
~ 復制文件/目錄
$ svn mv
~ 移動文件/目錄
--help
獲得充分的指示,例如:
$ svn mv --help move (mv, rename, ren): 在工作副本或版本庫中移動或改名文件或目錄。 用法: move SRC... DST 當移動多個源時,它們作為 DST 的子節點增加,DST 必須是目錄。 注意: 本子命令等同于先 “copy”,然后 “delete”。 注意: 此命令中 --revision 選項沒有作用,已經淘汰。 SRC 可同時為工作副本(WC) 路徑或 URL: WC -> WC : 移動并加入新增調度 (連同歷史記錄) URL -> URL : 完全是服務器端更名。 所有 SRC 必須是同一類型。 有效選項: -r [--revision] ARG : ARG (一些命令也接受ARG1:ARG2范圍) 版本參數可以是如下之一: NUMBER 版本號 '{' DATE '}' 在指定時間以后的版本 'HEAD' 版本庫中的最新版本 'BASE' 工作副本的基線版本 'COMMITTED' 最后提交或基線之前 'PREV' COMMITTED的前一版本 -q [--quiet] : 不打印信息,或只打印概要信息 --force : 強制操作運行 --parents : 創建中間目錄 -m [--message] ARG : 指定日志信息ARG -F [--file] ARG : 從文件ARG讀取日志信息 --force-log : 強制校驗日志信息資源 --editor-cmd ARG : 使用 ARG 作為外部編輯器 --encoding ARG : 將ARG的值視為字符編碼 --with-revprop ARG : 在新版本設置版本屬性 ARG 使用格式 name[=value]
$ svn revert
revert: 將工作副本文件恢復到原始版本(恢復大部份的本地修改)。 用法: revert PATH... 注意: 本子命令不會訪問網絡,它解除任何沖突的狀態。 但是,它不恢復被刪除的目錄。 有效選項: --targets ARG : 傳遞文件 ARG 內容為附件參數 -R [--recursive] : 向下遞歸,與 --depth=infinity 相同 --depth ARG : 受深度參數 ARG(“empty”,“files”,“immediates”,或“infinity”) 約束的操作 -q [--quiet] : 不打印信息,或只打印概要信息 --changelist ARG : 只能對修改列表 ARG 成員操作 [aliases: --cl]
$ svn resolved
resolved: 刪除工作副本中目錄或文件的“沖突”狀態。 用法: resolved PATH... 注意: 本子命令不會依語法來解決沖突或是刪除沖突標記;它只是刪除沖突相關的 附加文件,讓 PATH 可以被再次提交。它已經過時,被 “svn resolve --accept working”取代。 有效選項: --targets ARG : 傳遞文件 ARG 內容為附件參數 -R [--recursive] : 向下遞歸,與 --depth=infinity 相同 --depth ARG : 受深度參數 ARG(“empty”,“files”,“immediates”,或“infinity”) 約束的操作 -q [--quiet] : 不打印信息,或只打印概要信息
$ svn up C sandwich.txt Updated to revision 2. $ ls -1 sandwich.txt sandwich.txt.mine sandwich.txt.r1 sandwich.txt.r2
sandwich.txt
,直到你解決沖突,可選的處置是:
svn revert <filename>
來放棄所有的本地修改
<filename>.r*
代表的是文件的第幾個版本
<filename>.mine
代表的是本地我的文件版本
<filename>
是包含沖突標識的提示文件
$ svn ci -m "提交理由"
然后,就是以上過程的不斷循環
特別的,對于從CVS系統遷移過來的用戶,需要提升一些關鍵概念,來更好的使用 SVN:
“修訂版本54”
時,他們是在討論一個特定的樹(并且間接來說,文件系統在提交54次之后的樣子)。
“文件foo.c的修訂版本5”
是不正確的,相反,一個人會說“foo.c在修訂版本5出現”
。同樣,我們在假定文件的進展時也要小心,在CVS,文件foo.c的修訂版本5和6一定是不同的,在Subversion,foo.c可能在修訂版本5和6之間沒有改變。
svn add
和svn delete
現在也工作在目錄上了,就像在文件上一樣,還有svn copy
和svn move
也一樣;然而,這些命令不會導致版本庫即時的變化,相反,工作的項目只是“預定要”添加和刪除,在運行svn commit
之前沒有版本庫的修改
cvs status
和cvs update
之間的混亂。
cvs status
命令有兩個目的:
cvs update
或cvs -n update
來快速查看區別,如果用戶忘記使用-n
選項,副作用就是將還沒有準備好處理的版本庫修改合并到工作拷貝。
svn status
的輸出使之同時滿足閱讀和解析的需要來努力消除這種混亂,同樣,svn update
只會打印將要更新的文件信息,而不是本地修改
status (stat, st): 顯示工作副本中目錄與文件的狀態 用法: status [PATH...] 未指定參數時,只顯示本地修改的條目(沒有網絡訪問)。 使用 -q 時,只顯示本地修改條目的摘要信息。 使用 -u 時,增加工作版本和服務器上版本過期信息。 使用 -v 時,顯示每個條目的完整版本信息。 輸出的前六欄各占一個字符寬度: 第一欄: 表示一個項目是增加、刪除,還是修改 “ ” 無修改 “A” 增加 “C” 沖突 “D” 刪除 “I” 忽略 “M” 改變 “R” 替換 “X” 未納入版本控制,但被外部項目所用 “?” 未納入版本控制 “!” 該項目已遺失(被非 svn 命令刪除)或不完整 “~” 版本控制下的項目與其它類型的項目重名 第二欄: 顯示目錄或文件的屬性狀態 “ ” 無修改 “C” 沖突 “M” 改變 第三欄: 工作副本目錄是否被鎖定 “ ” 未鎖定 “L” 鎖定 第四欄: 已調度的提交是否包含副本歷史 “ ” 沒有包含 “+” 包含 第五欄: 該條目相對其父目錄是否已切換 “ ” 正常 “S” 已切換 第六欄: 版本庫鎖定標記 (沒有 -u) “ ” 沒有鎖定標記 “K” 存在鎖定標記 (使用 -u) “ ” 沒有在版本庫中鎖定,沒有鎖定標記 “K” 在版本庫中被鎖定,存在鎖定標記 “O” 在版本庫中被鎖定,鎖定標記在一些其他工作副本中 “T” 在版本庫中被鎖定,存在鎖定標記但已被竊取 “B” 沒有在版本庫中被鎖定,存在鎖定標記但已被終止 是否過期的信息出現的位置是第八欄(與 -u 并用時): “*” 服務器上有更新版本 “ ” 工作副本是最新版的 剩余的欄位皆為變動寬度,并以空白隔開: 工作版本號(使用 -u 或 -v 時) 最后提交的版本與最后提交的作者(使用 -v 時) 工作副本路徑總是最后一欄,所以它可以包含空白字符。 范例輸出: svn status wc M wc/bar.c A + wc/qax.c svn status -u wc M 965 wc/bar.c * 965 wc/foo.c A + 965 wc/qax.c Status against revision: 981 svn status --show-updates --verbose wc M 965 938 kfogel wc/bar.c * 965 922 sussman wc/foo.c A + 965 687 joe wc/qax.c 965 687 joe wc/zig.c Status against revision: 981 有效選項: -u [--show-updates] : 顯示更新信息 -v [--verbose] : 打印附加信息 -N [--non-recursive] : 過時;嘗試 --depth=files 或 --depth=immediates --depth ARG : 受深度參數 ARG(“empty”,“files”,“immediates”,或“infinity”) 約束的操作 -q [--quiet] : 不打印信息,或只打印概要信息 --no-ignore : 忽略默認值和 svn:ignore 屬性 --incremental : 給予適合串聯的輸出 --xml : 輸出為 XML --ignore-externals : 忽略外部項目 --changelist ARG : 只能對修改列表 ARG 成員操作 [aliases: --cl]
分支自然可見了!
而標簽不必要了!
$ svn cp trunk branches/my-proj-branch_0.1
changeset
(修訂集)來使用的標簽
在SVN 中,版本號天然就包含了這一特性, 完全可以用版本號來當 標簽用!
因為Subversion把分支和標簽看作普通目錄看待,一直要記住檢出項目的trunk(http://svn.example.com/repos/calc/trunk/), 而不是項目本身的(http://svn.example.com/repos/calc/)。 如果你錯誤的檢出了項目本身,你會緊張的發現你的項目拷貝包含了所有的分支和標簽
SVN 有豐富的客戶端軟件可以選擇,一般命令行內置工具已經足夠好用,但是對習慣窗口界面的人,SVN 也有很多選擇,其中最穩定和友好的是官方社區創建的:
建議Windows 中的用戶下載體驗;
SVN 作為成熟的版本管理系統,可以支持各種級別的開發支持; 當面對大型復雜系統開發時,作為基礎配置管理支持系統,必須擁有一些高級功能來支撐復雜業務,這里介紹幾方面常用知識;
整個過程隨著軟件的成熟不斷重復:
$ cd trunk-working-copy $ svn update At revision 1910. $ svn merge http://svn.example.com/repos/calc/trunk@1910 http://svn.example.com/repos/calc/branches/mybranch@1910 U real.c U integer.c A newdirectory A newdirectory/newfile …通過比較HEAD修訂版本的主干和HEAD修訂版本的分支,你確定了只在分支上的增量信息,兩條開發線都有了分枝的修改。
和CVS 類似SVN 同樣為自動化事務響應開辟有"HOOKS"~鉤子腳本支持;只是更加精簡和規范化了;
一般提供9類標準鉤子模板:
$ ls repos/hooks/ post-commit.tmpl post-unlock.tmpl pre-revprop-change.tmpl post-lock.tmpl pre-commit.tmpl pre-unlock.tmpl post-revprop-change.tmpl pre-lock.tmpl start-commit.tmpl
分別響應核心的四類操作:
HOOK | 觸發事件 | 參數 |
---|---|---|
start-commit | 提交事務產生前 | REPOS-PATH:到版本庫的路徑;USER:要進行提交的用戶名 |
pre-commit | 事務完成提交之前 | REPOS-PATH:版本庫的路徑;TXN-NAME正在提交的事務名稱 |
post-commit | 事務完成后 | REPOS-PATH:到版本庫的路徑;REV:被創建的新的修訂版本號 |
pre-revprop-change | 修訂版本屬性變更前 | REPOS-PATH:到版本庫的路徑;REVISION:要修改屬性的修訂版本;USER:經過認證的用戶名;ACTION:屬性自身的名字 |
post-revprop-change | 修訂版本屬性被改變之后 | REPOS-PATH:到版本庫的路徑;REVISION:屬性存在的修訂版本;USER:經過校驗的產生變化的用戶名;ACTION:和屬性自身的名字 |
pre-lock | 嘗試鎖定文件時 | REPOS-PATH:到版本庫的路徑;PATH:鎖定的路徑;USER:企圖執行鎖定的用戶 |
post-lock | 路徑被鎖定后執行 | REPOS-PATH:到版本庫的路徑;USER:企圖執行鎖定的用戶 |
pre-unlock | 企圖刪除一個文件上的鉤子時 | REPOS-PATH:到版本庫的路徑;PATH:鎖定的路徑;USER:企圖解鎖的用戶 |
post-unlock | 路徑被解鎖后 | REPOS-PATH:到版本庫的路徑;USER:企圖解鎖的用戶 |
pre-commit
鉤子的事務,在不滿足要求時拒絕提交。
舉個實用的HOOKS 腳本實例:
pre-commit.tmpl
重命名為:pre-commit
并修訂為以下內容:
#!/bin/sh # PRE-COMMIT HOOK REPOS="$1" TXN="$2" SVNLOOK=/usr/local/bin/svnlook $SVNLOOK log -t "$TXN" "$REPOS" | grep "[a-zA-Z0-9]" > /dev/null if [ $? != 0 ]; then echo "$TXN $REPOS" 1>&2 echo "Alert! Commit message may not be empty." 1>&2 exit 1 fi exit 0
"Alert! Commit message may not be empty."
SVN作為基礎配置管理支撐系統,可以輕快的完成版本管理的全方位支持了,而且,進一步的配合Trac 可以完成項目管理的大部分流程支持!
Trac 是種輕型全功能項目管理環境,主要特性有:
詳細的敬請期待哲思手冊相關文章;
PS:
Trac中文化項目長期由 Zoom.Quiet 團隊支持,推薦體驗;