提示:前面三篇文章已經分別的對
blob
物件、tree
物件、commit
物件進行了詳細的說明,這篇文章我們總結一下,Git物件在基礎操作流程中的生成的時機。
1、Git操作最基本的流程
1)建立工作目錄對工作目錄進行修改。
2)執行git add ./
命令新增檔案到暫存區。
相當於執行了如下兩個底層命令:
git hash-object -w檔名
(修改了多少個工作目錄中的檔案此命令就要被執行多少次)git update-index
說明:git add
命令做了什麼事情?
表面上是將工作目錄中的檔案新增到暫存區中,其實真正的流程是:
- 先將工作目錄中的檔案,生成
blob
物件儲存到本地版本庫中,
一個檔案生成一個blob
物件,一個檔案執行一次git hash-object -w 檔案路徑
命令。 - 再通過
git update-index
命令,把本地版本庫中blob
物件,生成檔案的索引(快照),儲存到暫存區中。
所以說Git是絕對安全的,只要你對檔案做過的修改,哪怕沒有提交到本地版本庫,只是提交到暫存區,Git也會幫你記錄下來。
3)執行git commit -m "註釋內容"
命令,把暫存區的快照提交到本地版本庫。
相當於執行了如下兩個底層命令:
git write-tree
:生成tree
物件。git commit-tree
:生成commit
物件。
說明:git commit
命令做了什麼事情?
表面上是將暫存區的檔案索引提交到了本地版本庫中,其實真正的流程是:
- 先通過
git write-tree
命令,把暫存區中的索引資訊,生成一個tree
物件儲存到本地版本庫中。 - 然後通過
git commit-tree
命令,把上面生成的樹物件進行封存,生成一個commit
物件,儲存到本地版本庫中。
重點提示:一個commit
物件肯定會對應一個tree
物件(單方向1對1的關係),一個commit
物件是不會對應兩個tree
物件的。(如上說明)
2、工作目錄中檔案的狀態
工作目錄下面的所有檔案都不外乎這兩種狀態:已跟蹤狀態或未跟蹤狀態。
已跟蹤的檔案是指本來就被納入版本控制管理的檔案,在之前的快照中有它們的記錄,工作一段時間後,它們的狀態會分為已提交狀態,已修改狀態或者已暫存狀態,這三種。
然後所有其他檔案都屬於未跟蹤檔案。它們既沒有上次更新時的快照,也不在當前的暫存區域。
使用Git時的檔案狀態變化週期如下圖所示:
提示:初次克隆某個倉庫到本地時,工作目錄中的所有檔案都屬於已跟蹤檔案,且狀態為已提交;在編輯過某些檔案之後,Git將這些檔案標為已修改。我們逐步把這些修改過的檔案放到暫存區域,直到最後一次性提交所有這些暫存起來的檔案。
3、Git效率說明
我們經歷了一次完整的Git提交過程,現在我們來思考一下Git提供的這三種物件帶來的高效率:
- 首先Git會對所有的檔案內容進行壓縮,這使得即使倉庫中儲存了非常多的內容,而
.git
也不會很大, - 然後就是速度,考慮這樣的情況,當我們修改了一個檔案的時候,Git會去計算這個檔案的
SHA-1
雜湊值。
如果該雜湊值所得到的路徑已經存在,那就說明,這個檔案並沒有被真正修改(也可以是改了然後又改了回來),這時就不會在本地版本庫中儲存新的物件。也就是說blob
物件跟檔名一點關係都沒有,兩個不同名字的檔案,只要他們的內容相同,在Git的眼裡他就是一個blob
物件,且只有一份。
如果我們真正的修改了一個檔案,那麼Git會計算這個檔案的雜湊值,然後將這個檔案壓縮儲存在objects
目錄中。
這樣設計的可以大大的節約儲存的空間,也提升了Git的儲存速度。 - 如果我們需要進行一次提交操作,是先對原來的檔案進行更改,然後需要建立一個相應的樹結構,來記錄這些檔案的變化。也就是每一次提交都建立一個頂層樹物件來表示這次提交快照。
Git會對比前一個提交的頂層樹物件,然後將沒有改變的樹物件或資料物件直接複製到新建立的這個頂層樹物件中,將改變的樹物件或資料物件,進行覆蓋,最後再提交到本地版本庫。
所以說決定你倉庫大小的並不是完全在於每個檔案的大小,而是你修改提交的次數,修改的次數越多,產生的樹物件、資料物件和提交物件也就越多。