從 gi t的角度來看,文件的修改涉及到如下三個區域:工做目錄, stage區(暫存區)以及本地倉庫. java
當咱們對咱們的項目作了一些修改(新增文件,刪除文件,修改文件等),咱們處理的就是咱們的工做目錄.這個目錄是存在於咱們電腦的文件系統上的.全部的修改都會保留在工做目錄直到咱們把它們加入到暫存區(經過git add命令)。git
暫存區這是對下一次提交最好的表示方式,當咱們執行git commit
,git會獲取暫存區中的修改,並將這些修改做爲下一次的提交內容.暫存區的一個實際做用就是容許你調整你的提交,你能夠向暫存區新增和刪除修改直到你對你下一次的提交滿意,這個時候你就能夠用git commit
提交你的內容了。bash
在提交修改後,它們就會進入.git/objects
目錄,在其中被保存爲commit,blob以及tree objects(參考[數據模型]www.jianshu.com/p/843c8b0aa…)那一篇文章)工具
把暫存區認爲是一個存儲修改的真實區域並不許確,git沒有專門的stage目錄來存放這些文件的修改(blobs),git有一個名爲index的文件來跟蹤這三個區域的修改:工做目錄,暫存區以及本地倉庫。spa
當咱們添加修改到暫存區的時候,git會更新index文件中的信息,而且建立一個新的blob object,而後將它們放到與以前提交的記錄所產生的其餘blob相同的.git/objects目錄中。3d
接下來咱們就經過一個正常的git流程來演示下git如何使用的index指針
首先在咱們的倉庫裏面有master以及feature兩個分支,若是咱們執行下面的命令,會有三件事情發生code
git checkout feature
複製代碼
第一,git會移動HEAD指針來指向feature分支,爲了更加便於理解,咱們只顯示功能分支的最後一次提交cdn
第二,git將獲取feautre分支指向的提交內容並將其添加到索引中對象
咱們注意到index是一個文件而不是目錄,因此git是沒有往其中存儲內容的,git只是存儲咱們倉庫中每一個文件的信息而已,相似於上面這樣
mtime : 上次更新時間
file : 文件名稱
wdir : 工做目錄中文件版本
stage : index中文件版本
repo : 倉庫中的文件版本
複製代碼
文件版本以校驗和來標識,若是兩個文件有相同的校驗和,那麼它們就有同樣的內容以及版本.
最後,git會將你的工做目錄和HEAD指向的內容相匹配(它將使用樹和blob對象從新建立項目目錄的內容)
因此,當你使用checkout的時候,工做目錄,暫存區以及倉庫都是相同的版本 咱們來看看當咱們編輯Main.java的時候會發生什麼?
如今僅僅只影響了咱們的工做目錄,可是咱們運行下面的命令的時候
git status
複製代碼
git 首先會更新index文件中Main.java的工做目錄的版本
而後咱們看到Main.java在工做目錄和暫存區有不一樣的版本
而後git會提示咱們
On branch feature
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: Main.java
no changes added to commit (use "git add" and/or "git commit -a")
複製代碼
這就代表工做目錄的修改不在暫存區中(那麼下一次的提交就不會包含Main.java的修改).
因此,執行如下命令將Main.java加入到暫存區
git add Main.java
複製代碼
執行了上面這條命令,就又會發生兩件事兒,第一,git會爲Main.java建立一個blob object而後存儲在.git/objects目錄下,第二,會再次更新index文件
這個時候咱們再次執行命令
git status
複製代碼
git會發現Main.java的暫存區的版本和工做目錄版本一致,可是和倉庫的版本不一致
因此git就告知咱們
On branch feature
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: Main.java
複製代碼
證實Main.java已經在暫存區,可是尚未提交到倉庫.如今咱們就能夠提交咱們的修改了
git commit -m "add some code to Main.java"
複製代碼
git會作下面幾件事兒: 1. 新增commit object和tree object,並把它們和執行git add時建立的blob object鏈接起來 2. 移動feature的指針到新的commit object 3. 更新index
好啦,如今咱們的Main.java在全部區域都有相同的版本了.
不管執行 git add
仍是git commit
index文件都會變動,這也更好的證實了咱們上述模型,固然index文件中的內容確定沒有那麼清晰,它是一個二進制文件,若是想要查看它的內容就須要藉助其餘工具來實現
上面就是關於git index的原理了,如今回過頭來看發現其實並不複雜,可是對於咱們理解在一些在index上操做的命令(add,checkout,revert,commit,add...)倒是相當重要的