記錄原由
最近因?yàn)楣拘聛淼耐拢谑褂?code>Git時犯了一些非常低級的錯誤,導(dǎo)致團(tuán)隊(duì)為了解決這些問題浪費(fèi)了很多時間。究其原因其實(shí)還是對于Git內(nèi)部實(shí)現(xiàn)不清晰,僅僅知道敲幾個git命令,但是卻不知道敲了這個命令Git會發(fā)生什么!這里根據(jù)git官方文檔節(jié)選了一些重要概念分享出來。
幾個重要概念
三種狀態(tài)
- 工作區(qū)狀態(tài)
- 就是修改了文件還沒有做
git add的文件狀態(tài)
- 暫存區(qū)狀態(tài)
- 已經(jīng)
git add但還未git commit的文件狀態(tài)
- 已提交狀態(tài)
- 已經(jīng)
git commit的文件狀態(tài),也就是真正存儲到git倉庫
Branch指針和HEAD指針
Git的分支特性是其最強(qiáng)大最獨(dú)特的功能,也正是因?yàn)檫@個特性讓git得以在眾多的版本控制系統(tǒng)中脫穎而出,在理解branch之前,有必要先對git commit命令做一個簡單的介紹
- 當(dāng)使用
git commit進(jìn)行提交操作時,Git便會創(chuàng)建一個提交對象,這個對象會包含一個指向本次提交的指針,指針指向本次commit的快照。指針也就是我們通常所說的commit id(長度為 40 的 SHA-1 值字符串)。如此一來,Git就可以在需要的時候根據(jù)commit id來回退版本
Branch的本質(zhì)其實(shí)僅僅是指向提交對象的********某一個可變指針********。所以根據(jù)這個概念,我們可以知道master并不是一個特殊的分支,他跟我們眾多自定義的分支沒有任何不同,唯一區(qū)別是它是Git的默認(rèn)分支(初始化的時候總得有一個默認(rèn)分支)
下面的圖是單個master分支時的結(jié)構(gòu),這里master僅僅是一個指向f30ab提交對象的指針

執(zhí)行 $ git branch testing創(chuàng)建一個 testing分支,會在當(dāng)前所在的提交對象上創(chuàng)建一個名為testing的指針,也就是testing分支

注意:此時兩個指針指向了相同的提交
那么Git是如何來知道當(dāng)前處于哪個分支的呢?
這就引出了Git中的另一個特殊的指針HEAD,HEAD用來指向當(dāng)前所在的分支,也就是一個用來指向分支指針的指針(有點(diǎn)拗口),就像下圖這樣,當(dāng)前是在master分支,因?yàn)?code>git branch并不會移動HEAD指針切換分支

執(zhí)行 $ git checkout testing命令才會將HEAD指針指向testing分支

當(dāng)我們在testing分支上繼續(xù)提交幾個commit之后,testing指針和HEAD指針都會跟著向前移動,但是master指針并不會移動,依舊指向f30ab這個提交

現(xiàn)在執(zhí)行git checkout master切回master分支,HEAD指針會重新指向master,也就是說現(xiàn)在又回到了一個舊的版本,這也是Git的神奇之處

接下來我們在master分支上做一些修改,提交一個commit,HEAD和master指針會繼續(xù)向前移動,并且這個項(xiàng)目的提交(快照版本)已經(jīng)產(chǎn)生了分叉

保存分支信息的目錄在
.git/refs/heads下,也可以在這個目錄下查看或修改分支指針
merge 命令
在上文的例子中,項(xiàng)目有兩個分支,且已經(jīng)產(chǎn)生了分叉,這時候需要把testing分支上的內(nèi)容合并至master時需要用到merge命令
在master執(zhí)行git merge testing,會生成一個新的提交9c67a,并且HEAD和master指針繼續(xù)向前移動

reset 命令
假如上面的merge操作有問題,需要撤銷,可以使用reset命令,但首先需要明確回退的版本是哪一個,例如要回退的版本是c2b9e,執(zhí)行git reset --hard c2b9e后,HEAD和master指針會回退到版本c2b9e
