版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
Git權(quán)威指南上(1-2篇)目錄\h第1篇初識(shí)Git\h第1章版本控制的前世和今生\h1.1黑暗的史前時(shí)代\h1.2CVS——開啟版本控制大爆發(fā)\h1.3SVN——集中式版本控制集大成者\(yùn)h1.4Git——Linus的第二個(gè)偉大作品\h第2章愛上Git的理由\h2.1每日工作備份\h2.2異地協(xié)同工作\h2.3現(xiàn)場(chǎng)版本控制\h2.4避免引入輔助目錄\h2.5重寫提交說明\h2.6想吃后悔藥\h2.7更好用的提交列表\h2.8更好的差異比較\h2.9工作進(jìn)度保存\h2.10代理SVN提交實(shí)現(xiàn)移動(dòng)式辦公\h2.11無處不在的分頁器\h2.12快\h第3章Git的安裝和使用\h3.1在Linux下安裝和使用Git\h3.1.1包管理器方式安裝\h3.1.2從源代碼進(jìn)行安裝\h3.1.3從Git版本庫進(jìn)行安裝\h3.1.4命令補(bǔ)齊\h3.1.5中文支持\h3.2在MacOSX下安裝和使用Git\h3.2.1以二進(jìn)制發(fā)布包的方式安裝\h3.2.2安裝Xcode\h3.2.3使用Homebrew安裝Git\h3.2.4從Git源碼進(jìn)行安裝\h3.2.5命令補(bǔ)齊\h3.2.6其他輔助工具的安裝\h3.2.7中文支持\h3.3在Windows下安裝和使用Git(Cygwin篇)\h3.3.1安裝Cygwin\h3.3.2安裝Git\h3.3.3Cygwin的配置和使用\h3.3.4Cygwin下Git的中文支持\h3.3.5Cygwin下Git訪問SSH服務(wù)\h3.4Windows下安裝和使用Git(msysGit篇)\h3.4.1安裝msysGit\h3.4.2msysGit的配置和使用\h3.4.3msysGit中shell環(huán)境的中文支持\h3.4.4msysGit中Git的中文支持\h3.4.5使用SSH協(xié)議\h3.4.6TortoiseGit的安裝和使用\h3.4.7TortoiseGit的中文支持\h第2篇Git獨(dú)奏\h第4章Git初始化\h4.1創(chuàng)建版本庫及第一次提交\h4.2思考:為什么工作區(qū)根目錄下有一個(gè).git目錄\h4.3思考:gitconfig命令的各參數(shù)有何區(qū)別\h4.4思考:是誰完成的提交\h4.5思考:隨意設(shè)置提交者姓名,是否太不安全\h4.6思考:命令別名是干什么的\h4.7備份本章的工作成果\h第5章Git暫存區(qū)\h5.1修改不能直接提交嗎\h5.2理解Git暫存區(qū)(stage)\h5.3GitDiff魔法\h5.4不要使用gitcommit-a\h5.5擱置問題,暫存狀態(tài)\h第6章Git對(duì)象\h6.1Git對(duì)象庫探秘\h6.2思考:SHA1哈希值到底是什么,是如何生成的\h6.3思考:為什么不用順序的數(shù)字來表示提交\h第7章Git重置\h7.1分支游標(biāo)master探秘\h7.2用reflog挽救錯(cuò)誤的重置\h7.3深入了解gitreset命令\h第8章Git檢出\h8.1HEAD的重置即檢出\h8.2挽救分離頭指針\h8.3深入了解gitcheckout命令\h第9章恢復(fù)進(jìn)度\h9.1繼續(xù)暫存區(qū)未完成的實(shí)踐\h9.2使用gitstash\h9.3探秘gitstash\h第10章Git基本操作\h10.1先來合個(gè)影\h10.2刪除文件\h10.2.1本地刪除不是真的刪除\h10.2.2執(zhí)行g(shù)itrm命令刪除文件\h10.2.3命令gitadd-u快速標(biāo)記刪除\h10.3恢復(fù)刪除的文件\h10.4移動(dòng)文件\h10.5一個(gè)顯示版本號(hào)的HelloWorld\h10.6使用gitadd-i選擇性添加\h10.7HelloWorld引發(fā)的新問題\h10.8文件忽略\h10.9文件歸檔\h第11章歷史穿梭\h11.1圖形工具:gitk\h11.2圖形工具:gitg\h11.3圖形工具:qgit\h11.4命令行工具\(yùn)h11.4.1版本表示法:gitrev-parse\h11.4.2版本范圍表示法:gitrev-list\h11.4.3瀏覽日志:gitlog\h11.4.4差異比較:gitdiff\h11.4.5文件追溯:gitblame\h11.4.6二分查找:gitbisect\h11.4.7獲取歷史版本\h第12章改變歷史\h12.1悔棋\h12.2多步悔棋\h12.3回到未來\h12.3.1時(shí)間旅行一\h12.3.2時(shí)間旅行二\h12.3.3時(shí)間旅行三\h12.4丟棄歷史\h12.5反轉(zhuǎn)提交\h第13章Git克隆\h13.1雞蛋不裝在一個(gè)籃子里\h13.2對(duì)等工作區(qū)\h13.3克隆生成裸版本庫\h13.4創(chuàng)建生成裸版本庫\h第14章Git庫管理\h14.1對(duì)象和引用哪里去了\h14.2暫存區(qū)操作引入的臨時(shí)對(duì)象\h14.3重置操作引入的對(duì)象\h14.4Git管家:git-gc\h14.5Git管家的自動(dòng)執(zhí)行第1篇初識(shí)GitGit是一款分布式版本控制系統(tǒng),有別于CVS和SVN等集中式版本控制系統(tǒng),Git可以讓研發(fā)團(tuán)隊(duì)更加高效地協(xié)同工作,從而提高生產(chǎn)率。使用Git,開發(fā)人員的工作不會(huì)因?yàn)轭l繁地遭遇提交沖突而中斷,管理人員也無須為數(shù)據(jù)的備份而擔(dān)心。經(jīng)過Linux這樣的龐大項(xiàng)目的考驗(yàn)之后,Git被證明可以勝任任何規(guī)模的團(tuán)隊(duì),即便團(tuán)隊(duì)成員分布于世界各地。Git是開源社區(qū)奉獻(xiàn)給每一個(gè)人的寶貝,用好它不僅可以實(shí)現(xiàn)個(gè)人的知識(shí)積累、保護(hù)好自己的數(shù)據(jù),而且還能與他人分享自己的成果。這在其他的很多版本控制系統(tǒng)中是不可想象的。你會(huì)為個(gè)人的版本控制而花費(fèi)高昂的費(fèi)用去購買商業(yè)版本控制工具嗎?你會(huì)去使用必須搭建額外的服務(wù)器才能使用的版本控制系統(tǒng)嗎?你會(huì)把“雞蛋”放在具有單點(diǎn)故障、服務(wù)器軟硬件有可能崩潰的唯一的“籃子”里嗎?如果你不會(huì),那么選擇Git,一定是最明智的選擇。本篇我們首先用一章的內(nèi)容來回顧一下版本控制的歷史,并以此向版本控制的前輩CVS和SVN致敬。第2章會(huì)通過一些典型的版本控制實(shí)例向您展示Git獨(dú)特的魅力,讓您愛上Git。在本篇的最后一章會(huì)介紹Git在Linux、MacOSX及Windows下的安裝和使用,這是我們進(jìn)一步研究Git的基礎(chǔ)。在這里有必要糾正一下Git的發(fā)音。一種錯(cuò)誤是按照單個(gè)字母來發(fā)音,另外一種更為普遍的錯(cuò)誤是把整個(gè)單詞讀作“技特”,實(shí)際上Git中字母G的發(fā)音與下列單詞中的G類似:GOD、GIVES、GREAT、GIFT。因此Git正確的發(fā)音應(yīng)該聽起來像是“歌易特”。本書的英文名為《GotGit》,當(dāng)面對(duì)這樣的書名時(shí)您還會(huì)把Git讀錯(cuò)嗎?第1章版本控制的前世和今生除了茫然未知的宇宙,幾乎任何事物都是從無到有,從簡(jiǎn)陋到完善。隨著時(shí)間車輪的滾滾向前,歷史被拋在身后逐漸遠(yuǎn)去,如同我們的現(xiàn)代社會(huì),世界大同,到處都是忙碌和喧囂,再也看不到已經(jīng)遠(yuǎn)去的刀耕火種、男耕女織的慢生活歲月。版本控制系統(tǒng)是一個(gè)另類。雖然其歷史并不短暫,也有幾十年,但是它的演進(jìn)進(jìn)程卻一直在社會(huì)的各個(gè)角落重復(fù)著,而且驚人的相似。有的人從未使用甚至從未聽說過版本控制系統(tǒng),他和他的團(tuán)隊(duì)就像停留在黑暗的史前時(shí)代,任由數(shù)據(jù)自生自滅。有的人使用著有幾十年歷史的CVS或其改良版Subversion,讓時(shí)間空耗在網(wǎng)絡(luò)連接的等待中。以Git為代表的分布式版本控制系統(tǒng)已經(jīng)風(fēng)靡整個(gè)開源社區(qū),正等待你的靠近。1.1黑暗的史前時(shí)代談及遠(yuǎn)古,人們總愛以“黑暗”來形容。黑暗實(shí)際上指的是秩序和工具的匱乏,而不是自然。如果以自然環(huán)境而論,由于工業(yè)化和城市化對(duì)環(huán)境的破壞,現(xiàn)今才是最黑暗的年代。對(duì)于軟件開發(fā)來說也是如此,在C語言一統(tǒng)天下的日子里我們的選擇很簡(jiǎn)單,如今面臨Java、.Net和腳本語言時(shí),我們的選擇變得復(fù)雜起來,但是從工具和秩序上講,過去的年代是黑暗的?;仡櫼幌挛医?jīng)歷的版本控制的“史前時(shí)代”吧。在大學(xué)里,代碼分散地拷貝在各個(gè)軟盤中,最終我被搞糊涂,不知道哪個(gè)軟盤中的代碼是最優(yōu)的,因?yàn)樽钚虏⒎亲顑?yōu),失敗的重構(gòu)會(huì)毀掉原來尚能運(yùn)作的代碼。在我工作的第一年,代碼的管理并未得到改善,還是以簡(jiǎn)單的目錄拷貝進(jìn)行數(shù)據(jù)的備份,三四個(gè)程序員利用文件服務(wù)器的共享目錄進(jìn)行協(xié)同,公共類庫和頭文件在操作過程中相互覆蓋,痛苦不堪。很明顯,那時(shí)我尚不知道版本控制系統(tǒng)為何物。我的版本控制史前時(shí)代一直延續(xù)到2000年,那時(shí)CVS已經(jīng)誕生了14年,而我在那時(shí)對(duì)CVS還一無所知。實(shí)際上,即便是在CVS出現(xiàn)之前的“史前時(shí)代”,也已經(jīng)有了非常好用的用于源碼比較和打補(bǔ)丁的工具:diff和patch,它們今天生命力依然頑強(qiáng)。大名鼎鼎的LinusTorvalds先生(Linux之父)也對(duì)這兩個(gè)工具偏愛有加,在1991~2002年之間,Linus一直頑固地使用diff、patch和tar包管理著Linux的代碼,雖然不斷有人提醒他有CVS的存在\h[1]。那么來看看diff和patch,熟悉它們將對(duì)理解版本控制系統(tǒng)(差異存儲(chǔ))和使用版本控制系統(tǒng)(代碼比較和沖突解決)都有莫大的好處。1.用diff命令比較兩個(gè)文本文件或目錄的差異先來構(gòu)造兩個(gè)文件:\h對(duì)這兩個(gè)文件執(zhí)行diff命令,并通過輸出重定向,將差異保存在diff.txt文件中。$diff-uhelloworld>diff.txt上面執(zhí)行diff命令的-u參數(shù)很重要,使得差異輸出中帶有上下文。打開文件diff.txt,會(huì)看到其中的差異比較結(jié)果。為了說明方便,為每一行增添了行號(hào)。1hello2010-09-2117:45:33.551610940+08002+++world2010-09-2117:44:46.343610465+08003@@-1,4+1,4@@4-應(yīng)該杜絕文章中的錯(cuò)別子。5+應(yīng)該杜絕文章中的錯(cuò)別字。67但是無論使用8*全拼,雙拼9@@-6,6+6,7@@1011是人就有可能犯錯(cuò),軟件更是如此。1213-犯了錯(cuò),就要扣工資!14-15改正的成本可能會(huì)很高。16+17+但是“只要眼球足夠多,所有Bug都好捉”,18+這就是開源的哲學(xué)之一。上面的差異文件,可以這么理解:第1行和第2行分別記錄了原始文件和目標(biāo)文件的文件名及時(shí)間戳。以三個(gè)減號(hào)()開始的行標(biāo)識(shí)的是原始文件,以三個(gè)加號(hào)(+++)開始的行標(biāo)識(shí)的是目標(biāo)文件。在比較內(nèi)容中,以減號(hào)(-)開始的行是只出現(xiàn)在原始文件中的行,例如:第4、13、14行。在比較內(nèi)容中,以加號(hào)(+)開始的行是只出現(xiàn)在目標(biāo)文件中的行,例如:第5行和16-18行。在比較內(nèi)容中,以空格開始的行,是在原始文件和目標(biāo)文件中都出現(xiàn)的行,例如:第6-8、10-12和第15行。這些行是用作差異比較的上下文。第3-8行是第一個(gè)差異小節(jié)。每個(gè)差異小節(jié)以一行差異定位語句開始。第3行就是一條差異定位語句,其前后分別用兩個(gè)@進(jìn)行標(biāo)識(shí)。第3行定位語句中-1,4的含義是:本差異小節(jié)的內(nèi)容相當(dāng)于原始文件的從第1行開始的4行。而第4、6、7、8行是原始文件中的內(nèi)容,加起來剛好是4行。第3行定位語句中+1,4的含義是:本差異小節(jié)的內(nèi)容相當(dāng)于目標(biāo)文件的從第1行開始的4行。而第5、6、7、8行是目標(biāo)文件中的內(nèi)容,加起來剛好是4行。因?yàn)槊頳iff是用于行比較的,所以即使改正了一個(gè)字,也顯示為一整行的修改(參見差異文件第4、5行)。Git對(duì)diff進(jìn)行了擴(kuò)展,并且還提供一種逐詞比較的差異比較方法,參見本書第2篇的第11.4.4小節(jié)。第9-18行是第二個(gè)差異小節(jié)。第9行是一條差異定位語句。第9行定位語句中-6,6的含義是:本差異小節(jié)的內(nèi)容相當(dāng)于原始文件的從第6行開始的6行。第10-15行是原始文件中的內(nèi)容,加起來剛好是6行。第9行定位語句中+6,7的含義是:本差異小節(jié)的內(nèi)容相當(dāng)于目標(biāo)文件的從第6行開始的7行。而第10-12、15-18行是目標(biāo)文件中的內(nèi)容,加起來剛好是7行。2.命令patch相當(dāng)于diff的反向操作有了hello和diff.txt文件,可以放心地將world文件刪除或用hello文件將world文件覆蓋。用下面的命令可以還原world文件:$cphelloworld$patchworld<diff.txt也可以保留world和diff.txt文件,刪除hello文件或用word文件將hello文件覆蓋。用下面的命令可以恢復(fù)hello文件:$cpworldhello$patch-Rhello<diff.txt命令diff和patch還可以對(duì)目錄進(jìn)行比較操作,這也就是Linus在1991~2002年用于維護(hù)Linux不同版本間差異的辦法。在沒有版本控制系統(tǒng)的情況下,可以用此命令記錄并保存改動(dòng)前后的差異,還可以將差異文件注入版本控制系統(tǒng)(如果有的話)。標(biāo)準(zhǔn)的diff和patch命令存在一個(gè)局限,就是不能對(duì)二進(jìn)制文件進(jìn)行處理。對(duì)二進(jìn)制文件的修改或添加會(huì)在差異文件中缺失,進(jìn)而丟失對(duì)二進(jìn)制文件的改動(dòng)或添加。Git對(duì)差異文件格式提供了擴(kuò)展支持,支持二進(jìn)制文件的比較,解決了這個(gè)問題。這一點(diǎn)可以參考本書第7篇第38章的相關(guān)內(nèi)容。\h[1]LinusTorvalds于2007年5月3日在Google的演講:/watch?v=4XpnKHJAok8\h[2]此處是故意將“字”寫成“子”,以便兩個(gè)文件進(jìn)行差異比較。1.2CVS——開啟版本控制大爆發(fā)CVS(ConcurrentVersionsSystem)\h[1]誕生于1985年,是由荷蘭阿姆斯特丹VU大學(xué)的DickGrune教授實(shí)現(xiàn)的。當(dāng)時(shí)DickGrune和兩個(gè)學(xué)生共同開發(fā)一個(gè)項(xiàng)目,但是三個(gè)人的工作時(shí)間無法協(xié)調(diào)到一起,迫切需要一個(gè)記錄和協(xié)同開發(fā)的工具軟件。于是DickGrune通過腳本語言對(duì)RCS(一個(gè)針對(duì)單獨(dú)文件的版本管理工具)進(jìn)行封裝,設(shè)計(jì)出有史以來第一個(gè)被大規(guī)模使用的版本控制工具。Dick教授的網(wǎng)站上介紹了CVS的這段早期歷史。\h[2]“在1985年的一個(gè)糟糕的秋日里,我在校汽車站等車回家,腦海里一直糾結(jié)著一件事——如何處理RCS文件、用戶文件(工作區(qū))和Entries文件的復(fù)雜關(guān)系,有的文件可能會(huì)缺失、沖突、刪除,等等。我的頭有些暈了,于是決定畫一個(gè)大表,將復(fù)雜的關(guān)聯(lián)畫在其中,看看出來的結(jié)果是什么樣的……”1986年Dick通過新聞組發(fā)布了CVS,1989年BrianBerliner用C語言將CVS進(jìn)行了重寫。從CVS的歷史可以看出,CVS不是設(shè)計(jì)出來的,而是被實(shí)際需要“逼”出來的,因此根據(jù)“實(shí)用為上”的原則,借用了已有的針對(duì)單一文件的版本管理工具RCS。CVS采用客戶端/服務(wù)器架構(gòu)設(shè)計(jì),版本庫位于服務(wù)器端,實(shí)際上就是一個(gè)RCS文件容器。每一個(gè)RCS文件以",v"作為文件名后綴,用于保存對(duì)應(yīng)文件的每一次更改歷史。RCS文件中只保留一個(gè)版本的完全拷貝,其他歷次更改僅將差異存儲(chǔ)其中,使得存儲(chǔ)變得非常有效率。我在2008年設(shè)計(jì)了一個(gè)SVN管理后臺(tái)pySvnManager\h[3],實(shí)際上也采用了RCS作為SVN授權(quán)文件的變更記錄的“數(shù)據(jù)庫”。圖1-1展示了CVS版本控制系統(tǒng)的工作原理,可以看到作為RCS文件容器的CVS版本庫和工作區(qū)目錄結(jié)構(gòu)的一一對(duì)應(yīng)關(guān)系。圖1-1CVS版本控制系統(tǒng)示意圖CVS這種實(shí)現(xiàn)方式的最大好處就是簡(jiǎn)單。把版本庫中任意一個(gè)目錄拿出來就可以成為另外一個(gè)版本庫。如果將版本庫中的一個(gè)RCS文件重命名,工作區(qū)檢出的文件名也會(huì)相應(yīng)地改變。這種低成本的服務(wù)器管理模式成為很多CVS粉絲至今不愿離開CVS的原因。CVS的出現(xiàn)讓軟件工程師認(rèn)識(shí)到了原來還可以這樣工作。CVS成功地為后來的版本控制系統(tǒng)確立了標(biāo)準(zhǔn),像提交說明(commitlog)、檢入(checkin)、檢出(checkout)、里程碑(tag)、分支(branch)等概念在CVS中早就已經(jīng)確立。CVS的命令行格式也被后來的版本控制系統(tǒng)競(jìng)相模仿。在2001年,我正為使用CVS激動(dòng)不已的時(shí)候,公司領(lǐng)導(dǎo)要求采用和美國(guó)研發(fā)部門同樣的版本控制解決方案。于是,我的項(xiàng)目組率先進(jìn)行了從CVS到該商業(yè)版本控制工具的遷移\h[4]。雖然商業(yè)版本控制工具有更漂亮的界面及更好的產(chǎn)品整合性,但是就版本控制本身而言,商業(yè)版本控制工具存在著如下缺陷。采用黑盒子式的版本庫設(shè)計(jì)。讓人捉摸不透的版本庫設(shè)計(jì),最主要的目的可能就是阻止用戶再遷移到其他平臺(tái)。缺乏版本庫整理工具。如果有一個(gè)文件(如記錄核彈引爆密碼的文件)檢入到版本庫中,就無法再徹底移除它。商業(yè)版本控制工具很難為個(gè)人提供版本控制解決方案,除非個(gè)人愿意花費(fèi)高昂的許可證費(fèi)用。商業(yè)版本控制工具注定是小眾軟件,新員工的培訓(xùn)成本不可忽視。而上述商業(yè)版本控制系統(tǒng)的缺點(diǎn)恰恰是CVS及其他開源版本控制系統(tǒng)的優(yōu)點(diǎn)。但在經(jīng)歷了最初的成功之后,CVS也盡顯疲態(tài):服務(wù)器端松散的RCS文件導(dǎo)致在建立里程碑或分支時(shí)效率不高,服務(wù)器端文件越多,速度越慢。分支和里程碑不可見,因?yàn)樗鼈儽环稚⒌赜涗浽诜?wù)器端的各個(gè)RCS文件中。合并困難重重,因?yàn)槿狈?duì)合并的追蹤,從而導(dǎo)致重復(fù)合并,引發(fā)嚴(yán)重沖突。缺乏對(duì)原子提交的支持,會(huì)導(dǎo)致客戶端向服務(wù)器端提交不完整的數(shù)據(jù)。不能優(yōu)化存儲(chǔ)內(nèi)容相同但文件名不同的文件,因?yàn)樵诜?wù)器端每個(gè)文件都是單獨(dú)進(jìn)行差異存儲(chǔ)的。不能對(duì)文件和目錄的重命名進(jìn)行版本控制,雖然直接在服務(wù)器端修改RCS文件名可以讓改名后的文件保存歷史,但是這樣做實(shí)際上會(huì)破壞歷史。CVS的成功導(dǎo)致了版本控制系統(tǒng)的大爆發(fā),各式各樣的版本控制系統(tǒng)如雨后春筍般誕生了。新的版本控制系統(tǒng)或多或少地解決了CVS版本控制系統(tǒng)存在的問題。在這些版本控制系統(tǒng)中,最典型的就是Subversion(SVN)。\h[1]/cvs/\h[2]/Programs/CVS.orig/\h[3]\h[4]于是就有了這篇文章:/doc/cvs_vs_starteam1.3SVN——集中式版本控制集大成者Subversion\h[1],由于其命令行工具名為svn,因此通常被簡(jiǎn)稱為SVN。SVN由CollabNet公司于2000年資助并開始開發(fā),目的是創(chuàng)建一個(gè)更好用的版本控制系統(tǒng)以取代CVS。SVN的前期開發(fā)使用CVS做版本控制,到了2001年,SVN已經(jīng)可以用于自己的版本控制了\h[2]。我開始真正關(guān)注SVN是在2005年,那時(shí)SVN正經(jīng)歷著后端存儲(chǔ)上的變革,即從BDB(簡(jiǎn)單的關(guān)系型數(shù)據(jù)庫)到FSFS(文件數(shù)據(jù)庫)的轉(zhuǎn)變。相對(duì)于BDB而言,F(xiàn)SFS具有穩(wěn)定、免維護(hù)和實(shí)現(xiàn)的可視性高等優(yōu)點(diǎn),于是我馬上就被SVN吸引了。圖1-2展示了SVN版本控制系統(tǒng)的工作原理。圖1-2SVN版本控制系統(tǒng)示意圖SVN的每一次提交,都會(huì)在服務(wù)器端的db/revs和db/revprops目錄下各創(chuàng)建一個(gè)以順序數(shù)字編號(hào)命名的文件。其中,db/revs目錄下的文件(即變更集文件)記錄了與上一個(gè)提交之間的差異(字母A表示新增,M表示修改,D表示刪除)。在db/revprops目錄下的同名文件(沒有在圖1-2中體現(xiàn))則保存著提交日志、作者、提交時(shí)間等信息。這樣設(shè)計(jì)的好處有:擁有全局版本號(hào)。每提交一次,SVN的版本號(hào)就會(huì)自動(dòng)加一。這為SVN的使用提供了極大的便利?;叵隒VS時(shí)代,每個(gè)文件都擁有各自獨(dú)立的版本號(hào)(RCS版本號(hào)),要想獲得全局版本號(hào),只能通過手工不斷地建立里程碑來實(shí)現(xiàn)。實(shí)現(xiàn)了原子提交。SVN不會(huì)像CVS那樣出現(xiàn)文件的部分內(nèi)容被提交而其余的內(nèi)容沒有被提交的情況。文件名不受限制。因?yàn)榉?wù)器端不再需要建立和客戶端文件相似的文件名,于是,文件的命名就不再受服務(wù)器操作系統(tǒng)的字符集和大小寫的限制。文件和目錄重命名也得到了支持。SVN最具有特色的功能是輕量級(jí)拷貝,例如將目錄trunk拷貝為branches/v1.x只相當(dāng)于在db/revs目錄中的變更集文件中用特定的語法做了一下標(biāo)注,無須真正的文件拷貝。SVN使用輕量級(jí)拷貝的功能,輕松地解決了CVS存在的里程碑和分支的創(chuàng)建速度慢又不可見的問題,使用SVN創(chuàng)建里程碑和分支只在眨眼之間。SVN在版本庫授權(quán)上也有改進(jìn),不再像CVS那樣依賴操作系統(tǒng)本身對(duì)版本庫目錄和文件進(jìn)行授權(quán),而是采用授權(quán)文件的方式來實(shí)現(xiàn)。SVN還有一個(gè)創(chuàng)舉,就是在工作區(qū)跟蹤目錄下(.svn目錄)為當(dāng)前目錄中的每一個(gè)文件都保存一份冗余的原始拷貝。這樣做的好處是部分命令不再需要網(wǎng)絡(luò)連接,例如文件修改的差異比較,以及錯(cuò)誤更改的回退等。正是由于這些閃亮的功能特性,才使得SVN在CVS之后誕生的諸多版本控制系統(tǒng)中脫穎而出,成為開源社區(qū)一時(shí)的新寵,也成為當(dāng)時(shí)各個(gè)企業(yè)進(jìn)行版本控制的最佳選擇之一。但是,相對(duì)于CVS,SVN在本質(zhì)上并沒有突破,都屬于集中式版本控制系統(tǒng)。即一個(gè)項(xiàng)目只有唯一的一個(gè)版本庫與之對(duì)應(yīng),所有的項(xiàng)目成員都通過網(wǎng)絡(luò)向該服務(wù)器進(jìn)行提交。這樣的設(shè)計(jì)除了容易出現(xiàn)單點(diǎn)故障以外,在查看日志和提交數(shù)據(jù)等操作時(shí)的延遲,會(huì)讓基于廣域網(wǎng)協(xié)同工作的團(tuán)隊(duì)抓狂。除了集中式版本控制系統(tǒng)固有的問題外,SVN的里程碑和分支的設(shè)計(jì)也被證明是一個(gè)錯(cuò)誤,雖然這個(gè)錯(cuò)誤的設(shè)計(jì)使得SVN擁有了快速創(chuàng)建里程碑和分支的能力,但是這個(gè)錯(cuò)誤的設(shè)計(jì)也導(dǎo)致了如下的更多問題。項(xiàng)目文件在版本庫中必須按照一定的目錄結(jié)構(gòu)進(jìn)行部署,否則就可能無法建立里程碑和分支。我在項(xiàng)目咨詢過程中見過很多團(tuán)隊(duì),直接在版本庫的根目錄下創(chuàng)建項(xiàng)目文件。這樣的版本庫布局,在需要?jiǎng)?chuàng)建里程碑和分支時(shí)就無從下手了,因?yàn)楦夸浭遣荒芸截惖阶幽夸浿械?。所以SVN的用戶在創(chuàng)建版本庫時(shí)必須遵守一個(gè)古怪的約定:先創(chuàng)建三個(gè)頂級(jí)目錄/trunk、/tags和/branches。創(chuàng)建里程碑和分支會(huì)破壞精心設(shè)計(jì)的授權(quán)。SVN的授權(quán)是基于目錄的,分支和里程碑也被視為目錄(和其他目錄沒有分別)。因此每次創(chuàng)建分支或里程碑時(shí),就要將針對(duì)/trunk目錄及其子目錄的授權(quán)在新建的分支或里程碑上重建。隨著分支和里程碑?dāng)?shù)量的增多,授權(quán)愈加復(fù)雜,維護(hù)也愈加困難。分支太隨意從而導(dǎo)致混亂。SVN的分支創(chuàng)建非常隨意:可以基于/trunk目錄創(chuàng)建分支,也可以基于其他任何目錄創(chuàng)建分支,因此SVN很難畫出一個(gè)有意義的分支圖。再加上一次提交可以同時(shí)包含針對(duì)不同分支的文件變更,使得事情變得更糟。雖然SVN在1.5版之后擁有了合并追蹤功能,但這個(gè)功能會(huì)因?yàn)榛靵y的分支管理而被抵消。2009年年底,SVN由CollabNet公司交由Apache社區(qū)管理,至此SVN成為了Apache組織的一個(gè)子項(xiàng)目\h[3]。這對(duì)SVN到底意味著什么?是開發(fā)的停滯?還是新的開始?結(jié)果如何我們將拭目以待。\h[1]/\h[2]/en/1.5/ro.whatis.html#ro.history\h[3]/wiki/Apache_Subversion1.4Git——Linus的第二個(gè)偉大作品Linux之父Linus是堅(jiān)定的CVS反對(duì)者,他也同樣地反對(duì)SVN。這就是為什么在1991-2002這十余年間,Linus寧可以手工修補(bǔ)文件的方式維護(hù)代碼,也遲遲不愿使用CVS的原因。我想在當(dāng)時(shí)要想勸說Linus使用CVS只有一個(gè)辦法:把CVS服務(wù)器請(qǐng)進(jìn)Linus的臥室,并對(duì)外配以千兆帶寬。2002年至2005年,Linus頂著開源社區(qū)精英們口誅筆伐的壓力,選擇了一個(gè)商業(yè)版本控制系統(tǒng)BitKeeper作為L(zhǎng)inux內(nèi)核的代碼管理工具\(yùn)h[1]。BitKeeper不同于CVS和SVN等集中式版本控制工具,而是一款分布式版本控制工具。分布式版本控制系統(tǒng)最大的反傳統(tǒng)之處在于,可以不需要集中式的版本庫,每個(gè)人都工作在通過克隆建立的本地版本庫中。也就是說每個(gè)人都擁有一個(gè)完整的版本庫,查看提交日志、提交、創(chuàng)建里程碑和分支、合并分支、回退等所有操作都直接在本地完成而不需要網(wǎng)絡(luò)連接。每個(gè)人都是本地版本庫的主人,不再有誰能提交誰不能提交的限制,加上多樣的協(xié)同工作模型(版本庫間推送、拉回,以及補(bǔ)丁文件傳送等)讓開源項(xiàng)目的參與度有爆發(fā)式增長(zhǎng)。2005年發(fā)生的一件事最終導(dǎo)致了Git的誕生。在2005年4月,AndrewTridgell(即大名鼎鼎的Samba的作者)試圖對(duì)BitKeeper進(jìn)行反向工程,以開發(fā)一個(gè)能與BitKeeper交互的開源工具。這激怒了BitKeeper軟件的所有者BitMover公司,要求收回對(duì)Linux社區(qū)免費(fèi)使用BitKeeper的授權(quán)\h[2]。迫不得已,Linus選擇了自己開發(fā)一個(gè)分布式版本控制工具以替代BitKeeper。以下是Git誕生過程中的大事記\h[3]:2005年4月3日,開始開發(fā)Git。2005年4月6日,項(xiàng)目發(fā)布。2005年4月7日,Git就可以作為自身的版本控制工具了。2005年4月18日,發(fā)生第一個(gè)多分支合并。2005年4月29日,Git的性能就已經(jīng)達(dá)到了Linus的預(yù)期。2005年6月16日,Linux內(nèi)核2.6.12發(fā)布,那時(shí)Git已經(jīng)在維護(hù)Linux核心的源代碼了。Linus以一個(gè)文件系統(tǒng)專家和內(nèi)核設(shè)計(jì)者的視角對(duì)Git進(jìn)行了設(shè)計(jì),其獨(dú)特的設(shè)計(jì)讓Git擁有非凡的性能和最為優(yōu)化的存儲(chǔ)能力。完成原型設(shè)計(jì)后,在2005年7月26日,Linus功成身退,將Git的維護(hù)交給另外一個(gè)Git的主要貢獻(xiàn)者JunioCHamano\h[4],直到現(xiàn)在。最初的Git除了一些核心命令以外,其他的都用腳本語言開發(fā),而且每個(gè)功能都作為一條獨(dú)立的命令,例如克隆操作用git-clone,提交操作用git-commit。這導(dǎo)致Git擁有龐大的命令集,使用習(xí)慣也和其他版本控制系統(tǒng)格格不入。隨著Git的開發(fā)者和使用者的增加,Git也在逐漸演變,例如到1.5.4版本時(shí),將一百多個(gè)獨(dú)立的命令封裝為一個(gè)git命令,使它看起來更像是一個(gè)獨(dú)立的工具,也使Git更貼近于普通用戶的使用習(xí)慣。經(jīng)過短短幾年的發(fā)展,眾多的開源項(xiàng)目都紛紛從SVN或其他版本控制系統(tǒng)遷移到Git。雖然版本控制系統(tǒng)的遷移過程是痛苦的,但是因?yàn)檫w移到Git會(huì)帶來開發(fā)效率的極大提升,以及巨大的效益,所以很快就會(huì)忘記遷移的痛苦過程,而且很快就會(huì)適應(yīng)新的工作模式。在Git的官方網(wǎng)站上列出了幾個(gè)使用Git的重量級(jí)項(xiàng)目,每一個(gè)都是人們耳熟能詳?shù)?,除了Git和Linux內(nèi)核外,還有Perl、Eclipse、Gnome、KDE、Qt、RubyonRails、Android、PostgreSQL、Debian、X.org,當(dāng)然還有GitHub的上百萬個(gè)項(xiàng)目。Git雖然是在Linux下開發(fā)的,但現(xiàn)在已經(jīng)可以跨平臺(tái)運(yùn)行在所有主流的操作系統(tǒng)上,包括Linux、MacOSX和Windows等。可以說每一個(gè)使用計(jì)算機(jī)的用戶都可以分享Git帶來的便利和快樂。\h[1]/wiki/BitKeeper\h[2]/wiki/Andrew_Tridgell\h[3]/wiki/Git_%28software%29\h[4]/?l=git&m=112243466603239第2章愛上Git的理由本章將通過一些典型應(yīng)用展示Git作為版本控制系統(tǒng)的獨(dú)特用法,不熟悉版本控制系統(tǒng)的讀者可以通過這些示例對(duì)版本控制擁有感性的認(rèn)識(shí)。如果是有經(jīng)驗(yàn)的讀者,示例中Git和SVN的對(duì)照可以讓您體會(huì)到Git的神奇和強(qiáng)大。本章將列舉Git的一些閃亮特性,期待能夠讓您愛上Git。2.1每日工作備份當(dāng)我開始撰寫本書時(shí)才明白寫書真的是一個(gè)辛苦活。如何讓辛苦的工作不會(huì)因?yàn)楣P記本硬盤的意外損壞而丟失?如何防范災(zāi)害而不讓一個(gè)籃子里的雞蛋都?xì)в谝坏??下面就介紹一下我在寫本書時(shí)是如何使用Git進(jìn)行文稿備份的,請(qǐng)看圖2-1。圖2-1利用Git做數(shù)據(jù)的備份如圖2-1所示,我的筆記本在公司局域網(wǎng)里的IP地址是00,公司的Git服務(wù)器的IP地址是。公司使用動(dòng)態(tài)IP上網(wǎng)因而沒有固定的外網(wǎng)IP,但是公司在數(shù)據(jù)中心有托管服務(wù)器,擁有固定的IP地址,其中一臺(tái)服務(wù)器用作Git服務(wù)器鏡像。我的寫書習(xí)慣大概是這樣:在寫完一個(gè)小節(jié)或是畫完一張圖后,我會(huì)執(zhí)行下面的命令提交一次。每一天平均提交3-5次。提交是在本地完成的,因此在圖中沒有表示出來。$gitadd-u#如果創(chuàng)建了新文件,可以執(zhí)行g(shù)itadd-i命令。$gitcommit下班后,我會(huì)執(zhí)行一次推送操作,將我在本地Git版本庫中的提交同步到公司的Git服務(wù)器上。相當(dāng)于圖2-1中的步驟①。$gitpush因?yàn)楣镜腉it服務(wù)器和異地?cái)?shù)據(jù)中心的Git服務(wù)器建立了鏡像,所以每當(dāng)我向公司內(nèi)網(wǎng)服務(wù)器推送的時(shí)候,就會(huì)自動(dòng)觸發(fā)從內(nèi)網(wǎng)服務(wù)器到外網(wǎng)Git服務(wù)器的鏡像操作。這相當(dāng)于圖2-1中的步驟②,步驟②是自動(dòng)執(zhí)行的,無須人工干預(yù)。圖2-1中標(biāo)記為mirror的版本庫就是Git鏡像版本庫,該版本庫只向用戶提供只讀訪問服務(wù),而不能對(duì)其進(jìn)行寫操作(推送)。從圖2-1中可以看出,我的每日工作保存有三個(gè)拷貝,一個(gè)在筆記本中,一個(gè)在公司內(nèi)網(wǎng)的服務(wù)器上,還有一個(gè)在外網(wǎng)的鏡像版本庫中。雞蛋分別裝在了三個(gè)籃子里。關(guān)于如何架設(shè)可以實(shí)時(shí)鏡像的Git服務(wù)器,會(huì)在本書第5篇第30章中詳細(xì)介紹。2.2異地協(xié)同工作為了能夠加快寫書的進(jìn)度,熬夜是必須的,這就出現(xiàn)了在公司和家里兩地工作同步的問題。圖2-2用于說明我是如何解決兩地工作同步問題的。圖2-2利用Git實(shí)現(xiàn)異地工作協(xié)同我在家里的電腦IP地址是00(家里也有一個(gè)小局域網(wǎng))。如果在家里有時(shí)間工作的話,首先要做的就是圖2-2中步驟③的操作:將mirror版本庫中的數(shù)據(jù)同步到本地。只需要一條命令就好了:$gitpullmirrormaster然后在家里的電腦上繼續(xù)編寫書稿并提交。當(dāng)準(zhǔn)備完成一天的工作后,就執(zhí)行下面的命令,相當(dāng)于圖2-2中步驟④的操作:將在家中的提交推送到標(biāo)記為home的版本庫中。$gitpushhome為什么還要再引入另外一個(gè)名為home的版本庫呢?使用mirror版本庫不好么?不要忘了mirror版本庫只是一個(gè)鏡像庫,不能提供寫操作。當(dāng)一早到公司,開始動(dòng)筆寫書之前,先要執(zhí)行圖2-2中步驟⑤的操作,從home版本庫將家里做的提交同步到公司的電腦中。$gitpullhomemaster公司的小崔是我這本書的忠實(shí)讀者,每當(dāng)有新章節(jié)完成,他都會(huì)執(zhí)行圖2-2中步驟⑥的工作,從公司內(nèi)網(wǎng)服務(wù)器獲取我最新的文稿。$gitpull一旦發(fā)現(xiàn)文字錯(cuò)誤,小崔會(huì)直接在文稿中修改,然后推送到公司的服務(wù)器上(圖2-2中步驟⑦)。當(dāng)然他的這個(gè)推送也會(huì)自動(dòng)同步到外網(wǎng)的mirror版本庫。$gitpush而我只要執(zhí)行g(shù)itpull操作就可以獲得小崔對(duì)文稿的修訂(圖2-2中的步驟⑧)。采用這種工作方式,文稿竟然分布在5臺(tái)電腦上擁有6個(gè)拷貝,真可謂狡兔三窟。不,比狡兔還要多三窟。在本節(jié)中,出現(xiàn)在Git命令中的mirror和home是和工作區(qū)關(guān)聯(lián)的遠(yuǎn)程版本庫。關(guān)于如何注冊(cè)和使用遠(yuǎn)程版本庫,請(qǐng)參見本書第3篇第19章中的內(nèi)容。2.3現(xiàn)場(chǎng)版本控制所謂現(xiàn)場(chǎng)版本控制,就是在客戶現(xiàn)場(chǎng)或在產(chǎn)品部署的現(xiàn)場(chǎng)進(jìn)行源代碼的修改,并在修改過程中進(jìn)行版本控制,以便在完成修改后能夠?qū)⑿薷慕Y(jié)果甚至修改過程一并帶走,并能夠?qū)⑿薷慕Y(jié)果合并至項(xiàng)目對(duì)應(yīng)的代碼庫中。1.SVN的解決方案如果使用SVN進(jìn)行版本控制,首先要將服務(wù)器上部署的產(chǎn)品代碼目錄變成SVN工作區(qū),這個(gè)過程不僅不簡(jiǎn)單,而且會(huì)顯得很繁瑣,最后將改動(dòng)結(jié)果導(dǎo)出也非常不方便,具體操作過程如下。(1)在其他位置建立一個(gè)SVN版本庫。$svnadmincreate/path/to/repos/project1(2)在需要版本控制的目錄下檢出剛剛建立的空版本庫。$svncheckoutfile:///path/to/repos/project1.(3)執(zhí)行添加文件操作,然后執(zhí)行提交操作。這個(gè)提交將是版本庫中編號(hào)為1的提交。$svnadd*$svnci-m"initialized"(4)開始在工作區(qū)中修改文件并提交。$svnci(5)如果對(duì)修改結(jié)果滿意,可以通過創(chuàng)建補(bǔ)丁文件的方式將工作成果保存并帶走。但是SVN很難針對(duì)每次提交逐一創(chuàng)建補(bǔ)丁,一般用下面的命令與最早的提交進(jìn)行比較,以創(chuàng)建出一個(gè)大補(bǔ)丁文件。$svndiff-r1>hacks.patch上面用SVN將工作成果導(dǎo)出的過程存在一個(gè)致命的缺陷,就是SVN的補(bǔ)丁文件不支持二進(jìn)制文件,因此采用補(bǔ)丁文件的方式有可能丟失數(shù)據(jù),如新增或修改的圖形文件會(huì)丟失。更為穩(wěn)妥但也更為復(fù)雜的方式可能要用到svnadmin命令將版本庫導(dǎo)出。命令如下:$svnadmindump--incremental-r2:HEAD\/path/to/repos/project1/>hacks.dump將svnadmin命令創(chuàng)建的導(dǎo)出文件恢復(fù)到版本庫中也非常具有挑戰(zhàn)性,這里就不再詳細(xì)說明了。還是來看看Git在這種情況下的表現(xiàn)吧。2.Git的解決方案與SVN將產(chǎn)品部署目錄轉(zhuǎn)化為SVN的工作區(qū)相比,Git要更為簡(jiǎn)單,而且使用Git導(dǎo)出提交歷史也更為簡(jiǎn)單和實(shí)用,具體操作過程如下。(1)創(chuàng)建現(xiàn)場(chǎng)版本庫。直接在需要版本控制的目錄下執(zhí)行Git版本庫初始化命令。$gitinit(2)添加文件并提交。$gitadd-A$gitcommit-m"initialized"(3)為初始提交建立一個(gè)里程碑:"v1"。$gittagv1(4)開始在工作區(qū)中工作——修改文件并提交。$gitcommit-a(5)當(dāng)對(duì)修改結(jié)果滿意并想將工作成果保存帶走時(shí),可以通過下面的命令將從v1開始的歷次提交逐一導(dǎo)出為補(bǔ)丁文件。轉(zhuǎn)換的補(bǔ)丁文件都包含一個(gè)數(shù)字前綴,并提取提交日志信息作為文件名,而且補(bǔ)丁文件還提供對(duì)二進(jìn)制文件的支持。下面命令的輸出摘自本書第3篇第20章中的實(shí)例。$gitformat-patchv1..HEAD0001-Fix-typo-help-to-help.patch0002-Add-I18N-support.patch0003-Translate-for-Chinese.patch(6)通過郵件將補(bǔ)丁文件發(fā)出。當(dāng)然,也可以通過其他方式將補(bǔ)丁文件帶走。$gitsend-email*.patchGit創(chuàng)建的補(bǔ)丁文件使用了Git擴(kuò)展格式,因此在導(dǎo)入時(shí)為了避免數(shù)據(jù)遺漏,要使用Git提供的命令而不能使用GNU的patch命令。即使要導(dǎo)入的不是Git版本庫,也可以使用Git命令,具體操作請(qǐng)參見本書第7篇第38章中的相關(guān)內(nèi)容。2.4避免引入輔助目錄很多版本控制系統(tǒng)都要在工作區(qū)中引入輔助目錄或文件,如SVN要在工作區(qū)的每一個(gè)子目錄下都創(chuàng)建.svn目錄,CVS要在工作區(qū)的每一個(gè)子目錄下都創(chuàng)建CVS目錄。這些輔助目錄如果出現(xiàn)在服務(wù)器上,尤其是Web服務(wù)器上是非常危險(xiǎn)的,因?yàn)檫@些輔助目錄下的Entries文件會(huì)暴露出目錄下的文件列表,讓管理員精心配置的禁止目錄瀏覽的努力全部白費(fèi)。還有,SVN的.svn輔助目錄下還存在文件的原始拷貝,在文件搜索時(shí)結(jié)果會(huì)加倍。如果你曾經(jīng)在SVN的工作區(qū)用過grep命令進(jìn)行內(nèi)容查找,就會(huì)明白我指的是什么。Git沒有這個(gè)問題,不會(huì)在子目錄下引入討厭的輔助目錄或文件(.gitignore和.gitattributes文件不算)。當(dāng)然,Git還是要在工作區(qū)的頂級(jí)目錄下創(chuàng)建名為.git的目錄(版本庫目錄),不過,如果你認(rèn)為唯一的一個(gè).git目錄也過于礙眼,可以將其放到工作區(qū)之外的任意目錄。一旦這么做了,在執(zhí)行Git命令時(shí),就要通過命令行(--git-dir)或環(huán)境變量GIT_DIR為工作區(qū)指定版本庫目錄,甚至還要指定工作區(qū)目錄。Git還專門提供了一個(gè)gitgrep命令,這樣在工作區(qū)根目錄下執(zhí)行查找時(shí),目錄.git也不會(huì)對(duì)搜索造成影響。關(guān)于輔助目錄的詳細(xì)討論請(qǐng)參見本書第2篇第4.2節(jié)中的內(nèi)容。2.5重寫提交說明很多人可能像我一樣,在敲下回車之后才發(fā)現(xiàn)提交說明中有錯(cuò)別字,或忘記了寫關(guān)聯(lián)的BugID,此時(shí)就需要重寫提交說明。1.SVN的解決方案在默認(rèn)情況下,SVN的提交說明是禁止更改的,因?yàn)镾VN的提交說明屬于不受版本控制的屬性,一旦修改就不可恢復(fù)。我建議SVN的管理員只有在配置了版本庫更改的外發(fā)郵件通知之后,再開放提交說明更改的功能。我發(fā)布于SourceForge上的pySvnManager項(xiàng)目提供了SVN版本庫圖形化的鉤子管理,會(huì)簡(jiǎn)化管理員的配置工作。即使SVN管理員啟用了允許更改提交說明的設(shè)置,修改提交說明也還是挺復(fù)雜的,看看下面的命令:$svnps--revprop-r<REV>svn:log"newlogmessage..."2.Git的解決方案Git修改提交說明很簡(jiǎn)單,而且提交說明的修改也是被追蹤的。Git修改最新提交的提交說明最為簡(jiǎn)單,使用一條名為修補(bǔ)提交的命令即可。$gitcommit--amend這個(gè)命令如果不帶-m參數(shù),會(huì)進(jìn)入提交說明編輯界面,修改原來的提交說明,直到滿意為止。如果要修改某個(gè)歷史提交的提交說明,Git也可以實(shí)現(xiàn),但要用到另外一個(gè)命令:變基命令。例如,要修改<commit-id>所標(biāo)識(shí)的提交的提交說明,執(zhí)行下面的命令,并在彈出的變基索引文件中修改相應(yīng)提交前面的動(dòng)作的關(guān)鍵字。$gitrebase-i<commit-id>^關(guān)于如何使用交互式變基操作更改歷史提交的提交說明,請(qǐng)參見本書第2篇第12章中的內(nèi)容。2.6想吃后悔藥假如提交的數(shù)據(jù)中不小心包含了一個(gè)不應(yīng)該檢入的虛擬機(jī)文件——大約有1個(gè)GB!這時(shí)候,您會(huì)多么希望這個(gè)世界上有后悔藥賣啊。1.SVN的解決方案SVN遇到這個(gè)問題該怎么辦呢?刪除錯(cuò)誤加入的大文件后再提交,這樣的操作是不能解決問題的。雖然表面上去掉了這個(gè)文件,但是它依然存在于歷史中。管理員可能是受影響最大的人,因?yàn)樗?fù)責(zé)管理服務(wù)器的磁盤空間占用及版本庫的備份。實(shí)際上這個(gè)問題也只有管理員才能解決,所以你必須向管理員坦白,讓他幫你在服務(wù)器端徹底刪除錯(cuò)誤引入的大文件。我要告訴你的是,對(duì)于管理員,這并不是一個(gè)簡(jiǎn)單的活。(1)如果SVN管理員沒有歷史備份,只能重新用svnadmindump導(dǎo)出整個(gè)版本庫。(2)再用svndumpfilter命令過濾掉不應(yīng)檢入的大文件。(3)然后用svnadminload重建版本庫。上面的操作描述中省略了一些竅門,如果要把竅門講清楚,這本書就不是講Git,而是講SVN了,故本書中不進(jìn)行深入探討。2.Git的解決方案如果你用Git,一切就會(huì)變得非常簡(jiǎn)單,而且你也不必去乞求管理員,因?yàn)槭褂肎it,每個(gè)人都是管理員。如果是最新的提交引入了不該提交的大文件:winxp.img,操作起來會(huì)非常簡(jiǎn)單,還是用修補(bǔ)提交命令。$gitrm--cachedwinxp.img$gitcommit--amend如果是歷史版本,例如是在<commit-id>所標(biāo)識(shí)的提交中引入的文件,則需要使用變基操作。$gitrebase-i<commit-id>^執(zhí)行交互式變基操作拋棄歷史提交,版本庫還不能立即瘦身,具體原因和解決方案請(qǐng)參見本書第2篇第14章中的內(nèi)容。除了使用變基操作,Git還有更多的武器可以實(shí)現(xiàn)版本庫的整理操作,具體請(qǐng)參見本書第6篇第35.4節(jié)的內(nèi)容。2.7更好用的提交列表正確的版本控制系統(tǒng)的使用方法是,一次提交只干一件事:或是完成了一個(gè)新功能,或是修改了一個(gè)Bug、或是寫完了一節(jié)的內(nèi)容,或是添加了一幅圖片,就執(zhí)行一次提交。不要在下班時(shí)才想起來要提交,那樣的話版本控制系統(tǒng)就被降格為文件備份系統(tǒng)了。但有時(shí)在同一個(gè)工作區(qū)中可能要同時(shí)做兩件事情:一個(gè)是尚未完成的新功能,另外一個(gè)是解決剛剛發(fā)現(xiàn)的Bug。很多版本控制系統(tǒng)沒有提交列表的概念,要么需要在命令行中指定要提交的文件,要么默認(rèn)把所有修改內(nèi)容全部提交,破壞了一次提交只干一件事的原則。1.SVN的解決方案SVN1.5開始提供變更列表(changelist)的功能,是通過引入一個(gè)新的命令svnchangelist來實(shí)現(xiàn)的。但是我從來就沒有真正用過,因?yàn)椋憾x一個(gè)變更列表太麻煩。例如,沒有一個(gè)快捷命令將當(dāng)前所有改動(dòng)的文件加入列表,也沒有快捷命令將工作區(qū)中的新文件全部加入列表。一個(gè)文件不能同時(shí)屬于兩個(gè)變更列表。兩次變更不許有文件交叉,這樣的限制不合理。變更列表是一次性的,提交之后自動(dòng)消失。這樣的設(shè)計(jì)沒有問題,但是相比定義列表時(shí)的繁瑣,以及提交時(shí)必須指定列表的繁瑣,使用變更列表未免得不償失。因?yàn)镾ubversion的提交不能撤銷,如果在提交時(shí)忘了提供變更列表名稱以針對(duì)特定的變更列表進(jìn)行提交,錯(cuò)誤的提交內(nèi)容將無法補(bǔ)救??傊琒VN的變更列表尚不如雞肋,食之無味,棄之不可惜。2.Git的解決方案Git通過提交暫存區(qū)實(shí)現(xiàn)對(duì)提交內(nèi)容的定制,非常完美地實(shí)現(xiàn)了對(duì)工作區(qū)的修改內(nèi)容進(jìn)行篩選提交:執(zhí)行g(shù)itadd命令將修改內(nèi)容加入提交暫存區(qū)。執(zhí)行g(shù)itadd-u命令可以將所有修改過的文件加入暫存區(qū),執(zhí)行g(shù)itadd-A命令可以將本地刪除文件和新增文件都登記到提交暫存區(qū),執(zhí)行g(shù)itadd-p命令甚至可以對(duì)一個(gè)文件內(nèi)的修改進(jìn)行有選擇性的添加。一個(gè)修改后的文件被登記到提交暫存區(qū)后,可以繼續(xù)修改,繼續(xù)修改的內(nèi)容不會(huì)被提交,除非對(duì)此文件再執(zhí)行一次gitadd命令。即一個(gè)修改的文件可以擁有兩個(gè)版本,在提交暫存區(qū)中有一個(gè)版本,在工作區(qū)中有另外一個(gè)版本。執(zhí)行g(shù)itcommit命令提交,無須設(shè)定變更列表,直接將登記在暫存區(qū)中的內(nèi)容提交。Git支持撤銷提交,而且可以撤銷任意多次。只要使用Git,就會(huì)時(shí)刻與隱形的提交列表打交道。本書第2篇第5章會(huì)詳細(xì)介紹Git的這一特性,相信你會(huì)愛上Git的這個(gè)特性。2.8更好的差異比較Git對(duì)差異比較進(jìn)行了擴(kuò)展,支持對(duì)二進(jìn)制文件的差異比較,這是對(duì)GNU的diff和patch命令的重要補(bǔ)充。而且Git的差異比較除了支持基于行的差異比較外,還支持在一行內(nèi)逐字比較的方式,當(dāng)向gitdiff命令傳遞--word-diff參數(shù)時(shí),就會(huì)進(jìn)行逐字比較。上面介紹了工作區(qū)的文件修改可能會(huì)有兩個(gè)不同的版本:一個(gè)在提交暫存區(qū),一個(gè)在工作區(qū)。因此,在執(zhí)行g(shù)itdiff命令時(shí)會(huì)遇到令Git新手費(fèi)解的現(xiàn)象。修改后的文件在執(zhí)行g(shù)itdiff命令時(shí)會(huì)看到修改造成的差異。修改后的文件通過gitadd命令提交到暫存區(qū)后,再執(zhí)行g(shù)itdiff命令將看不到該文件的差異。繼續(xù)對(duì)此文件進(jìn)行修改,再次執(zhí)行g(shù)itdiff命令會(huì)看到新的修改顯示在差異中,而看不到舊的修改。執(zhí)行g(shù)itdiff--cached命令才可以看到添加到暫存區(qū)中的文件所做出的修改。Git差異比較的命令充滿了魔法,本書第5.3節(jié)會(huì)帶您破解Git的diff魔法。一旦您習(xí)慣了,就會(huì)非常喜歡gitdiff的這個(gè)行為。2.9工作進(jìn)度保存如果在工作區(qū)的修改尚未完成時(shí)忽然有一個(gè)緊急的任務(wù),需要從一個(gè)干凈的工作區(qū)開始新的工作,或要切換到別的分支進(jìn)行工作,那么如何保存當(dāng)前尚未完成的工作進(jìn)度呢?1.SVN的解決方案如果版本庫規(guī)模不大,最好重新檢出一個(gè)新的工作區(qū),在新的工作區(qū)進(jìn)行工作。否則,可以執(zhí)行下面的操作。$svndiff>/path/to/saved/patch.file$svnrevert-R$svnswitch<new_branch>在新的分支中工作完畢后,再切換回當(dāng)前分支,將補(bǔ)丁文件重新應(yīng)用到工作區(qū)。$svnswitch<o(jì)riginal_branch>$patch-p1</path/to/saved/patch.file但是切記SVN的補(bǔ)丁文件不支持二進(jìn)制文件,這種操作方法可能會(huì)丟失對(duì)二進(jìn)制文件的更改!2.Git的解決方案Git提供了一個(gè)可以保存和恢復(fù)工作進(jìn)度的命令gitstash。這個(gè)命令非常方便地解決了這個(gè)難題。在切換到新的工作分支之前執(zhí)行g(shù)itstash保存工作進(jìn)度,工作區(qū)就會(huì)變得非常干凈,然后就可以切換到新的分支中了。$gitstash$gitcheckout<new_branch>新的工作分支修改完畢后,再切換回當(dāng)前分支,調(diào)用gitstashpop命令則可恢復(fù)之前保存的工作進(jìn)度。$gitcheckout<o(jì)rignal_branch>$gitstashpop本書第2篇第9章會(huì)為您揭開gitstash命令的奧秘。2.10代理SVN提交實(shí)現(xiàn)移動(dòng)式辦公使用像SVN一樣的集中式版本控制系統(tǒng),要求使用者和版本控制服務(wù)器之間要有網(wǎng)絡(luò)連接,如果因?yàn)槌霾钤谕饣蛟诩肄k公訪問不到版本控制服務(wù)器就無法提交。Git屬于分布式版本控制系統(tǒng),不存在這樣的問題。當(dāng)版本控制服務(wù)器無法實(shí)現(xiàn)從SVN到Git的遷移時(shí),仍然可以使用Git進(jìn)行工作。在這種情況下,Git作為客戶端來操作SVN服務(wù)器,實(shí)現(xiàn)在移動(dòng)辦公狀態(tài)下的版本提交(當(dāng)然是在本地Git庫中提交)。當(dāng)能夠連通SVN服務(wù)器時(shí),一次性將移動(dòng)辦公狀態(tài)下的本地提交同步到SVN服務(wù)器。整個(gè)過程對(duì)于SVN來說是透明的,沒有人知道你是使用Git在進(jìn)行提交。使用Git來操作SVN版本控制服務(wù)器的一般工作流程為:(1)訪問SVN服務(wù)器,將SVN版本庫克隆為一個(gè)本地的Git庫,一個(gè)貨真價(jià)實(shí)的Git庫,不過其中包含針對(duì)SVN的擴(kuò)展。$gitsvnclone<svn_repos_url>(2)使用Git命令操作本地克隆的版本庫,例如提交就使用gitcommit命令。(3)當(dāng)能夠通過網(wǎng)絡(luò)連接到SVN服務(wù)器,并想將本地提交同步到SVN服務(wù)器時(shí),先獲取SVN服務(wù)器上最新的提交,然后執(zhí)行變基操作,最后再將本地提交推送給SVN服務(wù)器。$gitsvnfetch$gitsvnrebase$gitsvndcommit本書第4篇第26章會(huì)詳細(xì)介紹這一話題。2.11無處不在的分頁器雖然擁有圖形化的客戶端,但Git的主要操作還是以命令行的方式完成的。使用命令行方式的好處一個(gè)是快,另外一個(gè)是可以防止鼠標(biāo)手的出現(xiàn)。Git的命令行加入了大量的人性化設(shè)計(jì),包括命令補(bǔ)全、彩色字符輸出\h[1]等,不過最具特色的還是無處不在的分頁器。在操作其他版本控制系統(tǒng)的命令行時(shí),如果命令的輸出超過了一屏,為了能夠逐屏顯示,需要在命令的后面加上一個(gè)管道符號(hào)將輸出交給一個(gè)分頁器。例如:$svnlog|less而Git則不用如此麻煩,因?yàn)槊總€(gè)Git命令自動(dòng)帶有一個(gè)分頁器,默認(rèn)使用less命令(less-FRSX)進(jìn)行分頁。當(dāng)一屏顯示不下時(shí)啟動(dòng)分頁器,這個(gè)分頁器支持帶顏色的字符輸出,對(duì)于太長(zhǎng)的行則采用截?cái)喾绞教幚?。因?yàn)閘ess分頁器在翻屏?xí)r使用了vi風(fēng)格的熱鍵,如果您不熟悉vi的話,可能會(huì)遇到麻煩。下面是分頁器中常用的熱鍵:字母q:退出分頁器。字母h:顯示分頁器幫助。按空格下翻一頁,按字母b上翻一頁。字母d和u:分別代表向下翻動(dòng)半頁和向上翻動(dòng)半頁。字母j和k:分別代表向上翻一行和向下翻一行。如果行太長(zhǎng)被截?cái)?,可以用左箭頭和右箭頭使窗口內(nèi)容左右滾動(dòng)。輸入/pattern:向下尋找和pattern匹配的內(nèi)容。輸入?pattern:向上尋找和pattern匹配的內(nèi)容。字母n或N:代表向前或向后繼續(xù)尋找。字母g:跳到第一行;字母G:跳到最后一行;輸入數(shù)字再加字母g:則跳轉(zhuǎn)到對(duì)應(yīng)的行。輸入!<command>:可以執(zhí)行Shell命令。如果不習(xí)慣分頁器的長(zhǎng)行截?cái)嗄J蕉M軌蜃詣?dòng)換行,可以通過設(shè)置LESS環(huán)境變量來實(shí)現(xiàn)。LESS環(huán)境變量設(shè)置如下:$exportLESS=FRX或者使用Git的方式,通過定義Git配置變量來改變分頁器的默認(rèn)行為。例如設(shè)置core.pager配置變量如下:$gitconfig--globalcore.pager'less-+$LESS-FRX'\h[1]須通過Git配置變量啟用,如運(yùn)行命令:gitconfig--globalcolor.uitrue2.12快您有項(xiàng)目托管在的CVS或SVN服務(wù)器上么?是否會(huì)因?yàn)楣镜腟VN服務(wù)器部署在另外一個(gè)城市而需要經(jīng)過互聯(lián)網(wǎng)才能訪問?使用傳統(tǒng)的集中式版本控制服務(wù)器時(shí),如果遇到上面的情況,而且網(wǎng)絡(luò)帶寬沒有保證,那么使用起來時(shí)一定會(huì)因?yàn)樗俣嚷屓送纯嗖豢?。Git作為分布式版本控制系統(tǒng)徹底解決了這個(gè)問題,幾乎所有的操作都在本地進(jìn)行,而且速度還不是一般的快。還有很多其他的分布式版本控制系統(tǒng),如Hg和Bazaar等,與這些分布式版本控制系統(tǒng)相比,Git在速度上也有優(yōu)勢(shì),這得益于Git獨(dú)特的版本庫設(shè)計(jì)。第2篇的相關(guān)章節(jié)會(huì)向您展示Git獨(dú)特的版本庫設(shè)計(jì)。其他很多的版本控制系統(tǒng),當(dāng)輸入檢出、更新或克隆等命令后,只能雙手合十,然后望眼欲穿,因?yàn)檎麄€(gè)操作過程不知道什么時(shí)候才能夠完成。而Git在版本庫克隆及與版本庫同步的時(shí)候,能夠?qū)崟r(shí)地顯示完成的進(jìn)度,這不但是非常人性化的設(shè)計(jì),更體現(xiàn)了Git的智能。Git的智能協(xié)議源自于會(huì)話過程中在客戶端和服務(wù)器端各自啟用了一個(gè)會(huì)話的角色,用于按需傳輸和獲取進(jìn)度。第3章Git的安裝和使用Git源自Linux,現(xiàn)在已經(jīng)可以部署在所有的主流平臺(tái)之上,包括Linux、MacOSX和Windows。我們?cè)陂_始Git之旅之前,首先要做的就是安裝Git。3.1在Linux下安裝和使用GitGit誕生于Linux平臺(tái)并作為版本控制系統(tǒng)率先服務(wù)于Linux內(nèi)核,因此在Linux上安裝Git是非常方便的。可以通過兩種不同的方式在Linux上安裝Git:一種方法是通過Linux發(fā)行版的包管理器安裝已經(jīng)編譯好的二進(jìn)制格式的Git軟件包,另外一種方式就是從Git源碼開始安裝。3.1.1包管理器方式安裝用Linux發(fā)行版的包管理器安裝Git最為簡(jiǎn)單,而且會(huì)自動(dòng)配置好命令補(bǔ)齊等功能,但安裝的Git可能不是最新的版本。還有一點(diǎn)要注意,Git軟件包在有的Linux發(fā)行版中可能不叫g(shù)it,而叫g(shù)it-core。這是因?yàn)橛幸豢蠲麨镚NU交互工具\(yùn)h[1](GNUInteractiveTools)的GNU軟件,在Git之前就在一些Linux發(fā)行版(Deianlenny)中占用了git這個(gè)名稱。為了以示區(qū)分,作為版本控制系統(tǒng)的Git,其軟件包在這些平臺(tái)就被命名為git-core。不過,因?yàn)樽鳛榘姹究刂葡到y(tǒng)的Git太有名了,所以一些Linux發(fā)行版在最新的版本中將GNUInteractiveTools軟件包的名稱由git改為了gnuit,將git-core改為了git。因此在下面介紹的在不同的Linux發(fā)行版中安裝Git時(shí),會(huì)看到有g(shù)it和git-core兩個(gè)不同的名稱。Ubuntu10.10(maverick)或更新的版本、Debian(
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2026年工業(yè)自動(dòng)化控制技術(shù)專業(yè)試題集
- 2026年基于大數(shù)據(jù)的AI算法分析與應(yīng)用專業(yè)試題
- 2026年法律法規(guī)多體系交叉認(rèn)證模擬題
- 2026年軟件工程項(xiàng)目管理技能實(shí)操試題
- 2026年法考法理學(xué)考題集法治理論與實(shí)務(wù)要點(diǎn)精講
- 2026年建筑裝飾裝修設(shè)計(jì)與施工管理試題室內(nèi)空間設(shè)計(jì)原理
- 2026年健康管理與慢性疾病預(yù)防知識(shí)競(jìng)賽挑戰(zhàn)題
- 2026年注冊(cè)會(huì)計(jì)師考試練習(xí)題庫及答案速查
- 新產(chǎn)品開發(fā)設(shè)計(jì)程序課件
- 2026年互聯(lián)網(wǎng)產(chǎn)品設(shè)計(jì)與用戶體驗(yàn)分析試題
- 2024四川綿陽涪城區(qū)事業(yè)單位選調(diào)(聘)筆試管理單位遴選500模擬題附帶答案詳解
- 發(fā)貨組年終總結(jié)
- 《化工制圖》試題及參考答案 (C卷)
- 2024年普通高等學(xué)校招生全國(guó)統(tǒng)一考試政治試題全國(guó)乙卷含解析
- 醫(yī)學(xué)影像設(shè)備更新項(xiàng)目資金申請(qǐng)報(bào)告-超長(zhǎng)期特別國(guó)債投資專項(xiàng)
- 新疆維吾爾自治區(qū)伊犁哈薩克自治州2023-2024學(xué)年八年級(jí)下學(xué)期期中數(shù)學(xué)試題
- 2024 年咨詢工程師《工程項(xiàng)目組織與管理》猛龍過江口袋書
- 人工智能在專業(yè)通信領(lǐng)域的應(yīng)用
- 人教版四年級(jí)《上冊(cè)語文》期末試卷(附答案)
- 醫(yī)院婦產(chǎn)科醫(yī)學(xué)病例匯報(bào)PPT
- 中小河流綜合整治工程監(jiān)理工作報(bào)告
評(píng)論
0/150
提交評(píng)論