版本控制是一種記錄若干文件內(nèi)容變化,,以便將來(lái)查閱特定版本修訂情況的系統(tǒng),。
本地版本控制系統(tǒng)
許多人習(xí)慣用復(fù)制整個(gè)項(xiàng)目目錄的方式來(lái)保存不同的版本,或許還會(huì)改名加上備份時(shí)間進(jìn)行區(qū)別,。這么做的唯一好處就是簡(jiǎn)單,,壞處也不少:有時(shí)候會(huì)混淆所在的工作目錄,一旦弄錯(cuò)了文件數(shù)據(jù)就沒(méi)辦法撤銷(xiāo)恢復(fù),。為了解決這個(gè)問(wèn)題,,人們很久以前就開(kāi)發(fā)了許多本地版本控制系統(tǒng),大多是采用某種簡(jiǎn)單的數(shù)據(jù)庫(kù)來(lái)記錄文件的歷次更新差異,。
集中化的版本控制系統(tǒng)
接下來(lái)人們又遇到一個(gè)問(wèn)題,,如何讓在不同系統(tǒng)上的開(kāi)發(fā)者協(xié)同工作?于是,,集中化的版本控制系統(tǒng)(Centralized Version Control Systems)應(yīng)運(yùn)而生,。這類(lèi)系統(tǒng),諸如CVS,、Subversion等,,都有一個(gè)單一的集中管理服務(wù)器,保存所有文件的修訂版本,,而協(xié)同工作的人們都通過(guò)客戶(hù)端連到這臺(tái)服務(wù)器,,取出最新的文件或者提交更新。多年以來(lái),,這已成為版本控制系統(tǒng)的標(biāo)準(zhǔn)做法,。
這么做帶來(lái)了很多好處,特別是相對(duì)于本地版本控制系統(tǒng)來(lái)說(shuō)?,F(xiàn)在,,每個(gè)人都可以在一定程度上看到項(xiàng)目中的其他人正在做什么,管理員也可以輕松掌握每個(gè)開(kāi)發(fā)者的權(quán)限,,看到每個(gè)人每天的提交記錄,。這樣做最大的缺點(diǎn)就是中央服務(wù)器的單點(diǎn)故障。如果宕機(jī)一小時(shí),,那么在一小時(shí)內(nèi)所有人都無(wú)法提交更新,,也就無(wú)法協(xié)同工作。要是中央服務(wù)器的磁盤(pán)發(fā)生故障,,碰巧沒(méi)有備份或者備份不及時(shí),,就會(huì)有丟失數(shù)據(jù)的風(fēng)險(xiǎn),。最壞的情況是徹底丟失整個(gè)項(xiàng)目的所有歷史更改記錄,而被客戶(hù)端提取出來(lái)的某些快照數(shù)據(jù)除外,,但是不能夠保證所有的數(shù)據(jù)都已經(jīng)有人事先完整的提取出來(lái),。
本地版本控制系統(tǒng)也存在類(lèi)似問(wèn)題,只要整個(gè)項(xiàng)目的歷史記錄被保存在單一位置,,就有丟失所有歷史更新記錄的風(fēng)險(xiǎn),。
分布式版本控制系統(tǒng)
分布式版本管理系統(tǒng)就是為了解決這個(gè)單點(diǎn)問(wèn)題,在這類(lèi)系統(tǒng)中,,像Git,、Mercurial、Bazaar以及Darcs等,,客戶(hù)端并不只是提取最新的文件快照,,而是把原始的代碼倉(cāng)庫(kù)完整地鏡像下來(lái)。這么一來(lái),,任何一處協(xié)同工作用的服務(wù)器發(fā)生故障,,事后都可以用任何一個(gè)鏡像出來(lái)的本地倉(cāng)庫(kù)恢復(fù)。因?yàn)槊恳淮蔚奶崛〔僮?,?shí)際上都是一次對(duì)代碼倉(cāng)庫(kù)的完整備份,。更進(jìn)一步,這類(lèi)系統(tǒng)都可以指定和若干不同的遠(yuǎn)端代碼倉(cāng)庫(kù)進(jìn)行交互,。因此,,你就可以在同一個(gè)項(xiàng)目中,分別和不同工作小組的人相互協(xié)作,。你可以根據(jù)需要設(shè)定不同的協(xié)作流程,。
Git與SVN等常規(guī)版本控制軟件的區(qū)別
Git 是一個(gè)快速、可擴(kuò)展的分布式版本控制系統(tǒng),,它具有極為豐富的命令集,,對(duì)內(nèi)部系統(tǒng)提供了高級(jí)操作和完全訪問(wèn)。
Git誕生于2005年,,起因是因?yàn)長(zhǎng)inux內(nèi)核開(kāi)源項(xiàng)目使用的版本控制系統(tǒng)BitKeeper被收回,,這就迫使Linux開(kāi)源社區(qū)(特別是Linux的締造者Linus Torvalds)不得不吸取教訓(xùn),只有開(kāi)發(fā)一套屬于自己的版本控制系統(tǒng)才不至于重蹈覆轍,。他們對(duì)新系統(tǒng)制定的目標(biāo)如下:
速度快,,設(shè)計(jì)簡(jiǎn)單,,對(duì)非線性開(kāi)發(fā)模式的強(qiáng)力支持(允許上千個(gè)并行開(kāi)發(fā)的分支),,完全分布式,有能力高效管理類(lèi)似Linux內(nèi)核一樣的超大規(guī)模項(xiàng)目(速度和數(shù)量),。
經(jīng)過(guò)不斷的完善,,Git始終保持著如下的特點(diǎn):
1,、直接記錄快照,而非差異比較,。
Git和其他版本控制系統(tǒng)的主要差別在于,,Git只關(guān)心文件數(shù)據(jù)的整體是否發(fā)生變化,而大多數(shù)其他系統(tǒng)則只關(guān)心文件內(nèi)容的具體差異,。這類(lèi)系統(tǒng)(CVS,、Subversion等)每次記錄都有哪些文件做了更新,以及更新了哪些行的什么內(nèi)容,,如下圖:
Git 并不保存這些前后變化的差異數(shù)據(jù),。實(shí)際上,Git 更像是把變化的文件作快照后,,記錄在一個(gè)微型的文件系統(tǒng)中,。每次提交更新時(shí),它會(huì)縱覽一遍所有文件的指紋信息并對(duì)文件作一快照,,然后保存一個(gè)指向這次快照 的索引,。為提高性能,若文件沒(méi)有變化,,Git 不會(huì)再次保存,,而只對(duì)上次保存的快照作一鏈接。Git 的工作方式就像下圖所示:
這是 Git 同其他系統(tǒng)的重要區(qū)別,。它完全顛覆了傳統(tǒng)版本控制的套路,,并對(duì)各個(gè)環(huán)節(jié)的實(shí)現(xiàn)方式作了新的設(shè)計(jì)。Git 更像是個(gè)小型的文件系統(tǒng),,但它同時(shí)還提供了許多以此為基礎(chǔ)的超強(qiáng)工具,,而不只是一個(gè)簡(jiǎn)單的 VCS。
2,、支持離線工作(近乎所有操作都是本地執(zhí)行),,本地提交可以稍后提交到服務(wù)器上;
3,、時(shí)刻保持?jǐn)?shù)據(jù)完整性,;
4、多數(shù)操作僅添加數(shù)據(jù),;
文件的三種狀態(tài)
對(duì)于任何一個(gè)文件,,在 Git 內(nèi)都只有三種狀態(tài):已提交(committed),已修改(modified)和已暫存(staged),。已提交表示該文件已經(jīng)被安全地保存在本地?cái)?shù)據(jù)庫(kù) 中了,;已修改表示修改了某個(gè)文件,但還沒(méi)有提交保存,;已暫存表示把已修改的文件放在下次提交時(shí)要保存的清單中,。由此我們看到 Git 管理項(xiàng)目時(shí),,文件流轉(zhuǎn)的三個(gè)工作區(qū)域:Git 的工作目錄,暫存區(qū)域,,以及本地倉(cāng)庫(kù),。
每個(gè)項(xiàng)目都有一個(gè) Git 目錄(譯注:如果 git clone 出來(lái)的話,就是其中 .git 的目錄,;如果git clone --bare 的話,,新建的目錄本身就是 Git 目錄。),,它是 Git 用來(lái)保存元數(shù)據(jù)和對(duì)象數(shù)據(jù)庫(kù)的地方,。該目錄非常重要,每次克隆鏡像倉(cāng)庫(kù)的時(shí)候,,實(shí)際拷貝的就是這個(gè)目錄里面的數(shù)據(jù),。
從項(xiàng)目中取出某個(gè)版本的所有文件和目錄,用以開(kāi)始后續(xù)工作的叫做工作目錄,。這些文件實(shí)際上都是從 Git 目錄中的壓縮對(duì)象數(shù)據(jù)庫(kù)中提取出來(lái)的,,接下來(lái)就可以在工作目錄中對(duì)這些文件進(jìn)行編輯。
所謂的暫存區(qū)域只不過(guò)是個(gè)簡(jiǎn)單的文件,,一般都放在 Git 目錄中,。有時(shí)候人們會(huì)把這個(gè)文件叫做索引文件,不過(guò)標(biāo)準(zhǔn)說(shuō)法還是叫暫存區(qū)域,。
基本的 Git 工作流程如下:
1. 在工作目錄中修改某些文件,。 2. 對(duì)修改后的文件進(jìn)行快照,然后保存到暫存區(qū)域,。 3. 提交更新,,將保存在暫存區(qū)域的文件快照永久轉(zhuǎn)儲(chǔ)到 Git 目錄中。
所以,,我們可以從文件所處的位置來(lái)判斷狀態(tài):如果是 Git 目錄中保存著的特定版本文件,,就屬于已提交狀態(tài);如果作了修改并已放入暫存區(qū)域,,就屬于已暫存狀態(tài),;如果自上次取出后,作了修改但還沒(méi)有放到暫存區(qū)域,,就 是已修改狀態(tài),。
Git的使用
Git 支持許多數(shù)據(jù)傳輸協(xié)議,包括本地傳輸,、 git://協(xié)議,、http(s):// 或者 SSH傳輸協(xié)議 user@server:/path.git,除了HTTP協(xié)議之外,,其他所有協(xié)議都要求在服務(wù)器端安裝并運(yùn)行Git,。
一、使用本地倉(cāng)庫(kù)
對(duì)于本地的項(xiàng)目管理,,一些具體的操作方法可以參考這篇文章:Git基礎(chǔ) 里面詳細(xì)的講解了Git每個(gè)操作的使用方法和效果,。因?yàn)楸疚闹饕康脑谟谘菔救绾卫肎itHub參與開(kāi)源項(xiàng)目,對(duì)于使用細(xì)節(jié)就不再花時(shí)間描述了,,不過(guò)我認(rèn)為仔細(xì)的看看這些使用方法對(duì)于提高工作效率非常有幫助,。
使用本地倉(cāng)庫(kù),用戶(hù)只是自己一個(gè)人,,所以不存在協(xié)同工作的問(wèn)題,,不管怎么玩兒,一般不會(huì)出問(wèn)題,。使用遠(yuǎn)程倉(cāng)庫(kù),,情況就會(huì)復(fù)雜、有趣的多,。
二,、使用遠(yuǎn)程倉(cāng)庫(kù)
要參與任何一個(gè) Git 項(xiàng)目的協(xié)作,必須要了解該如何管理遠(yuǎn)程倉(cāng)庫(kù),。遠(yuǎn)程倉(cāng)庫(kù)是指托管在網(wǎng)絡(luò)上的項(xiàng)目倉(cāng)庫(kù),,可能會(huì)有好多個(gè),其中有些你只能讀,,另外有些可以寫(xiě),。同他人協(xié)作開(kāi)發(fā)某 個(gè)項(xiàng)目時(shí),需要管理這些遠(yuǎn)程倉(cāng)庫(kù),,以便推送或拉取數(shù)據(jù),,分享各自的工作進(jìn)展。管理遠(yuǎn)程倉(cāng)庫(kù)的工作,,包括添加遠(yuǎn)程庫(kù),,移除廢棄的遠(yuǎn)程庫(kù),管理各式遠(yuǎn)程庫(kù)分 支,,定義是否跟蹤這些分支,,等等。
以現(xiàn)在比較流行的GitHub為例,,如果我在上面創(chuàng)建了一個(gè)項(xiàng)目,,實(shí)際上相當(dāng)于使用 git init 新建了一個(gè)服務(wù)器端的倉(cāng)庫(kù)。如果我想在本地進(jìn)行開(kāi)發(fā),,那么我就需要 git clone 到我的本地,。做了一些開(kāi)發(fā)之后,我可以 git push 將本地的修改推送到服務(wù)器倉(cāng)庫(kù)中,。隨著項(xiàng)目發(fā)展,,有其他人想要參與到這個(gè)項(xiàng)目中來(lái),,他可以在GitHub上Fork我這個(gè)項(xiàng)目,,這樣他對(duì)這個(gè)項(xiàng)目才有寫(xiě)權(quán)限,,而且可以將他的工作保存到GitHub的服務(wù)器上,。如果他希望將自己的工作提交給我,,首先他需要在本地開(kāi)發(fā)環(huán)境中添加我的遠(yuǎn)程倉(cāng)庫(kù) git remote add,。然后 git push remotename master 發(fā)起推送的請(qǐng)求,,如果我接受了,,他的工作就可以合并到主干中了,。因?yàn)槲覀兇藭r(shí)是并行開(kāi)發(fā),,如果他想看我的工作,,可以采用 git pull remotename 的方式將我所做的修改拉取到本地,非常的方便,。
上面這段話,,描述了我們?cè)谑褂眠h(yuǎn)程倉(cāng)庫(kù)以及與其他人協(xié)作過(guò)程中的大體流程,需要用到的一些遠(yuǎn)程倉(cāng)庫(kù)的操作如下:
1,、查看當(dāng)前配置的遠(yuǎn)程倉(cāng)庫(kù)
可以使用 git remote -v 來(lái)查看當(dāng)前項(xiàng)目中都添加了哪些遠(yuǎn)程倉(cāng)庫(kù)
其中Origin一般是自己在服務(wù)器上的遠(yuǎn)程倉(cāng)庫(kù),,其他的為他人的遠(yuǎn)程倉(cāng)庫(kù)。
2,、添加新的遠(yuǎn)程倉(cāng)庫(kù)
要添加一個(gè)新的遠(yuǎn)程倉(cāng)庫(kù),,可以指定一個(gè)簡(jiǎn)單的名字,以便將來(lái)引用,,運(yùn)行 git remote add [shortname] [url]
git remote add pb git://github.com/paulboone/ticgit.git
3,、抓取遠(yuǎn)程倉(cāng)庫(kù)的信息
git fetch [remote-name]
此命令會(huì)到遠(yuǎn)程倉(cāng)庫(kù)中拉取所有你本地倉(cāng)庫(kù)中還沒(méi)有的數(shù)據(jù)。運(yùn)行完成后,,你就可以在本地訪問(wèn)該遠(yuǎn)程倉(cāng)庫(kù)中的所有分支,,將其中某個(gè)分支合并到本地,或者只是取出某個(gè)分支,,一探究竟,。如果是克隆了一個(gè)倉(cāng)庫(kù),此命令會(huì)自動(dòng)將遠(yuǎn)程倉(cāng)庫(kù)歸于 origin 名下,。所以,,git fetch origin 會(huì)抓取從你上次克隆以來(lái)別人上傳到此遠(yuǎn)程倉(cāng)庫(kù)中的所有更新(或是上次 fetch 以來(lái)別人提交的更新)。有一點(diǎn)很重要,,需要記住,,fetch 命令只是將遠(yuǎn)端的數(shù)據(jù)拉到本地倉(cāng)庫(kù),并不自動(dòng)合并到當(dāng)前工作分支,,只有當(dāng)你確實(shí)準(zhǔn)備好了,,才能手工合并。
4、 從遠(yuǎn)程倉(cāng)庫(kù)抓取信息并合并
git pull [remote-name]
可以使用 git pull 命令自動(dòng)抓取數(shù)據(jù)下來(lái),,然后將遠(yuǎn)端分支自動(dòng)合并到本地倉(cāng)庫(kù)中當(dāng)前分支,。在日常工作中我們經(jīng)常這么用,既快且好,。實(shí)際上,,默認(rèn)情況下git clone 命令本質(zhì)上就是自動(dòng)創(chuàng)建了本地的 master 分支用于跟蹤遠(yuǎn)程倉(cāng)庫(kù)中的 master 分支(假設(shè)遠(yuǎn)程倉(cāng)庫(kù)確實(shí)有 master 分支)。所以一般我們運(yùn)行g(shù)it pull,,目的都是要從原始克隆的遠(yuǎn)端倉(cāng)庫(kù)中抓取數(shù)據(jù)后,合并到工作目錄中的當(dāng)前分支,。
5,、推送數(shù)據(jù)到遠(yuǎn)程倉(cāng)庫(kù)
git push [remote-name] [branch-name]
項(xiàng)目進(jìn)行到一個(gè)階段,要同別人分享目前的成果,,可以將本地倉(cāng)庫(kù)中的數(shù)據(jù)推送到遠(yuǎn)程倉(cāng)庫(kù),。實(shí)現(xiàn)這個(gè)任務(wù)的命令很簡(jiǎn)單: git push [remote-name] [branch-name]。如果要把本地的 master 分支推送到origin 服務(wù)器上(再次說(shuō)明下,,克隆操作會(huì)自動(dòng)使用默認(rèn)的 master 和 origin 名字),,可以運(yùn)行下面的命令:
git push origin master
只有在所克隆的服務(wù)器上有寫(xiě)權(quán)限,或者同一時(shí)刻沒(méi)有其他人在推數(shù)據(jù),,這條命令才會(huì)如期完成任務(wù),。如果在你推數(shù)據(jù)前,已經(jīng)有其他人推送了若干更新,,那 你的推送操作就會(huì)被駁回,。你必須先把他們的更新抓取到本地,合并到自己的項(xiàng)目中,,然后才可以再次推送,。
6、查看遠(yuǎn)程倉(cāng)庫(kù)信息
git remote show [remote-name]
7,、遠(yuǎn)程倉(cāng)庫(kù)的刪除和重命名
git remote rename [old name] [new name]
git remote rm [remote-name]
Git與GitHub
GitHub是一個(gè)利用Git提供免費(fèi)的代碼托管服務(wù)的網(wǎng)站(類(lèi)似的網(wǎng)站還有老牌的SourceForge),,很多著名的項(xiàng)目都托管在上面。
要想在GitHub上參與開(kāi)源項(xiàng)目,,根據(jù)Git的使用方法,,有兩種途徑可以實(shí)現(xiàn)。
第一種是項(xiàng)目的創(chuàng)建人將你添加到項(xiàng)目的合作貢獻(xiàn)者列表中,,這樣你就可以直接向這個(gè)項(xiàng)目推送代碼,。
第二種是Fork一份代碼到自己的空間下,這樣的一份代碼自己具有推送的權(quán)限,。如果開(kāi)發(fā)的進(jìn)展很好,,項(xiàng)目的創(chuàng)建者可以將Fork的這些項(xiàng)目添加為Remote倉(cāng)庫(kù),在他認(rèn)為合適的時(shí)候?qū)⒋afetch到自己的倉(cāng)庫(kù)中進(jìn)行合并,也可以由我們發(fā)起請(qǐng)求,,請(qǐng)創(chuàng)始人將代碼合并,。GitHub上提倡的就是使用這種方式進(jìn)行開(kāi)發(fā)合作。
下面以PHP-Daemon這個(gè)項(xiàng)目為例,,演示一下如何參與到GitHub中托管的開(kāi)源項(xiàng)目中,。
0、安裝配置Git
1,、首先注冊(cè)一個(gè)GitHub的賬號(hào),。
2、選擇一個(gè)自己喜歡的項(xiàng)目,,進(jìn)行Fork,。
3、建立本地的資源池(Local Repo),。
可以使用下面的命令將項(xiàng)目復(fù)制到本地,,復(fù)制的地址可以是SSH的也可以是HTTP形式的,具體的地址在項(xiàng)目頁(yè)面中可以看到,。
git clone [email protected]:cocowool/PHP-Daemon.git
4,、配置源項(xiàng)目地址。
項(xiàng)目克隆完成后,,默認(rèn)有一個(gè)名為“origin”的遠(yuǎn)端指向了我在GitHub上的項(xiàng)目,,而并非原始的項(xiàng)目。為了能夠及時(shí)獲取原始項(xiàng)目上的更新,,我們需要再增加一個(gè)遠(yuǎn)端,,命名為“upstream”。
git remote add upstream https://github.com/shaneharter/PHP-Daemon.git
git fetch upstream
5,、接下來(lái)可以做的事情,。
推送提交 Push Commits
一些小Tips
Mac OS X Lion 中自帶了Git的命令行和圖形化界面,雖然他的圖形化界面簡(jiǎn)陋到吐血,。
Mac下還有一個(gè)gitk,,提供了圖形化工具來(lái)進(jìn)行歷史的查閱。它是用 Tcl/Tk 寫(xiě)成的,,基本上相當(dāng)于 git log 命令的可視化版本,,凡是git log 可以用的選項(xiàng)也都能用在 gitk 上。
在項(xiàng)目目錄下輸入 /Developer/usr/bin/gitk 就可以看到,。
|
|