1. 程式人生 > >Git之(一)Git是什麼

Git之(一)Git是什麼

為什麼使用Git

孔子曾經曰過的,名正則言順 言順則事成。

我們在學習一項新技術之前,弄清楚為什麼要學它至關重要,至於為什麼要學習Git,我用一段if-else語句告訴你原因:

if(你相信我){
      我推薦你學習;
} else if(誠然,我又不是什麼大牛,你可以不相信我,但是你應該相信大多數人的選擇){
      世界上越來越多的人、越來越多的專案在使用Git,大勢所趨,勢不可擋;
}else if(用的人多算什麼,你可能認為真理掌握在少數人手中){
      你可以不相信大眾,但是你應該相信LinusTorvalds,就是靠一己之力寫出了Linux核心原型的大神//我說的是核心的原型,不是核心的全部,不要挑我毛病!
      Git就是他創造的第二個作品
}else{
      什麼?!你沒聽過LinusTorvalds,更不知道Linux是個什麼東西……
      throw new Exception(“好吧,你贏了,你可以不用學Git,我執行不下去了”);  
}


Git是什麼

首先,Git是一個版本管理工具。

我們自己平時寫個“HelloWorld”程式,或者寫一個只有幾百行程式碼的小專案,不需要專門的程式碼管理工具,依靠自己的記憶就能把程式碼捋順。

但是,一旦涉及到程式碼量巨大的專案,往往需要經過很多人協同工作數週乃至數月才能完成。開發過程中,會面臨著程式碼的修改、增刪、恢復等工作,開發人員不可能清楚的記得每次變化,這時候就需要藉助版本管理工具來跟蹤程式碼的變化歷程。

版本管理工具賦予每個檔案一個版本號,每次修改之後,哪怕只改動了一個字母,版本管理工具都會精確地記錄下來,並改變該檔案的版本號。這樣,每個版本號就對應著檔案的一次變化,依此可以進行檔案的對比、恢復等操作。

最早廣泛應用的版本管理工具是CVS(Concurrent Versions System),後來逐漸被SVN(Subversion)替代,兩者的工作原理類似,都是以一臺伺服器為核心進行集中式程式碼管理:


集中式 vs 分散式

SVN屬於典型的集中式版本控制系統,集中式版本控制系統都有一個單一的集中管理的伺服器,儲存所有檔案的修訂版本,而協同工作的人們都通過客戶端連到這臺伺服器,取出最新的檔案或者提交更新。

這種做法帶來了許多好處,特別是相較於老式的本地VCS 來說。現在,每個人都可以一定程度上看到專案中的其他人正在做些什麼。而管理員也可以輕鬆掌控每個開發者的許可權。

事分兩面,有好有壞。這麼做最顯而易見的缺點是中央伺服器的單點故障。若是宕機一小時,那麼在這一小時內,誰都無法提交更新、還原、對比等,也就無法協同工作。如果中央伺服器的磁碟發生故障,並且沒做過備份或者備份得不夠及時的話,還會有丟失資料的風險。最壞的情況是徹底丟失整個專案的所有歷史更改記錄,被客戶端提取出來的某些快照資料除外,但這樣的話依然是個問題,不能保證所有的資料都已經有人提取出來。

SVN只關心檔案內容的具體差異。每次記錄有哪些檔案作了更新,以及都更新了什麼內容。如下圖所示:


與SVN不同,Git記錄版本歷史只關心檔案資料的整體是否發生變化。Git 並不儲存檔案內容前後變化的差異資料。實際上,Git 更像是把變化的檔案作快照後,記錄在一個微型的檔案系統中。每次提交更新時,它會縱覽一遍所有檔案的指紋資訊並對檔案作一快照,然後儲存一個指向這次快照的索引。為提高效能,若檔案沒有變化,Git 不會再次儲存,而只對上次儲存的快照作一連線。Git 的工作方式如下圖所示:


在分散式版本控制系統中,客戶端並不只提取最新版本的檔案快照,而是把原始的程式碼倉庫完整地映象下來。這麼一來,任何一處協同工作用的伺服器發生故障,事後都可以用任何一個映象出來的本地倉庫恢復。這類系統都可以指定和若干不同的遠端程式碼倉庫進行互動。藉此,就可以在同一個專案中,分別和不同工作小組的人相互協作。可以根據需要設定不同的協作流程。

另外,因為Git在本地磁碟上儲存著所有有關當前專案的歷史更新,並且Git中的絕大多數操作都只需要訪問本地檔案和資源,不用連網,所以處理起來速度飛快。用SVN的話,沒有網路或者斷開VPN就無法做任何事情。但用Git的話,就算你在飛機或者火車上,都可以非常愉快地頻繁提交更新,等到了有網路的時候再上傳到遠端的映象倉庫。換作其他版本控制系統,這麼做幾乎不可能,抑或是非常麻煩。

簡略的說,Git具有以下特點:

1、Git中每個克隆(clone)的版本庫都是平等的。可以從任何一個版本庫的克隆來建立屬於自己的版本庫,同時你的版本庫也可以作為源提供給他人,只要你願意。

2、Git的每一次提取操作,實際上都是一次對程式碼倉庫的完整備份

3、提交完全在本地完成,無須別人給你授權,你的版本庫你作主,並且提交總是會成功。

4、Git的提交不會被打斷,直到你的工作完全滿意了,PUSH給他人或者他人PULL你的版本庫,合併會發生在PULL和PUSH過程中,不能自動解決的衝突會提示你手工完成。

全域性版本號 vs 全球版本號

SVN的全域性版本號和CVS的每個檔案都獨立維護一套版本號,在看似簡單的全域性版本號的背後,是SVN提供對於事物處理的支援,每一個事物處理(即一次提交)都具有整個版本庫全域性唯一的版本號。

Git的版本號則更進一步,版本號是全球唯一的。在儲存到 Git 之前,所有資料都要進行內容的校驗和(checksum)計算,並將此結果作為資料的唯一標識和索引。換句話說,不可能在你修改了檔案或目錄之後,Git 一無所知。這項特性作為 Git 的設計哲學,建在整體架構的最底層。所以如果檔案在傳輸時變得不完整,或者磁碟損壞導致檔案資料缺失,Git 都能立即察覺。

Git 使用 SHA-1 演算法計算資料的校驗和,通過對檔案的內容或目錄的結構計算出一個 SHA-1 雜湊值,作為指紋字串。該字串由 40 個十六進位制字元(0-9 及a-f)組成,看起來就像是這個樣子:

24b9da6552252987aa493b52f8696cd6d3b00373

1、所有儲存在Git 資料庫中的東西都是用此雜湊值來作索引的,而不是靠檔名。

2、使用雜湊值作版本號的好處就是對於一個分散式的版本控制系統,每個人每次提交後形成的版本號都不會出現重複。另一好處是保證資料的完整性,因為雜湊值是根據內容或目錄結構計算出來的,所以我們還可以據此來判斷資料內容是否被篡改。

3、SVN 的版本號是連續的,可以預判下一個版本號,而 Git 的版本號則不是。因為 subversion 是集中式版本控制,很容易實現版本號的連續性。Git 是分散式的版本控制系統,而且Git 採用 40 位長的雜湊值作為版本號,每個人的提交都是各自獨立完成的,沒有先後之分(即使提交有先後之分,也由於PUSH/PULL的方向和時機而不同)。Git 的版本號雖然不連續,但是是有線索的,即每一個版本都有對應的父版本(一個或者兩個),進而可以形成一個複雜的提交鏈。

4、Git 的版本號簡化:Git 可以使用從左面開始任意長度的字串作為簡化版本號,只要該簡化的版本號不產生歧義。一般採用7位的短版本號(只要不會出現重複的,你也可以使用更短的版本號)。

許多人可能會擔心一個問題:在隨機的偶然情況下,在他們的倉庫裡會出現兩個具有相同 SHA-1 值的物件。那會怎麼樣呢?

如果你真的向倉庫裡提交了一個跟之前的某個物件具有相同 SHA-1 值的物件,Git 將會發現之前的那個物件已經存在在 Git 資料庫中,並認為它已經被寫入了。如果什麼時候你想再次檢出那個物件時,你會總是得到先前的那個物件的資料。

不過,你應該瞭解到,這種情況發生的概率是多麼微小。SHA-1 摘要長度是 20 位元組,也就是 160 位。為了保證有 50% 的概率出現一次衝突,需要 2^80 個隨機雜湊的物件(計算衝突機率的公式是p = (n(n-1)/2) *(1/2^160))。2^80 是 1.2 x 10^24,也就是一億億億,那是地球上沙粒總數的 1200 倍。

現在舉例說一下怎樣才能產生一次SHA-1 衝突。如果地球上 65 億的人類都在程式設計,每人每秒都在產生等價於整個 Linux 核心歷史(一百萬個 Git 物件)的程式碼,並將之提交到一個巨大的 Git 倉庫裡面,那將花費 5 年的時間才會產生足夠的物件,使其擁有 50% 的概率產生一次 SHA-1 物件衝突……

所以,你還擔心會衝突嗎?