轉載:http://www.lxweimin.com/p/619122f8747b
從根本上來講,Git是一個內容尋址文件系統,并在此之上提供了一個版本控制系統的用戶界面,它是一個非常強大且易用的工具,理解Git的工作原理,能夠幫助我們更容易學習和使用Git。
本文不會像書籍里那樣,一條條討論checkout、branch、remote等諸如此類動詞形式的高層命令和底層命令,本文主要從宏觀方向傳達Git的思想和工作原理,能夠使初學者更加理解,更利于學習。
git
直接記錄快照,而非差異比較
Git 和其他版本控制系統的主要差別在于,Git 只關心文件數據的整體是否發生變化,而大多數其他系統則只關心文件內容的具體差異。這類系統(CVS,Subversion,Perforce,Bazaar 等等)每次記錄有哪些文件作了更新,以及都更新了哪些行的什么內容:
其他系統在每個版本中記錄著各個文化的具體差異
Git 并不保存這些前后變化的差異數據。實際上,Git 更像是把變化的文件作快照后,記錄在一個微型的文件系統中。每次提交更新時,它會縱覽一遍所有文件的指紋信息并對文件作一快照,然后保存一個指向這次快照的索引。為提高性能,若文件沒有變化,Git 不會再次保存,而只對上次保存的快照作一鏈接。Git 的工作方式就如下圖所示。
Git保存每次更新時的文件快照
這是 Git 同其他系統的重要區別。它完全顛覆了傳統版本控制的套路,并對各個環節的實現方式作了新的設計。Git 更像是個小型的文件系統,但它同時還提供了許多以此為基礎的超強工具,而不只是一個簡單的 VCS。
工作區和暫存區
Git 和其他版本控制系統的一個不同之處就是有暫存區的概念。
工作區(Working Directory)
在電腦中能看到的目錄,比如我建立的gittest就是一個工作區
工作區
版本庫(Repository)
工作區中的隱藏目錄.git,就是Git的版本庫。
工作區和版本庫
Git的版本庫里存了很多東西,其中最重要的就是稱為stage(或者叫index)的暫存區,還有Git為我們自動創建的第一個分支master,以及指向master的一個指針叫HEAD。
回憶在我上一篇博客中提到的將文件添加到版本庫的流程圖:
將文件添加到版本庫
通過以上兩幅圖不難看出,需要提交的文件經過add后先都放到暫存區index(或者叫stage)中,然后經過commit指令,一次性提交暫存區的所有修改到head。一旦提交后,暫存區清空,同時若對工作區沒有做任何修改,那么工作區就是干凈的(working directory clean)
文件的三種狀態
對任何一個文件,在Git內都有三種狀態:
已提交(committed):表示該文件已經被安全的保存在本地數據庫中了
已修改(modified):表示修改了某個文件,但還沒有提交保存
已暫存(staged):表示把已修改的文件放在下次提交時要保存的清單中
文件流轉圖
所謂的暫存區域只不過是個簡單的文件,一般都放在 Git 目錄中。有時候人們會把這個文件叫做索引文件,不過標準說法還是叫暫存區域。
我們可以從文件所處的位置來判斷狀態:
Git 目錄中保存著的特定版本文件----->已提交狀態
作了修改并已放入暫存區域----->已暫存狀態
自上次取出后,作了修改但還沒有放到暫存區域----->已修改狀態
重要的 .git 目錄
當一個新目錄或已有目錄執行git init時,Git會創建一個.git目錄。這個目錄包含了幾乎所有Git存儲和操作的對象。若想備份或復制一個版本庫,只需把這個目錄拷貝至另一處即可。對于一個全新的版本庫,該目錄結構如下所示:
目錄結構圖
description文件:僅供GitWeb程序使用
config文件:包含項目特有的配置選項
info目錄:包含一個全局性排除(global exclude)文件,用以放置那些不希望被記錄在 .gitignore文件中的忽略模式(ignored patterns)
hooks目錄:包含客戶端或服務端的鉤子腳本(hook scripts)
HEAD文件:指示目前被檢出的分支
index文件:保存暫存區信息
objects目錄:存儲所有數據內容
refs 目錄:存儲指向數據(分支)的提交對象的指針
關于Git底層命令和高層命令的原理討論,很大一部分都在這個目錄中,要想了解具體的原理,可以看這本書,這里僅僅列出了每部分的功能,有個大體了解。
基本的 Git 工作流程
在工作目錄中修改某些文件。
對修改后的文件進行快照,然后保存到暫存區域。
提交更新,將保存在暫存區域的文件快照永久轉儲到 Git 目錄中。
分析 Git 命令
有了上述介紹,我們可以對 Git 的命令有更深的理解,這里以將文件添加到代碼庫為例進行分析:我們都知道需要兩步,第一步add,第二步commit,但為什么要分兩步呢?每一步都做了什么呢?
(1)git commit -a:相當于運行 git add 把所有當前目錄下的文件加入暫存區域再運行 git commit
(2)git commit :進行一次包含最后一次提交加上工作目錄中文件快照的提交,并且文件被添加到暫存區域
(3)git checkout HEAD -- :回滾到復制最后一次提交
以上僅僅分析了添加文件到代碼庫的過程,更多命令詳解看這里
參考資料
作者:sunnyaxin
鏈接:http://www.lxweimin.com/p/619122f8747b
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權并注明出處。