原本地址:git乾貨系列:(二)深入學習之前先理解git暫存區
部落格地址:tengj.top/
前言
暫存區(stage, index)
是Git
最重要的概念之一,理解了這個概念很多 Git
命令就不再那麼神祕了。下面幾個驗證例子一開始看不懂沒關係,工作區、版本庫中的暫存區和版本庫之間的關係圖先理解先。
正文
下面這個圖展示了工作區、版本庫中的暫存區和版本庫之間的關係。
在這個圖中,我們可以看到部分 Git
命令是如何影響工作區和暫存區(stage, index)
的。
- 圖中左側為工作區,右側為版本庫。在版本庫中標記為
index
的區域是暫存區(stage, index)
,標記為master
的是master
分支所代表的目錄樹。 - 圖中我們可以看出此時
HEAD
實際是指向master
分支的一個“遊標”。所以圖示的命令中出現HEAD
的地方可以用master
來替換。 - 圖中的
objects
標識的區域為Git
的物件庫,實際位於.git/objects
目錄下,我們會在後面的章節重點介紹。 - 當對工作區修改(或新增)的檔案執行
git add
命令時,暫存區的目錄樹被更新,同時工作區修改(或新增)的檔案內容被寫入到物件庫中的一個新的物件中,而該物件的ID
被記錄在暫存區的檔案索引中。 - 當執行提交操作
(git commit)
時,暫存區的目錄樹寫到版本庫(物件庫)中,master
分支會做相應的更新。即master
指向的目錄樹就是提交時暫存區的目錄樹。 - 當執行
git reset HEAD
命令時,暫存區的目錄樹會被重寫,被 master 分支指向的目錄樹所替換,但是工作區不受影響。 - 當執行
git checkout .
或者git checkout -- [file]
命令時,會用暫存區全部或指定的檔案替換工作區的檔案。這個操作很危險,會清除工作區中未新增到暫存區的改動。 - 當執行
git checkout HEAD .
或者git checkout HEAD [file]
命令時,會用HEAD
指向的master
分支中的全部或者部分檔案替換暫存區和以及工作區中的檔案。這個命令也是極具危險性的,因為不但會清除工作區中未提交的改動,也會清除暫存區中未提交的改 動。 - 當執行
git rm --cached [file]
命令時,會直接從暫存區刪除檔案,工作區則不做出改變。 - 當執行
git rm file
命令時,會同時刪除暫存區和工作區的檔案。 - 當執行
rm file
命令時,只會刪除工作區的檔案。
下面舉例子來證明以上觀點
假設:
工作區:a
暫存區(index):b
HEAD:C
git diff命令結論
git diff 比較a跟b
git diff --cached 比較b跟c
git diff HEAD 比較a跟c複製程式碼
git reset跟 git checkout結論
git reset HEAD c覆蓋b
git checkout -- <file> b覆蓋a
git checkout HEAD <file> c覆蓋a,b複製程式碼
git rm命令結論
git rm 刪除a跟b
git rm --cached 只刪除b
rm file 只刪除a複製程式碼
證明git diff結論
例子,預設新建一個readme.txt
,裡面輸入內容one
然後add並且commit
一次。
1:修改readme.txt
,新增內容two
,這時候a內容改變了,多了two
,而b跟c內容不變,都只有one
。
執行git diff readme.txt
檢視效果
結論:如圖看出,內容有修改, a跟b比較了
執行git diff --cached readme.txt
檢視效果
結論:如圖看出,沒有變化,因為b跟c內容一樣。
執行git diff HEAD readme.txt
檢視效果
如圖所示:內容有修改,a跟c比較了
2.這時候執行git add readme.txt
,這時候a,b內容都多了two,而c內容不變,只有one
執行git diff readme.txt
檢視效果
結論:如圖看出,沒有變化, 因為a跟b內容一樣。
執行git diff --cached readme.txt檢視效果
結論:如圖看出,內容有修改,b跟c比較了
執行git diff HEAD readme.txt
檢視效果
結論:如圖看出,內容有修改,a跟c比較了
3.最後使用git commit
提交一次,這時候a,b,c內容都一樣,都包含two
。
結論,如圖看出,沒有變化,說明a,b,c內容一樣
根據上面的例項再一次證明了如下觀點:
git diff 比較工作區跟暫存區
git diff --cached 比較暫存區跟HEAD
git diff HEAD 比較工作區跟HEAD複製程式碼
證明git reset跟 git checkout結論
例子,預設新建一個readme.txt
,裡面輸入內容one
然後add並且commit
一次,這時候a,b,c內容都是one
1.修改readme.txt
,新增內容two
,執行git add readme.txt
操作,這時候a ,b內容都多了two
,c還是隻有one
.
執行git reset HEAD -- readme.txt
命令後,c覆蓋b,這時候b內容也變成只有one
了,使用git diff readme.txt
命令可以看到,有內容修改,a跟b內容不一樣。
2.此時a內容有two,b和c都只有one,執行git checkout -- readme.txt
後,b覆蓋a,此時a,b,c都是one。執行git diff readme.txt
命令可以看到,沒有改變。
3.此時a,b,c都只有one
,修改一下,新增內容two
,執行git add readme.txt
和git commit -m "two"
.再修改一次readme.txt
,新增內容three
,然後會執行git add readme.txt
,此時a跟b都包含three,而c只包含one跟two。執行git checkout HEAD readme.txt
後,c覆蓋a和b,a,b裡面內容都只有one跟two。分別使用命令git diff --cached
和git diff HEAD
來檢視b跟c,a跟c的比對,發現都一樣。
根據上面的例項再一次證明了如下觀點:
git reset HEAD HEAD覆蓋暫存區
git checkout -- <file> 暫存區覆蓋工作區
git checkout HEAD <file> HEAD覆蓋暫存區和工作區複製程式碼
證明git rm 結論
預設新建一個readme.txt
,裡面輸入內容one
,然後使用git add readme.txt
命令。
1.執行git rm readme.txt命令,發現檔案被刪除了。
2.再新建一個一個readme.txt
,裡面輸入內容 one,然後使用git add readme.txt
命令。執行git rm --cached readme.txt
命令,發現檔案內readme.txt
還在,然後執行git status
命令,發現是Untracked
狀態,也就是未add
,這就說明暫存區被刪除了。
根據上面的例項再一次證明了如下觀點:
git rm file 會將檔案從快取區和你的硬碟中(工作區)刪除
git rm --cached 只刪除暫存區,不刪除工作區
rm file 只刪除工作區複製程式碼
總結
暫存區的原理需要大家重複的加深瞭解,基礎打牢了後面學起來就輕鬆很多,上面幾個例子都自己驗證一遍,加深印象。
一直覺得自己寫的不是技術,而是情懷,一篇篇文章是自己這一路走來的痕跡。靠專業技能的成功是最具可複製性的,希望我的這條路能讓你少走彎路,希望我能幫你抹去知識的蒙塵,希望我能幫你理清知識的脈絡,希望未來技術之巔上有你也有我。