如何從稍微底層一點的角度,從底層實現理解一切皆commit ?
配合希沃白板課件食用,效果更佳:
【希沃白板5】課件分享 : 《Git 進階 - 從使用角度深入理解Git》
https://r302.cc/ke8XdO?platform=enpc&channel=copylink
點擊鏈接直接預覽課件
git 文件系統
git 本質上是一個基於鍵值對的文件系統。
文件系統,最重要的兩個內容,當然就是 文件 和 文件夾 了。
blob object(數據對象)
git 中的 blob object 就是文件系統中的文件,包含 鍵:一個 hash 值和校驗值的組合,值:文件內容。
比較特殊的是:blob object 只存內容,不存文件名,文件名在 tree object 中保存。
tree object (樹對象)
相當於文件系統中的文件夾。
commit object(提交對象)
提交對象可以理解為對樹對象的一層封裝,里面包含了提交時間,提交作者等信息,更重要的,里面包含了父提交的ID,由此就可以形成 git 提交的有向無環圖。
git 的這些對象的數據,保存在 .git/objects 目錄下。
這里,我們並沒有發現分支這些概念,回顧之前說的『一切皆 commit』的理解,分支這些,不過是某個 commit 的引用。(都是紙老虎)
案例
將 t/bugfix 分支重置到 a1b2c3 提交。
可以使用熟悉的 reset 命令: (@t/bugfix)git reset --hard a1b2c3
,也可以用更底層的命令:git update-ref refs/head/t/bugfix a1b2c3
。
效果是一樣的,當然,平時使用,只推薦前者,這里只是作為對“分支是某個commit的引用”這句話理解的一個案例。
標簽對象
tag object(標簽對象)
標簽對象:指向一個特定對象的固定引用對象;
可以給 git 中的任意對象打標簽;
標簽對象不是引用(與分支名不同),是一種獨立的git對象。但在使用上(針對提交的tag),體驗一致。所以“一切皆commit”這句話,對標簽而言,是不一定正確的,但實際使用中,一般只會給提交打標簽。
所有的引用,都記錄在 .git\refs 文件夾中。
壓縮與增量存儲
在沒有壓縮時,稱 git 的存儲模式為松散的對象模式,即一個文件的不同版本,都是保存其全部的數據。在 git gc 時,會壓縮並實現增量存儲。這個命令在執行 pull 等命令時自動觸發。
為什么 git 徹底刪除大文件要修改整個歷史?
因為提交的不可變性,如圖,如果 newfile 是個大文件,即使刪除,在提交歷史中依然存在。要徹底刪除,就要重寫 second 提交以及之后的每一個提交,因為之后的提交都有 tree 指向這個大文件,即使刪除,提交的父提交也需要變化。
如
- 徹底清除 newfile 之后,second 提交將無效,需要生成一個新提交,second' ;
- three 提交的 tree 引用中,也需要刪除 new.cs 的引用,同時修改父提交為 second' ,生成新提交為 three' ;
- 對於 forth 提交,不用清理 tree 對象,但也需要將父提交修改為 three',得到新的提交 forth' ;
- 以此類推,后面的每一個提交都需要修改;
勘誤:這里的 three,應該是 third 。圖片中也寫錯了,就懶得改了。
原文連接:https://www.cnblogs.com/jasongrass/p/10582465.html
END