SVN 學習筆記二(一口氣學會SVN)
我們可能希望一來就直接操作。列出一堆命令。詳細的命令引數等資訊,我們都可以加入 --help 選項獲取,下面不會詳細介紹。除非必要。現在先看下面的例子:
$svn --help
usage: svn <subcommand> [options] [args]
Subversion command-line client, version 1.6.12.
Type 'svn help <subcommand>' for help on a specific subcommand.
Type 'svn --version' to see the program version and RA modules
or 'svn --version --quiet' to see just the version number.
Most subcommands take file and/or directory arguments, recursing
on the directories. If no arguments are supplied to such a
command, it recurses on the current directory (inclusive) by default.
Available subcommands:
add
blame (praise, annotate, ann)
cat
changelist (cl)
checkout (co)
cleanup
commit (ci)
copy (cp)
delete (del, remove, rm)
diff (di)
export
help (?, h)
import
info
list (ls)
lock
log
merge
mergeinfo
mkdir
move (mv, rename, ren)
propdel (pdel, pd)
propedit (pedit, pe)
propget (pget, pg)
proplist (plist, pl)
propset (pset, ps)
resolve
resolved
revert
status (stat, st)
switch (sw)
unlock
update (up)
Subversion is a tool for version control.
好了,什麼都出來了。一大堆資訊。慢慢讀吧。可是這樣的方式,對我們使用SVN並無指導意義。什麼時候用什麼命令? 下面就來說一下SVN的基本使用,在此之前,還有兩個重要的東西需要理解。
SVN 除了可以讓你追溯歷史,還有一個重要的功能,便是多人協作。我們要解決的問題不僅僅是可以從歷史中恢復。還有如果多人同時修改一個檔案,那麼該以誰的為主呢?
所以在SVN中,我們有兩種使用模式:
Lock-Modify-Unlock
簡單的說就是,給需要修改的檔案加鎖,然後修改,然後解鎖。
這是一個很好的辦法。但是如果一個檔案被鎖住了,那麼其他人就不能修改了。而此時如果是我在修改檔案頭,而你需要修改檔案末尾的話,你也只能等我修改完。這樣是很浪費你的時間的。所以我們又有另外一種模式。
Copy-Modify-Merge
這是一種很高階的模式,從庫中拷貝一份,修改,然後根據拷貝的和庫中的不同,在合併。為什麼說高階呢,因為合併是一個很複雜的過程。很可能失敗。但是這種方法卻儘可能使大家不受影響。例如你和我同時修改一個檔案,我改檔案頭,你改檔案尾,然後一提交,就給合成一份了。不會互相打擾。事實上問題比這複雜的多。
好了,說了這麼多廢話。我們可以正式開始了。
雖然一般情況,我們是不用自己去建立一個SVN庫的,現在為了說明流暢,我們從建立一個庫開始。
$svnadmin create /var/idp/repos
於是我們建立了一個SVN庫。到下面看看
$ls /var/idp/repos
conf db format hooks locks README.txt
我們的庫就建立好了。這裡不多說, svnadmin是一個高階命令,我們基本用不到。
匯入需要管理的檔案:
$svn import /home/madic/code file:///var/idp/repos -m "init code"
Adding /home/madic/code/signo
Adding /home/madic/code/signo/sigset.c
Adding (bin) /home/madic/code/signo/wait
Adding /home/madic/code/signo/wait.c
Committed revision 1.
這裡版本變為1,初始版本為0。 每次對庫的操作改變,都會產生一個新的版本。版本是我們追溯歷史的一個索引。在版本管理中非常重要。當前庫中最新的版本可以用HEAD表示。HEAD版也就是庫中最新版本。
我們把 /home/madic/code 檔案下的檔案目錄都匯入了svn庫,從此,他們就被時光機管理,資料永不丟失(當然你幹掉時光機,資料還是會丟失的)。
注意 (bin) 表示這是一個二進位制檔案,非文字檔案。
除了import 外,我們還可以用 svn add 新增檔案。
使用list命令檢視庫中檔案
$svn list file:///var/idp/repos
signo/
signo/sigset.c
signo/wait
signo/wait.c
現在,我們開始工作了。那麼,就使用 CMC(Copy-Modify-Merge)模式吧。
如何建立一個Working Copy 呢?看:
$svn checkout file:///var/idp/repos /home/madic/code_svn
A /home/madic/code_svn/signo
A /home/madic/code_svn/signo/sigset.c
A /home/madic/code_svn/signo/wait
A /home/madic/code_svn/signo/wait.c
Checked out revision 1.
恭喜我們現在擁有一個Working Copy了,你就在這個WorkingCopy中折騰吧,只要不提交,那麼對庫來說就沒有任何影響。就算你用了 rm 不小心刪除了某個檔案,不用著急。使用update便可以找回。
$svn update
svn update
Restored 'main.c'
At revision 1.
這裡,我們刪掉 main.c 然後到WC 下,執行 svn update 命令,就找回main.c了。
在Working Copy 目錄中,Subversion如何知道檔案的情況呢,其實這些都是 .svn的功勞。每個SVN管理的WC中,都會有一個隱藏的資料夾,.svn
$ls -la .svn
drwxr-xr-x 6 madic madic 4096 2011-07-26 11:00 .svn
如果不小心誤刪除,也可以用svn update恢復。
接下來,我們開始正常的編輯檔案。編輯之前,已定要使用svn update 來確保你編輯的檔案是最新的。如果不是最新的,那麼這個檔案就是 Out-of-date了,此時你的編輯就不能被提交到庫中。編輯時,你不必使用svn的命令了。你可以用任何編輯器編輯檔案。當你編輯完成後儲存。
$svn status -q
M readme.txt
這個M表示此檔案被修改了。於是我們需要把她提交到庫,這樣別人才能看到我修改的東西。
$svn commit -m "我修改了檔案內容" readme.txt
svn commit -m "modify" readme.txt
Sending readme.txt
Transmitting file data .
Committed revision 8.
檔案被提交,版本更新到8.
這樣,我們就完成了一個最基本的SVN操作流程。也許如果沒有什麼大事,我們就到此結束了。難道還有什麼問題嗎?
上面提到,我們在修改的同時,可能別人也在修改。所以要儘量在每次修改的時候,保持我們的WC和庫中的是同步的,也就是最新的。我們使用svn update來使自己的working copy是最新的。我們也可以用一個新的命令來看WC的狀態。
$svn status -u -v readme.txt
M 8 8 madic readme.txt
M * 8 3 madic foo.c
我們看到readme.txt 目前是M(modify)狀態,說明此檔案被改了。當前版本和最新版本都是8 ,使用者是madic。
而foo.c 多了個星號,這表明foo.c 已經out-of-date 了。也就是說,我們在修改的版本,已經不是最新的了。在我們修改的時候,已經有人提交了新的版本。
除了 M表示修改,還有 U表示更新,D表示刪除,A 表示新增, C表示衝突。
有時候有兩個MM,此時並非表示美眉,而是檔案的內容和屬性都被改變了。
同樣UU表示屬性和內容都更新了。
所以,在我們提交以後,並非就結束了,此時,我們需要檢視一下狀態。如果有檔案處於C狀態,那麼說明我們遇到麻煩了。因為C表示衝突了,一定是某個人和我們在改同一個地方。
這時,最好的辦法是直接找到和我們衝突的修改人。然後溝通吧。是你死還是我亡。衝突實際上是在svn update的時候發生的。由於我編輯的太久了,你已經提交了一個新版本,我提交的時候,提示 out-of-date了,於是我svn update,衝突出現:
$ svn update
Conflict discovered in 'readme.txt'.
Select: (p) postpone, (df) diff-full, (e) edit,
(mc) mine-conflict, (tc) theirs-conflict,
(s) show all options:
這時幾個選擇出現了,postpone 的意思是暫時推後處理,我可能要和那個和我衝突的傢伙商量一番。 diff-full,則是比比看,到底什麼地方衝突了。edit,修改衝突合併的檔案。 mc,這個霸道,直接用我的。 tc , 底氣不足,還是用別人修改的吧。我們一切三思而後行,所以選擇了p,然後在看看檔案目錄下有什麼。
多了三個檔案:
readme.txt.mine readme.txt.r9readme.txt readme.txt.r8
我們來說說這三個檔案:readme.txt.mine 後最 mine是本地最新的。
readme.txt.r9 很明顯,是版本9的,這個版本正式庫中最新的版本。
readme.txt.r8 這個版本是庫中最新的版本的前一版本。
我們來看一下,現在的readme.txt
$cat readme.txt
<<<<<<< .mine
hi
=======
hello
>>>>>>> .r9
很明顯,我的版本中是hi ,而r9 的是hello。
好吧,我明白了。現在假設我們很明白,或者已經和發生衝突的檔案的編輯同事商量好了。我們就要解決衝突了。
首先,上面說的三個檔案,如果存在,我們就提交不了。
其次,需要選擇一個解決方法。
$svn resolve --accepting working reademe.txt
svn resolve 是解決衝突的命令。解決的方法由--accepting 選項決定。
base 恢復到衝突前的一個版本。
mine-full 恢復到以我的修改為主的版本
their-full 恢復到庫中最新版本
working 手動解決
所以,上面的那句命令其實還有問題,因為我們還沒有手工修改檔案。
於是我們開啟readme.txt,去掉哪些衝突標識
<<<<<<< .mine
hi
=======
hello
>>>>>>> .r9
修改為
No hi no hello
然後儲存readme.txt
在使用
$svn resolve --accepting working reademe.txt
注意,這一步以後,並沒有真正完成衝突解決。
$svn commit -m "conflict resole"
Sending readme.txt
Transmitting file data .
Committed revision 10.
這次提交OK。衝突至此解決。
有時候,我們編寫到一半發現有人提交了更新或者是越寫越亂,我們想放棄這次編輯,恢復到上一個版本,當然,我們可以直接rm掉,然後update,我們也可以這樣:
$svn revert readme.txt
Reverted 'readme.txt'
問題解決以後,請使用svn status 檢視一下狀態,是否正常了。
$svn status -vu readme.txt
10 10 yinshaoxin readme.txt
Status against revision: 10
沒有什麼M,C,* ,D, ? 這些,說明狀態正常。
對於我們操作的這些,我們可以通過歷史svn log來檢視狀態。
$svn log
r9 | yinshaoxin | 2011-07-26 13:39:12 +0800 (Tue, 26 Jul 2011) | 1 line
shaoxin
------------------------------------------------------------------------
r8 | madic | 2011-07-26 11:12:47 +0800 (Tue, 26 Jul 2011) | 1 line
modify
------------------------------------------------------------------------
r7 | madic | 2011-07-26 09:35:51 +0800 (Tue, 26 Jul 2011) | 1 line
code
------------------------------------------------------------------------
r6 | madic | 2011-07-20 15:43:52 +0800 (Wed, 20 Jul 2011) | 1 line
pa
------------------------------------------------------------------------
r5 | madic | 2011-07-20 15:42:19 +0800 (Wed, 20 Jul 2011) | 1 line
p
------------------------------------------------------------------------
r4 | madic | 2011-07-20 10:40:03 +0800 (Wed, 20 Jul 2011) | 1 line
dir
------------------------------------------------------------------------
r3 | madic | 2011-07-19 14:01:49 +0800 (Tue, 19 Jul 2011) | 1 line
keywords
------------------------------------------------------------------------
r2 | madic | 2011-07-19 13:58:24 +0800 (Tue, 19 Jul 2011) | 1 line
new test
------------------------------------------------------------------------
r1 | madic | 2011-07-15 16:56:05 +0800 (Fri, 15 Jul 2011) | 1 line
ci chage
------------------------------------------------------------------------
天哪,所有的svn日誌都顯示出來了。我們可以使用r來確定一個範圍。
這就是時光機的歷史查看了。來吧,想看哪一個版本的。
$svn log -r 5:9
------------------------------------------------------------------------
r5 | madic | 2011-07-20 15:42:19 +0800 (Wed, 20 Jul 2011) | 1 line
p
------------------------------------------------------------------------
r6 | madic | 2011-07-20 15:43:52 +0800 (Wed, 20 Jul 2011) | 1 line
pa
------------------------------------------------------------------------
r7 | madic | 2011-07-26 09:35:51 +0800 (Tue, 26 Jul 2011) | 1 line
code
------------------------------------------------------------------------
r8 | madic | 2011-07-26 11:12:47 +0800 (Tue, 26 Jul 2011) | 1 line
modify
------------------------------------------------------------------------
r9 | yinshaoxin | 2011-07-26 13:39:12 +0800 (Tue, 26 Jul 2011) | 1 line
shaoxin
------------------------------------------------------------------------
注意 -r 5:9 和 -r 9:5 是不同的順序顯示。
當然也可以指定一個檔案的版本日誌。
使用log注意,當你提交一個版本後,log並看不到這個日誌。
因為 commit 和 update是獨立的。commit並不更新本地版本。我們只有使用 update以後,在使用log則可以看到。
還有,如果你使用svn log 不指定路徑的話,那麼預設的是當前的目錄。這樣,對於其他目錄的log,我們只有一條空日誌。
$-------------------------------------------
最後不要像我一樣,日誌都是亂七八糟,請重視日誌,因為在以後查詢問題梳理版本變化的時候,會對你有很大幫助。
好了,從現在開始,你已經基本掌握SVN的用法了。如果具體命令引數不會用,請使用 help 。
如果你想了解的更多一點,那麼我們繼續看下一章。