最近來了一些newguys,版本控制工具全部開始遷移到Git上來.原來都是老CVS或SVN的用戶. 所以打算把內部Wiki上比較兩篇粗糙Git的入門文章操作重寫一遍.在本篇中全面解析git概念和基礎使用方法.
在寫的這篇文章時.在思考.應該如何快速切入理解Git的基本使用?相對Linux操作系統下分布式版本控制工具.很多操作中都直接采用命令的方式來做.可更多Windows 開發人員習慣的是直觀的用戶操作界面.復雜的指令是Git在Linux本身具有的特點.而Windows 上UI不足也可以使用工具加以彌補.圖形化工具(無論是 git extentions ,還是TortoiseGit),都只不過是命令行的封裝。就功能而言,命令行全部可以做到;但命令行能做的,他們不一定可以做到。命令行更加原生、本色,跨越平台之間局限.
so。本篇就以git 命令行操作方式逐步切入.至於一些圖形化工具會在下篇講到.
<1>Git基礎概念
Git—The Stupid Content Tracker-俗稱傻瓜內容跟蹤器.Linus Benedict Torvalds-Linus之父在官方的Wiki中自嘲的取了這個名字.官方給出解釋如下:
I'm an egotistical bastard, and I name all my projects after myself. First Linux, now git.
Git最初是用於Linux內核開發的一個版本控制工具.從2002年起,Linux 內核一直使用BitKeeper來進行版本管理,但是在2005年BitKeeper和Linux 內核開源社區的合作關系結束,BitKeeper再也不能免費使用了,這迫使Linus決定開發一個開源界自已的版本控制系統.與常用的版本控制CVS、Subversion等均不同.它采用分布式的版本庫控制方式.相對於CVS或SVN. Git並不需要服務器端軟件的支持.Git的速度很快.它的本地操作速度和本地文件系統在一個級別,遠程倉庫的操作速度和SFTP文件傳輸在一個級別.至於如何實現的可以看看Git內部實現機制.Git is the next Unix.這對於諸如 Linux kernel 這樣的大項目來說自然很重要。 Git 最為出色的是它的合並跟蹤[merge tracing]能力.
Git最初的開發動力來自於BitKeeper和Monotone[2][3]。 Git最初只是作為一個可以被其他前端比如Cogito 或 StGIT[4]包裝的后端而開發的。不過,后來Git內核已經成熟到可以獨立地用作版本控制[5]。很多有名的軟件都使用Git來進行版本控制[6],其中有Linux內核、X.Org服務器和OLPC內核開發.
<2>Git基礎使用
其實如果你是一個原來使用過CVS到SVN.或是也經歷從VSS遷移到TFS.你會發現版本控制管理模式從集中向分散演變.這也是因為現在的很多開發團隊變得越來越分散,原來微軟的Visual SourceSafe和Team Foundation Server這樣的集中式源代碼控制系統很難保持其吸引力.而Git作為分布式版本控制工具.逐漸在.NET 社區開始廣泛使用.
了解Git一些基礎概念.如下篇幅來了解Git在實際項目中使用.在使用Git之前需要安裝對應Git工具.相對於Windows 平台.可選安裝軟件有兩個:
Windows 安裝工具:
Windows平台有兩個模擬*nix like運行環境的工具:cygwin,msys;Git在cygwin,msys下都有相應的移植版本.工具下載:
TortoiseGit-[http://code.google.com/p/tortoisegit/downloads/list]
Msysgit-[http://code.google.com/p/msysgit/downloads/list]
注:前者是與Windows 資源管理器整合的Git管理工具.后者是Git的功能軟件.個人覺得msys平台下的msysGit最好用.推薦使用.
本篇Git操作演示均采用MsysGit工具.安裝過程沒什么可提的.在設置Git Setup時:
由於windows平台的換行符(CRLF)和Linux(*nix)平台的換行符(LF)不同,那么在windows下開發最好選“Checkout as-is, commit as-is”這個選項,這樣,Git就不會修改你代碼的換行符風格。
安裝完成后需要配置Git.在Linux下,可以在命令行里直接使用git config進行配置, 而在windows下則要先打開“Git Bash”,進入msysGit命令行界面,再用git config命令進行相應的配置操作.打開Git Bash.首先需要配置的UserName用戶名和Email.這回在每次Git操作日志出現:
Git的配置信息分為全局和項目兩種,上面命令中帶了“--global"參數,這就意味是在進行全局配置,它會影響本機上的每個一個Git項目.為了演示目的這里首先建立一個用來測試操作的倉庫,首先在默認路徑下創建一個倉庫目錄.並在該目錄下創建一個倉庫:
mkDir創建一個測試倉庫目錄demogitdir,Cd 則是進入該目錄. git init 指令在當前目錄下創建一個測試操作的倉庫.有了可操作的倉庫.可以添加一個任意內容的文件到倉庫並提交:
echo 則是把”hello git tool”內容寫入到sayhello.txt文件中. git add則是把該文件添加暫存區. 通過git commit指令則提交到默認的當前的倉庫中.可以通過Git Log查看當前的提交記錄.也可以在記錄中看到Git設置的用戶名和Email.:
在log能看到Commit 后根據一段“8223db3b064a9826375041c8fea020cb2e3b17d1” SHA1串.Git通過對提交內容進行 SHA1 Hash運算,得到它們的SHA1串值,作為每個提交的唯一標識。根據一般的密碼學原理來說,如果兩個提交的內容不相同,那么它們的名字就不會相同;反之,如果它們的名字相同,就意味着它們的內容也相同.現在修改一下剛創建的文件內容 並提交到倉庫中,在來查看該文件與第一個保存版本之間存在的不同:
在原來基礎上添加字符串chenkai modify.這時可以提交並查看當前git 狀態和日志.有具體的庫.在回過頭看看GitConfig具體的配置.在Git bash中可以通過cat /Head指令獲取當前庫GitConfig中配置 比如獲取剛才設置用戶名和Email:
很多剛操作對git config配置不熟悉.可以直接找到對應根目錄下GitConfig文件直接修改也可以達到同樣的效果.當然也可以通過git config –list獲取全部配置信息.
通過如上Git 一些指令操作是即使你不了解Git原理前提下 是否有了一個感性的認識.如下來挖掘Git設計原則和工作原理.
<3>Git演變歷程
其實要理解Git這個版本控制工具由來過程.以及演變到今天具有分布式特點.從版本控制最原始角度來分析.它突顯特點最容易理解的角度.開發人員最容易在使用工具往往注重學會它如何去使用 而忽略這些建立功能背后所解決問題.如果我們能夠從Git本身設計原則上看到解決問題.就自然會理解Git版本工具優勢特點在哪里.才不會在使用過程純粹為了使用Git而學習.同樣要在使用過程中理解其演變過程.知其所以然.用起來才能游刃有余.
什么版本控制?
版本控制是一種記錄若干文件內容變化,以便將來查閱特定版本修訂情況的系統
嚴格意義來說版本控制文件可以是任何文本文件.而我們突出是對源代碼文本文件版本控制管理.
在最原始版本控制中.習慣用復制整個項目目錄的方式來保存不同的版本,或許還會改名加上備份時間以示區別.這樣的方式很簡單.但存在問題也不少.容易混淆工作目錄.版本之間沒有交互實現版本指教差異跟蹤等.未解決這個問題在最開始設計多種本地版本控制系統,大多都是采用某種簡單的數據庫來記錄文件的歷次更新差異,具體構成:
最流行的一種叫做 rcs,現今許多計算機系統上都還看得到它的蹤影。甚至在流行的 Mac OS X 系統上安裝了開發者工具包之后,也可以使用 rcs 命令。它的工作原理基本上就是保存並管理文件補丁(patch)。文件補丁是一種特定格式的文本文件,記錄着對應文件修訂前后的內容變化。所以,根據每次修訂后的補丁,rcs 可以通過不斷打補丁,計算出各個版本的文件內容。這個特點甚至影響后來的CVS和SVN設計.現在依然能夠在SVN中看到,版本之間需要作出補丁包.
雖然解決了能夠通過數據控制版本之間變化.但在實際操作又要面對新問題-如何讓在不同系統上的開發者協同工作?於是,集中化的版本控制系統( Centralized Version Control Systems,簡稱 CVCS )應運而生。這類系統,諸如 CVS,Subversion 以及 Perforce 等,都有一個單一的集中管理的服務器,保存所有文件的修訂版本,而協同工作的人們都通過客戶端連到這台服務器,取出最新的文件或者提交更新。多年以來,這已成為版本控制系統的標准做法,結構成圖:
這種做法的好處是:
相較於老式的本地 VCS 來說。現在,每個人都可以一定程度上看到項目中的其他人正在做些什么。而管理員也可以輕松掌控每個開發者的權限,並且管理一個 CVCS 要遠比在各個客戶端上維護本地數據庫輕松容易得多
壞處以及遺留難以處理的問題是:
最顯而易見的缺點是中央服務器的單點故障。若是宕機一小時,那么在這一小時內,誰都無法提交更新,也就無法協同工作。如果中央服務器的磁盤發生故障,並且沒做過備份或者備份得不夠及時的話,還會有丟失數據的風險。最壞的情況是徹底丟失整個項目的所有歷史更改記錄,被客戶端提取出來的某些快照數據除外,但這樣的話依然是個問題,你不能保證所有的數據都已經有人提取出來。本地版本控制系統也存在類似問題,只要整個項目的歷史記錄被保存在單一位置,就有丟失所有歷史更新信息的風險.
well.新的需求出現總是不斷推動新的工具推出.緊接着.為了解決集中化版本控制中存在種種問題.同時繼承原有的特點.分布式版本控制系統( Distributed Version Control System,簡稱 DVCS )面世了。在這類系統中,諸如 Git,Mercurial,Bazaar 還有 Darcs 等,客戶端並不只提取最新版本的文件快照,而是把原始的代碼倉庫完整地鏡像下來。這么一來,任何一處協同工作用的服務器發生故障,事后都可以用任何一個鏡像出來的本地倉庫恢復。因為每一次的提取操作,實際上都是一次對代碼倉庫的完整備份,結構分析截圖:
well 有了Git這種分布式工具.許多這類系統都可以指定和若干不同的遠端代碼倉庫進行交互。籍此,你就可以在同一個項目中,分別和不同工作小組的人相互協作。你可以根據需要設定不同的協作流程,比方說層次模型式的工作流,這在以前的集中式系統中是無法實現的.
從05開始其Linux開源社區為了不重蹈覆轍.決定基於Linux操作系統開發一個新版版本控制工具.就是我們今天見到的Git.當時開發團隊對Git工具 設計目標作了如下的設想:
Git 設計目標:
- 速度
- 簡單的設計
- 對非線性開發模式的強力支持(允許上千個並行開發的分支)
- 完全分布式
- 有能力高效管理類似 Linux 內核一樣的超大規模項目(速度和數據量)]
從05年至今.經過Linux開源社區推動.Git逐漸成熟.同時對演變對其他Windows MAC平台支持.
<4>Git構建原理
其實很多人從CVS或是SVN過渡而來的用戶,在使用指令操作方式依然能夠粗類旁通.其實在原理層次2者之間並無可比性.反而從SVN過來而來用戶在理解總是存在一個對比的概念.Git 和其他版本控制系統的主要差別在於,Git 只關心文件數據的整體是否發生變化,而大多數其他系統則只關心文件內容的具體差異。這類系統(CVS,Subversion,Perforce,Bazaar 等等)每次記錄有哪些文件作了更新,以及都更新了哪些行的什么內容,構圖吐下:
而Git在對基本文件操作完全不同.Git 並不保存這些前后變化的差異數據。實際上,Git 更像是把變化的文件作快照后,記錄在一個微型的文件系統中。每次提交更新時,它會縱覽一遍所有文件的指紋信息並對文件作一快照,然后保存一個指向這次快照的索引。為提高性能,若文件沒有變化,Git 不會再次保存,而只對上次保存的快照作一連接。Git 的工作方式如下:
這是 Git 同其他系統的重要區別。它完全顛覆了傳統版本控制的套路,並對各個環節的實現方式作了新的設計。Git 更像是個小型的文件系統,但它同時還提供了許多以此為基礎的超強工具,而不只是一個簡單的 VCS.
因Git在底層的設計.本身具有的操作特點也不同於其他版本控制工具.具體表現如下幾點.
A:所有操作幾乎在本地運行.
Git 中的絕大多數操作都只需要訪問本地文件和資源,不用連網。但如果用 CVCS 的話,差不多所有操作都需要連接網絡。因為 Git 在本地磁盤上就保存着所有有關當前項目的歷史更新,所以這也就不難解釋Git的處理起來速度飛快特點.
Git這點能讓開發人員.在大的項目結構下.隨時隨地在不用連接服務器的情況下查看版本之間差異.而不是采用SVN的方式通過請求服務器端運算獲取差異.引文每次版本更新都能夠拿到本地存在最新代碼的快照.以后所有的操作都可以基於本地的Code進行.而無需請求服務器端.
這樣一來可以讓開發人員隨意修改本地的Code.在存在網絡的情況時通過Push操作吧更改上傳遠程的鏡像上.換作其他版本控制系統,這么做幾乎不可能,抑或非常麻煩,例如:Subversion 或 CVS,雖然可以編輯文件,但無法提交更新,因為數據庫在網絡上.
B:時刻保持數據完整性
在保存到 Git 之前,所有數據都要進行內容的校驗和(checksum)計算,並將此結果作為數據的唯一標識和索引。換句話說,不可能在你修改了文件或目錄之后,Git 一無所知。這項特性作為 Git 的設計哲學,建在整體架構的最底層。所以如果文件在傳輸時變得不完整,或者磁盤損壞導致文件數據缺失,Git 都能立即察覺.
Git 使用 SHA-1 算法計算數據的校驗和,通過對文件的內容或目錄的結構計算出一個 SHA-1 哈希值,作為指紋字符串。該字串由 40 個十六進制字符(0-9 及 a-f)組成,看起來就像是:
1: 24b9da6552252987aa493b52f8696cd6d3b00373
Git 的工作完全依賴於這類指紋字串,所以你會經常看到這樣的哈希值。實際上,所有保存在 Git 數據庫中的東西都是用此哈希值來作索引的,而不是靠文件名
C:多數操作僅僅添加數據
常用的 Git 操作大多僅僅是把數據添加到數據庫。因為任何一種不可逆的操作,比如刪除數據,要回退或重現都會非常困難。在別的 VCS 中,若還未提交更新,就有可能丟失或者混淆一些修改的內容,但在 Git 里,一旦提交快照之后就完全不用擔心丟失數據,特別是在養成了定期推送至其他鏡像倉庫的習慣的話。
這種高可靠性令我們的開發工作安心不少,盡管去做各種試驗性的嘗試好了,再怎樣也不會弄丟數據.
D:Git文件中三種狀態
接下來要講的概念非常重要。對於任何一個文件,在 Git 內都只有三種狀態:已提交(committed),已修改(modified)和已暫存(staged)。已提交表示該文件已經被安全地保存在本地數據庫中了;已修改表示修改了某個文件,但還沒有提交保存;已暫存表示把已修改的文件放在下次提交時要保存的清單中。
由此我們看到 Git 管理項目時,文件流轉的三個工作區域:Git 的工作目錄,暫存區域,以及本地數據目錄:
每個項目都有一個 git 目錄,它是 Git 用來保存元數據和對象數據庫的地方。該目錄非常重要,每次克隆鏡像倉庫的時候,實際拷貝的就是這個目錄里面的數據。
從項目中取出某個版本的所有文件和目錄,用以開始后續工作的叫做工作目錄。這些文件實際上都是從 git 目錄中的壓縮對象數據庫中提取出來的,接下來就可以在工作目錄中對這些文件進行編輯。
所謂的暫存區域只不過是個簡單的文件,一般都放在 git 目錄中。有時候人們會把這個文件叫做索引文件,不過標准說法還是叫暫存區域。
基本的 Git 工作流程如下所示:
- 在工作目錄中修改某些文件。
- 對這些修改了的文件作快照,並保存到暫存區域。
- 提交更新,將保存在暫存區域的文件快照轉儲到 git 目錄中。
所以,我們可以從文件所處的位置來判斷狀態:如果是 git 目錄中保存着的特定版本文件,就屬於已提交狀態;如果作了修改並已放入暫存區域,就屬於已暫存狀態;如果自上次取出后,作了修改但還沒有放到暫存區域,就是已修改狀態.
其實如上三種裝當你在每次從創建文件到提交文件整個過程.一旦執行一條命令都可以通過Git Status來查看當前文件的狀態.就能夠很清晰撲捉到一個文件從創建到提交過程在Git版本狀態的變化過程.我就不在此演示了.
<5>Git基礎概念小結
着重寫本篇主要目的是為了在使用Git解惑.清楚了解Git之前整個版本管理工具演化過程.以及相對其他版本工具Git自身具有的特點.和工作原理.重要性不言而喻. 就像很多開發人員強迫自己學習GOF 23種模式一樣.大多的人只是關注如何快速熟練的使用GOF每種模式.力求使用能夠精通.我們願景是能夠遇到問題時能夠采用前人經驗去解決.可惜是現實中使用效果總是與我們設想效果差很遠.原因很簡單.很多開發人員學習玩GoF 23模式后在碰到問題往往反而更迷茫了.因為他不知道采用哪種模式來解決問題最簡單.或是換句話我們只是知道 了解 並熟練掌握GOF模式使用而忽略GOF模式本身的價值.具體解決什么樣問題. 適用在什么問題場景最合適?這是否對學習對強迫自己學習GOF的同學是一種悲哀呢/.
學習GIT也是如此.不要陷入細節的海洋無法自拔.在處理問題上.多一點全局的觀念.往往能夠帶來更多思考.至少我們能確定做事方向和路線是對的.有些開發人員往往從事行業多年.卻對很多專業技術都是略知.說白在建立自身知識系統完整性缺乏. 這也是產生所謂行業多了很多”IT民工”角色 而少了真正的創新原因之一.
這種現象是否值得我們去反思這種問題的現狀呢?