? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? (圖片來源:自己畫的)
基于同一個commit創建新分支
(圖片來源:書籍《Linux運維之道》 ISBN 9787121461811)
在新分支上修改然后commit一次
??????????????????????????????? (圖片來源:書籍《Linux運維之道》 ISBN 9787121461811)
在舊分支上也修改并commit一次
?????????????????????????? (圖片來源:書籍《Linux運維之道》 ISBN 9787121461811)
1. blob是binary large object,二進制大對象,是git管理的數據的底層實際存儲形式,也就是里面是一串各種0和1
2. tree是一個對象,這個對象是一個樹索引,這個索引是在git commit的時候生成的。之所以不同的commit代表不同的版本,其底層是不同的commit哈希值指向的是不同的tree對象,tree對象包含目錄和文件的結構,以及每個文件底層指向的是哪個blob
?3. 如果一個git數據倉庫只有一個branch,比如創建git數據倉庫時,會默認自帶一個main分支,每次的commit,都是由這個branch指向的。關鍵點是,commit是branch的底層,而不是branch是commit的底層。
?4. 本來每次的commit都只有一個branch,比如main,指向這個commit的,如果基于這個main branch創建出來一個新的branch,實際上是基于這個main branch所指向的commit創建出來一個新的branch,比如release,這時這兩個branch都是指向同一個commit的。然后在release分支上再commit,這時release分支就指向新的commit了,這時main分支還是指向原來的commit的,如果把HEAD checkout到main分支了,再commit一次,那么這個新的commit也是基于原來的commit的,所以看著就是main分支和release分支分岔了。這就是不同的分支所代表的含義,不同的分支,只不過是從同一個commit開始,在不同的分支的指向下,不同的commit被不同的分支名稱區別化了,等于基于同一個commit開始,然后第二個commit被release分支跟蹤了,第三個commit還是被main分支跟蹤著,然后基于第二個commit之后的commit繼續被release分支跟蹤著,基于第三個commit之后的commit都被main分支跟蹤著。這么來看,其實分支就是一個指針。不同的分支是不同的指針指向不同的commit的持續變化。
?5. 而HEAD就是指向分支這個指針的指針,當把HEAD移動到某個分支指針時,這時候看到的就是這個分支指針所指向的commit
6. 一般的HEAD指針時指向不同分支指針的,比如HEAD_1和HEAD_2,但是也可以像HEAD_3一樣,這個指針的指針直接指向commit了,而不先指向分支再通過分支的指針指向commit,這種叫detached HEAD分離指針,這樣的作用是可以訪問這個commit(通過這個commit的哈希值),查看這個commit的狀態,也可以指向這個commit之后,基于這個commit再創建一個分支指針出來,然后在這個分支上開發,比如branch_c
?7. HEAD_4和branch_d也是同樣的理論,區別是,這個commit_2打了一個TAG,這個TAG是給commit_2貼的一個標簽,方便人類識別,可以通過這個TAG來訪問這個commit_2,打TAG的目的是,在很多的commit中,每一個commit都是用哈希值代表的,人們在工作中,不容易通過hash值和當時commit的msg來確定這個commit是干嘛的,所以對于重要的commit,可以打一個或多個TAG來指定這個commit是干嘛的。比如v2.15.3-rc0,代表這個tag是一個版本的發行候選版第一版,通過TAG的名稱方便找到這個commit,如果需要,也可以基于這個TAG,也就是這個commit來檢出進行使用,比如打部署包。如果需要在這個TAG所代表的commit的基礎上進行再次開發,也可以基于這個TAG所代表的commit來創建一個新的分支,然后在這個新的分支上進行開發和維護。