? 2003-7 arfankai
歡迎轉(zhuǎn)載,但請保留作者,請不要用于商業(yè)性質(zhì)
last modified 2003-7-23
本文主要講的是linux操作系統(tǒng)下,在cnix的開發(fā)中,cvs的初步使用。
一,什么是cvs? 為什么要使用cvs? cvs的作用。
CVS是Concurrent Version System(并行版本系統(tǒng))的縮寫,用于版本管理,尤其在多人團(tuán)隊合作的開發(fā)模式中作用巨大。
為什么要使用CVS呢? 如果各位有過團(tuán)隊合作開發(fā)的經(jīng)驗就會知道,在團(tuán)隊合作開發(fā)中,要對整個項目的各個文件進(jìn)行控制是多么繁瑣的一件事情,經(jīng)常會出現(xiàn)不同的人修改了同一個程序,而需要人工合并整理。更糟糕的是,項目會出現(xiàn)多個版本,連開發(fā)者自己都不知道自己修改了那些文件,大量的精力消耗在各個版本,各個文件的整合中。這些精力完全可以避免,而省下更多的精力用在項目本身之中。
CVS還有一個更加重要的特性:能記下每個文件的每次修改,以及如何被修改。。。對于基于Internet 的合作方式來說,這些特性太重要了。一個地域上分散的自愿者組織顯然不可能投入很多的時間來訓(xùn)練其成員彼此合作。因為這樣的話,當(dāng)該組織有成員變更的時候,為此付出的投資將損失殆盡。所以需要指定一套基本的項目分配方案,以確保新成員能較容易的適應(yīng)工作,同時也需要設(shè)置一個自動的系統(tǒng)來接受外來代碼,并使每個成員能及時得到最新修改的代碼。
CVS的特點--能通過網(wǎng)絡(luò)訪問源代碼(實際上我們后面會講到,就是拷貝一份源代碼到本地),
能同步開發(fā),(廢話;)
能自動對修改進(jìn)行合并。(這個好!!)
二,CVS的工作方式--"拷貝-修改-合并"模型。
CVS是這樣組織的:(假設(shè)基于網(wǎng)絡(luò)的合作模式,并且以cnix為例子)
遠(yuǎn)程的gro.clinux.org上面保存著cnix的repository(源代碼庫),項目開發(fā)者擁有自己的一個 working copy(工作拷貝),這個工作拷貝是通過使用cvs checkout 命令從源代碼庫中申請得到。之后,項目開發(fā)者可以在自己的工作拷貝上進(jìn)行修改,修改了之后可以進(jìn)行提交( cvs commit)。由cvs負(fù)責(zé)對各個開發(fā)者所修改的部分進(jìn)行整合。如下圖:
cnix(repository)
|
---------+------------------------------------------------------------------
| | | | |
cnix cnix ...
(working copy) (working copy)
三,CVS基本術(shù)語
讓我們來了解一下CVS中會經(jīng)常提到的一些術(shù)語:
Revision(修訂版本)--文件歷史記錄中的被開發(fā)者提交的變化。一個修訂版本就是一個時常變化的項目的snapshot(瞬態(tài)圖)。
Repository(源代碼庫)--CVS存儲所有修訂版本歷史記錄的地方。每個項目都有自己的一個確定的源代碼庫。(ft。?;逎唵握f,就是遠(yuǎn)程gro上的cnix源代碼庫)
Working copy(工作拷貝)--開發(fā)者對文件作出修改時文件所在的拷貝(ft。?;逎y懂,簡單來說,就是我自己機(jī)器上的一份遠(yuǎn)程cnix的拷貝拉)
Check out(檢驗)--從源代碼庫中申請一份工作拷貝。該工作拷貝反映的是取出時項目的瞬時狀態(tài)。當(dāng)開發(fā)者對拷貝作出修改時,必須運用commit(提交)和update(更新)命令來 "發(fā)布"變化和查看其他開發(fā)者所作的修改。
(簡單來說,就是你需要使用CVS中的check out命令來從gro上得到一份cnix的工作拷貝)
Commit(提交)--將工作拷貝中的變化輸入中央源代碼庫。
(簡單來說,就是如果你修改了你自己的工作拷貝,并且想發(fā)布這些修改,那么你需要使用 CVS中的commit命令提交這些修改到gro的cnix倉庫中;)
Log message(日志信息)--提交修訂版本的時候,附帶描述變化的注解。通過查閱記錄信息,人們可以獲得一個當(dāng)前項目進(jìn)程的總結(jié)。
(還是要簡單的來說一下,xixi, 你每次cvs commit的時候,它都會要求你輸入一些log,你可以寫一下你這次修改的目的,修改了那些地方。。。這樣做的好處是別人可以通過查看cvs log得知你的修改,還可以通過一個cvs到ChangeLog 的工具把這些Log自動的轉(zhuǎn)化成Gnu的ChangeLog格式)
Update(更新)--從源代碼庫中取出別人的修改數(shù)據(jù),將其輸入自己的工作拷貝,并顯示自己的工作拷貝是否有未提交的修改。注意,不要和commit(提交)混淆,更新和提交是一對互補(bǔ)的指令。記住:Update將使工作拷貝和源代碼庫拷貝保持同步更新。
(簡單來說,就是是試圖使自己本地的工作拷貝更新到跟ropository一致的狀態(tài)。)
Conflicts(沖突)--倆個開發(fā)者對同一個區(qū)域所作的變化都提交給主版本時出現(xiàn)的情況,在 CVS覺察并指出這個沖突后,開發(fā)者必須解決該沖突。
(怎么解決,看下去,我會舉一個例子)
四,CVS中比較常用和簡單的命令介紹
(1),cvs import
使用這個命令進(jìn)行源代碼的第一次導(dǎo)入。比如遠(yuǎn)程gro中還沒有cnix的時候,需要使用:
[kai@kai cnix ]$ cd ~/Projects/cnix
[kai@kai cnix ]$ cvs import -m "import cnix" cnix arfankai start
把當(dāng)前目錄下的項目導(dǎo)入到遠(yuǎn)程gro的源代碼倉庫中,作為一個項目最初的開始。
(2),cvs checkout
具體使用的時候可以縮寫成cvs co。
使用這個命令從遠(yuǎn)程的源代碼庫導(dǎo)出一份cnix的代碼到本地。比如:
[kai@kai / ]$ cd ~/
[kai@kai kai ]$ export CVS_RSH=ssh
[kai@kai kai ]$ cvs -z3 -d arfankai@cvs.cnix.gro.clinux.org:/cvs/cnix co cnix
cvs server: Updating cnix
U cnix/Makefile
U cnix/define.mk
cvs server: Updating cnix/boot
U cnix/boot/boot.S
U cnix/boot/head.S
cvs server: Updating cnix/driver
U cnix/driver/Makefile
U cnix/driver/ide.c
... ...
之后,在你的家目錄里將會看到一個cnix的目錄。
(3),cvs commit
具體使用的時候,可以縮寫成cvs ci。
使用這個命令把你修改的文件提交給遠(yuǎn)程的cvs server。假設(shè)我修改了cnix/Makefile文件:
[kai@kai cnix ]$ cvs status Makefile
======================================================
File: Makefile Status: Locally Modified
Working revision: 1.1.1.1
Repository revision: 1.1.1.1 /cvs/cnix/cnix/Makefile,v
Sticky Tag: (none)
Sticky Date: (none)
Sticky Options: (none)
[kai@kai cnix ]$
然后提交之~,如下:
[kai@kai cnix <118>]$ cvs ci -m "test by arfankai" Makefile
Checking in Makefile;
/cvs/cnix/cnix/Makefile,v <-- Makefile
new revision: 1.2; previous revision: 1.1
done
[kai@kai cnix <119>]$
-m選項后面接的是log msg.
(4),cvs status
簡單的用法如(3)所示。用于看一個文件的狀態(tài)。
(5),cvs add
往源代碼庫里面增加一個文件或者是一個空的目錄名。注意:你使用這個命令的時候, 文件名或者是目錄名必須是已經(jīng)在你的本地工作目錄中有了,然后才能添加。注意2:如果添加的是文件,那么你使用這個命令之后,并不會立刻在遠(yuǎn)程repository中就會出現(xiàn)該文件,還需要使用cvs ci命令。如果添加的是目錄名,那么會立刻放映到遠(yuǎn)程repository。
建立一個空的本地test文件:
[kai@kai cnix <173>]$ touch test
把test文件加入到工作列表:
[kai@kai cnix <174>]$ cvs add test
cvs server: scheduling file `test' for addition
cvs server: use 'cvs commit' to add this file permanently
使用cvs ci提交文件到遠(yuǎn)程源代碼庫:
[kai@kai cnix <175>]$ cvs ci -m "add test" test
RCS file: /cvs/cnix/cnix/test,v
done
Checking in test;
/cvs/cnix/cnix/test,v <-- test
initial revision: 1.1
done
經(jīng)過這樣倆步,文件tmp.c才真正的加入到了源代碼倉庫中。
(6),cvs delete
刪除一個文件或者目錄。
刪除一個文件的步驟分三步:
1),刪除本地工作目錄中的該文件。(我們以刪除剛才加入的test文件為例子)
[kai@kai cnix <181>]$ rm test
2),將刪除的文件加入到工作列表:cvs remove 文件名
[kai@kai cnix <182>]$ cvs remove test
cvs server: scheduling `test' for removal
cvs server: use 'cvs commit' to remove this file permanently
3),提交刪除動作到遠(yuǎn)程源代碼庫:cvs ci 文件名
(從另外一個方面來說,添加和刪除都是一個"修改",所以他們對于源代碼庫來說是一樣的,都需要提交這些"修改")
[kai@kai cnix <183>]$ cvs ci -m "remove test" test
Removing test;
/cvs/cnix/cnix/test,v <-- test
new revision: delete; previous revision: 1.1
done
(7),cvs update
更新本地工作拷貝。可以縮寫成cvs up
cvs update 文件名(目錄名)
或
cvs up 文件名(目錄名)
或
cvs up (不加參數(shù),則會更新當(dāng)前目錄所有的文件以及遞歸的子目錄文件)
如果要連源代碼庫中新增的目錄也下載,則要加上 -d 選項。
cvs up -d
舉例如下:
[kai@kai cnix <198>]$ cvs up
cvs server: Updating .
U test <---把源代碼庫中的test文件更新到本地。
cvs server: Updating boot <---依序檢查各個子目錄
cvs server: Updating driver
cvs server: Updating fs
cvs server: Updating include
cvs server: Updating include/asm
cvs server: Updating include/cnix
cvs server: Updating init
cvs server: Updating kernel
cvs server: Updating lib
cvs server: Updating mm
cvs server: Updating shell
cvs server: Updating shell/app
cvs server: Updating tools
(8),cvs diff
比較版本差異。當(dāng)發(fā)現(xiàn)本地工作拷貝和源代碼庫中的文件不一致時,可以了解差異之處。
cvs diff 文件名
或
cvs diff (不加文件名參數(shù),表示遞歸的比對當(dāng)前目錄所有的文件和文件夾)
(具體的例子我不舉了)
(9),cvs log
查詢記錄,可以縮寫成cvs lo
比如,查詢一下Makefile文件的記錄:
[kai@kai cnix <200>]$ cvs log Makefile
RCS file: /cvs/cnix/cnix/Makefile,v
Working file: Makefile
head: 1.2
branch:
locks: strict
access list:
symbolic names:
start: 1.1.1.1
asmcos: 1.1.1
keyword substitution: kv
total revisions: 3; selected revisions: 3
description:
----------------------------
revision 1.2
date: 2003/07/22 13:35:45; author: arfankai; state: Exp; lines: +1 -0
test by arfankai
----------------------------
revision 1.1
date: 2003/03/25 09:51:27; author: asmcos; state: Exp;
branches: 1.1.1;
Initial revision
----------------------------
revision 1.1.1.1
date: 2003/03/25 09:51:27; author: asmcos; state: Exp; lines: +0 -0
======================================================
五,如何使用CVS進(jìn)行cnix的開發(fā)。
(本來已經(jīng)寫了好多了,突然停電。。。55)
在前一份文檔中,我已經(jīng)講了一些本地ssh的設(shè)置的問題。請參考這里:
http://cnix.gro.clinux.org/doc/dev_cnix.htm 按照那份文檔設(shè)置好之后,我們可以使用cvs checkout出一份cnix的本地working copy.
[kai@kai / ]$ cd ~/
[kai@kai kai ]$ export CVS_RSH=ssh
[kai@kai kai ]$ cvs -z3 -d arfankai@cvs.cnix.gro.clinux.org:/cvs/cnix co cnix
cvs server: Updating cnix
U cnix/Makefile
U cnix/define.mk
cvs server: Updating cnix/boot
U cnix/boot/boot.S
U cnix/boot/head.S
cvs server: Updating cnix/driver
U cnix/driver/Makefile
U cnix/driver/ide.c
... ...
之后,在你的家目錄里將會看到一個cnix的目錄。以后的所有修改都可以在這個目錄中進(jìn)行。
現(xiàn)在假設(shè)一種情況:我把cnix checkout到本地之后,由于忙畢業(yè)設(shè)計的事情,一個禮拜沒有怎么看代碼。今天想起Makefile有一個bug,于是先在本地改正之~
準(zhǔn)備提交之前,先用cvs update更新一下本地的working copy.
[kai@kai cnix <11>]$ cvs up
cvs server: Updating .
M Makefile <---本地修改了Makefile文件
cvs server: Updating boot
cvs server: Updating driver
cvs server: Updating fs
cvs server: Updating include
cvs server: Updating include/asm
cvs server: Updating include/cnix
cvs server: Updating init
cvs server: Updating kernel
cvs server: Updating lib
cvs server: Updating mm
U mm/page_alloc.c <---合作者新添加了page_alloc.c文件
P mm/memory.c <---合作者修改了memory.c文件
cvs server: Updating shell
cvs server: Updating shell/app
cvs server: Updating tools
[kai@kai cnix <12>]$
可以看到,cvs會提示一些文件的狀態(tài)。比如Makefile文件前面有一個"M"標(biāo)志,表示本地有修改,還沒有提交到源代碼庫。mm目錄下的page_alloc.c文件是新增加的("U"標(biāo)志),可能是在這一個禮拜中的某個時候,xiexiecn或者是ps/2或者是asmcos或者是別的開發(fā)者添加了這個文件,所以現(xiàn)在運行cvs update 會update到本地。mm目錄下的memory.c 可能被其他的合作者進(jìn)行了修改("P"標(biāo)志),所以也會由cvs更新到本地。
運行cvs update之后,就能把源代碼庫中的更新的文件更新到本地。現(xiàn)在需要做的是把我自己的修改Makefile提交到源代碼庫。
[kai@kai cnix <13>]$ cvs ci -m "test" Makefile
Checking in Makefile;
/cvs/cnix/cnix/Makefile,v <-- Makefile
new revision: 1.3; previous revision: 1.2
done
[kai@kai cnix <14>]$
我們來考查幾種比較簡單的情況下,CVS的處理方式:
ps/2和xiexiecn各自都從gro的cvs源代碼庫中取了一份工作拷貝。ps/2隨意編輯自己的工作拷貝, xiexiecn也編輯自己的工作拷貝。
(1),ps/2修改的是mm/memory.c; xiexiecn修改的是kernel/sched.c。
ps/2修改好了memory.c,進(jìn)行提交(cvs commit),xiexiecn也修改好了sched.c,進(jìn)行提交(倆人提交的時間是獨立的,沒有聯(lián)系)。由于倆人修改的是不同的文件,所以互不相干。都能很好的將這些修改提交到repository,并可附上修改記錄(可多可少,不明確規(guī)定)。
假設(shè)ps/2先進(jìn)行了提交,然后看電視去了:p,xiexiecn提交了sched.c之后,還想再工作一會,于是他先使用cvs status看一下,會發(fā)現(xiàn)memory.c已經(jīng)被ps/2修改,可以使用
cvs update mm/memory.c
更新memory.c文件,使得自己的工作拷貝在最update的狀態(tài)。
(一般來說,一個開發(fā)者在決定修改之前,最好是先使用cvs status看一下想要修改的文件,如果別人已經(jīng)有了修改,就可以先update一下,然后再在這個新版本的基礎(chǔ)上進(jìn)行修改,這樣可以省卻很多麻煩:)
(2),某一時刻,ps/2和xiexiecn都對mm/memory.c產(chǎn)生興趣,各自在自己的工作拷貝上對這個文件進(jìn)行了修改,但是ps/2修改的是文件開頭的幾行,比如加入了一些版權(quán)信息; xiexiecn修改的是文件的最后,比如添加了一個函數(shù)。一句話:他們修改的是一個文件的不同文本區(qū)。
然后他們分別進(jìn)行提交,CVS也能很好的處理這些修改,并且把他們倆個人的修改自動的整合到repository中的memor.c,v中。(Great!!)
下次當(dāng)ps/2又想對memory.c進(jìn)行修改的時候,記得我剛才的建議嗎?:) 可以先使用
cvs status mm/memory.c
看一下這個文件的狀態(tài),會發(fā)現(xiàn)需要update,于是使用
cvs update mm/memory.c
update之~,再在這個基礎(chǔ)上進(jìn)行修改,以后會愉快得多:) 。。。
(3),某一時刻,ps/2和xiexiecn都對mm/memory.c產(chǎn)生興趣,各自在自己的工作拷貝上對這個文件進(jìn)行了修改,并且他們修改的是同一個部分。比如在同一行各自加了條不一樣的注釋。 ps/2 加了一條:
//This is test.
xiexiecn加的是另外一條:
/* This is a test */
之后他們提交各自不同的修改,這樣將會產(chǎn)生沖突。我們假設(shè)ps/2先進(jìn)行了這項提交,他會很順利的提交成功。然后當(dāng)xiexiecn也試圖提交memory.c的修改時,CVS將會告訴他發(fā)現(xiàn)一個沖突(conflicts),并且提交不會成功。CVS會要求你先解決掉這個沖突(conflicts)。于是 xiexiecn可以先使用
cvs status mm/memory.c
看一下本地的memory.c和repository的memory.c的狀態(tài)報告。如下:
~/Projects/cnix/mm $ cvs status memory.c
=======================================================
File: memory.c Status: Needs Merge(需要合并)
Working revision: 1.14
Repository revision: 1.14 /cvs/cnix/cnix/mm/memory.c,v
Sticky Tag: (none)
Sticky Date: (none)
Sticky Options: (none)
~/Projects/cnix/mm $
然后使用cvs update 命令先update到本地:
~/Projects/cnix/mm $ cvs update memory.c
RCS file: /cvs/cnix/cnix/mm/memory.c,v
retrieving revision 1.14
retrieving revision 1.15
Merging differences between 1.14 and 1.15 into memory.c (合并到本地的memory.c中)
rcsmerge: warning: conflicts during merge (合并的過程中發(fā)現(xiàn)有沖突)
cvs server: conflicts found in memory.c
C memory.c
~/Projects/cnix/mm $
可以發(fā)現(xiàn),cvs 提示合并的過程中發(fā)現(xiàn)沖突(conflicts)。
我們看一下memory.c文件的相應(yīng)部分,就可以發(fā)現(xiàn),memory.c文件對應(yīng)部分變成這樣:
<<<<<<< memory.c
/* This is a test */
=======
//This is test.
>>>>>>> 1.15
這就是沖突標(biāo)記。
xiexiecn需要在整理這個沖突之后(比如只留下這一行: /* This is a test */) 再提交一個已解決沖突的新版本。也許xiexiecn和ps/2需要彼此交流一下以解決分歧。
六,總結(jié)
綜上,CVS的基本使用是非常簡單的,而CVS在自由軟件中的作用卻是巨大的??梢赃@么說,如果不學(xué)會CVS的基本使用,不會理解到合作開發(fā)的樂趣。
希望各位能從cnix中得到自己想要的東西。
參考資料:
1,CVS開源軟件開發(fā)技術(shù),Karl Fogel 著,肖虎勤 陳軍等翻譯,機(jī)械工業(yè)出版社
2,http://linux.tnc.edu.tw/techdoc/cvs/book1.html (簡單參考手冊,很不錯)
3,http://www.soforge.com/cvsdoc/zh_CN/book1.html (詳細(xì)手冊)
4,http://www.uml.net.cn/sjms/sjms051612.htm
5,http://www.igenus.org/resource/CVS/cvs.txt
還有很多很多,google一下吧,別偷懶:)