前言
這一節主要介紹Git
標籤、別名與Git
的垃圾回收機制。
一、Git
標籤(tag
)
1.標籤的實質
標籤與分支十分相似,都是指向某一次提交;並且,它們的值都為各自指向提交的SHA1
值;但是,不同於會隨著提交的變化而變化的分支,一旦給某次提交新增了標籤,該標籤就永遠不會發生變化。
注意:標籤標識的是某一次提交,這次提交可以是任何分支上的任何一次提交。
兩類標籤
Git
標籤有兩種:
- 輕量級標籤(
lightweight
):不可新增註釋; - 帶有附註的標籤(
annotated
):可以新增註釋;
Annotated tags are meant for release while lightweight tags are meant for private or temporary object labels.
以上是git
官方文件對兩種標籤的說明,大意是:帶註釋的標籤用於釋出,而輕量級標籤則用於私人或臨時物件。
什麼時候打標籤呢?
-
版本釋出:一般
master
分支都會作為專案的釋出分支,當專案開發到了一個成熟的階段,準備在master
分支進行釋出時。一般都會在master
分支的當前提交上打上一個類似"v1.2
"的標籤;比如
Vue
框架:可以看到有許多標籤,並且可以在
releases
選項中檢視標籤和釋出版本: -
版本管理:可以通過標籤的形式記錄專案某一階段的狀態,方便管理;
比如管理學習微信小程式時每個知識點的程式碼:
檢視標籤檔案
如下圖所示,分別給master
分支的提交mas2
新增一個輕量級標籤v1.0
和一個帶有附註的標籤v2.0
:
git dog
為git log --all --decorate --oneline --graph
的別名,後面會講解;
隨後,檢視儲存標籤檔案的.git/refs/tags
目錄:
可以看到:
tags
目錄下儲存著新增的標籤檔案v1.0
和v2.0
;- 分別開啟標籤檔案
v1.0
和v2.0
,它們的值都是一個SHA1
值,並且與新增標籤時所在提交mas2
的SHA1
值6920a6e...
相等。 emm...
等等!並不相等呀,只有v1.0
的值與提交mas2
的SHA1
值相等,而與v2.0
的值並不相等!- 為什麼給同一次提交
mas2
新增的標籤,它們的SHA1
值會不相等呢?這是因為v1.0
是輕量級標籤,而v2.0
是帶有附註的標籤。
雖然兩個標籤標記的都是同一次提交,但是它們的構造不一樣:
-
輕量級標籤
v1.0
直接將這次提交的SHA1
值作為自己的SHA1
值; -
而帶附註的標籤
v2.0
會建立一個tag
物件,它的SHA1
值是tag
物件的SHA1
值;
這就是輕量級標籤與帶有附註標籤的區別。不過這兩個標籤仍然會指向同一次提交,如下圖所示:
2.建立標籤
git tag <tag_name>
建立一個輕量級標籤:
git tag -a <tag_name> -m '註釋'
建立一個帶有附註的標籤:
3.檢視標籤
git tag
顯示新增的所有標籤:
也可以新增--list
引數:
如下圖所示:切換了分支tag
仍然存在,說明tag
與分支並沒有關係,它標識的是某次特定的提交:
git show <tag_name>
如圖所示,在master
分支上進行兩次提交,每次為檔案test.txt
新增一行內容並且打上標籤。其中v1.0
為輕量級標籤,v2.0
為帶有附註的標籤:
隨後,使用git show
檢視標籤的內容:
-
輕量級標籤:
如圖所示,該指令會顯示標籤
v1.0
所指向的提交;並且,會輸出標籤指向提交與上一次提交的比較結果;由於標籤v1.0
指向的提交為master
分支的第一次提交,所以上一次提交為null
。因此比較結果顯示:相比於上一次提交,標籤指向的提交1st
在檔案test.txt
中新增了一行1st
; -
帶註釋的標籤:
相比於輕量級標籤,帶附註的標籤是一個物件,可以儲存附註和打標籤的人和時間等資訊,所以顯示的資訊多一些;從圖中的比較結果可知,相比於上一次提交
1st
,標籤v2.0
指向的提交2nd
為檔案test.txt
新增了一行2nd
;
4.查詢標籤
git tag -l <tag_name>
該方式支援正規表示式查詢;
如上圖所示:
v*
表示搜尋所有以v
開頭的標籤;?2*
表示搜尋任意開頭,但包含2
的標籤;
5.將標籤推送到遠端
要將標籤推送到遠端倉庫,首先要建立本地倉庫與遠端倉庫的聯絡,比如可以採用:
git push -u origin master
建立本地master
分支與遠端master
分支的聯絡,並進行一次推送:
git push origin <tag_name>
這種方法可以推送指定的本地標籤到遠端倉庫,例如將本地master
分支上的標籤v1.0
推送到遠端倉庫:
執行上述指令後,對應的遠端倉庫gitTest
中就會出現相應的tag
資訊了:
也可以在releases
選項中,檢視tag
和Releases
資訊:
也可以同時推送多個本地標籤到遠端倉庫:
git push origin v2.0 v3.0
以上的命令都是簡寫形式,完整寫法為:
git push origin refs/tags/v4.0:refs/tags/v4.0
git push origin --tag
該方法可以一次性推送所有的本地標籤到遠端倉庫:
也可以採用簡寫命令:
//下面的tag可以寫成tags,效果一樣
git push --tag
6.刪除遠端標籤
當然,我們可以直接在遠端倉庫上刪除遠端標籤。但是,最好的方式還是採用命令列進行刪除。刪除遠端標籤的方法與刪除遠端分支的方法非常類似,同樣有兩種方法:
git push origin :<tag_name>
這種方法相當於推送一個空的標籤到遠端倉庫,由此達到刪除的效果。比如刪除遠端倉庫中的標籤v3.0
:
git push origin :v3.0
這樣遠端倉庫中的標籤V3.0
就被刪除了:
但是本地倉庫中對應的標籤V3.0
並沒有被刪除:
上述指令為簡寫,完整寫法如下:
git push origin :refs/tags/v3.0
git push origin --delete <tag_name>
該方法採用了更加語義化的引數--delete
,實現遠端標籤的刪除:
git push origin --delete v2.0
同樣成功地刪除了遠端倉庫中的標籤v2.0
:
但是,本地的標籤v2.0
也沒有被刪除:
採用下列的完整寫法,效果是一樣的:
git push origin --delete tag v2.0
不難發現,刪除遠端分支和遠端標籤的方法是一樣的。
7.刪除本地標籤
git tag -d <tag_name>
如通過以下命令刪除標籤v3.0
:
git tag -d v3.0
8.切換標籤
git checkout <tag_name>
如圖所示,在master
分支上進行了三次提交,並且新增了相應的標籤:
當我們通過checkout
命令切換到標籤v2.0
時:
可見,會出現遊離的提交。此時檢視各分支狀態:
如上圖所示,當前處於標籤v2.0
指向的提交,並且切換標籤的過程中改變了HEAD
指標的指向。但是,並沒有改變分支master
的指向。過程如下圖所示:
也就是說,切換標籤與使用reset
進行版本回退十分相似。只不過切換標籤只改變了HEAD
指標的指向,會造成遊離的提交。若有需要可以建立一個新分支進行儲存。
9.拉取標籤
在下圖所示的情況中,本地倉庫mygit
與遠端倉庫有公共的提交歷史(同源),並且不發生合併衝突的情況下(具體可參考Git應用詳解第六講:Git協作與Git pull常見問題):
可以直接通過git pull
將遠端倉庫的標籤拉取下來,並建立本地倉庫中沒有的標籤:
二、Git
別名
1.設定git
命令別名
git config <作用域> alias.<別名> '<命令>'
別名就是一個替代,使用一個簡短的字串來代替常用的長命令。比如可以通過如下命令,使用別名bra
來替代branch
命令:
git config --global alias.bra branch
當命令較為簡短時,可以省略命令兩邊的單引號:
在上述命令中:
-
--global
表示設定的別名作用域為系統使用者,即該使用者對所有的git
倉庫都可以使用這個別名;其餘還有倉庫作用域--loacl
,系統作用域--system
; -
alias.br
表示更改別名為br
; -
再往後的
branch
表示需要起別名的命令,可以是帶引數的長命令,此時不能省略命令兩邊的單引號:git config --global alias.dog 'log --all --decorate --oneline --graph'
由於上面配置的別名作用域為系統使用者,該配置會寫入gitconfig
配置檔案。開啟該檔案可以看到寫入的別名配置:
補充:使用
vi ~/.gitconfig
可以直接開啟gitconfig
這個檔案(記得加點),無論當前所處的路徑是什麼;
也就是說可以直接通過修改gitconfig
檔案的alias
選項來設定別名,但是不建議。
這樣,通過別名就可以簡化一些常用的命令了,比如git status
、git checkout
等:
2.設定外部命令別名
像gitk
這樣的外部命令,是沒有git
字首的。設定別名的方法與設定git
提供的命令有所不同,要按照如下格式設定:
git config <作用域> alias.<別名> '<!外部命令>'
- 感嘆號表示這是一個外部命令;
- 注意要加上單引號,不用加
git
字首;
比如在系統使用者作用域下,將git ui
設定為gitk
的別名:
git config --global alias.ui '!gitk'
設定完成後,該配置會被寫入系統使用者的配置檔案gitconfig
中:
隨後直接使用git ui
便能開啟gitk
介面:
補充:設定了別名後,原來的命令仍然有效。
三、垃圾回收:Git gc
所謂gc
就是垃圾回收機制,實際使用較少;它的作用是清理不必要的檔案並優化本地儲存庫。
為了演示它的作用,設定以下測試環境:
-
首先,在本地倉庫
mygit
建立master
和dev
兩個分支,並將它們推送到遠端倉庫: -
然後,給本地倉庫
mygit
新增一個輕量級標籤v1.0
和一個帶有附註的標籤v2.0
:
此時.git/refs
目錄下的各檔案如下所示:
heads
目錄儲存的是本地分支資訊,remote
目錄儲存的是遠端分支資訊,tags
目錄儲存的是標籤資訊,符合預期。
隨後,執行git gc
命令:
再次檢視.git/refs
目錄:
可以看到refs
目錄及其子目錄下的檔案消失了,但是.git
目錄下多了一個packed-refs
檔案。事實上,refs
目錄下的檔案不是消失了,而是被打包到了packed-refs
檔案中。開啟packed-refs
檔案:
可以看到執行git gc
後refs
目錄及其子目錄下的檔案都被壓縮打包到packed-refs
檔案中了。從圖中可以看到輕量級標籤v1.0
只佔一行,而帶附註的標籤v2.0
佔兩行:
- 其中第
6
行和第8
行的SHA1
值是相同的,這是因為兩個標籤都是給同一次提交上新增的; - 而帶附註的標籤
v2.0
中的另外一行資訊(第7
行)表示的則是tag
物件的SHA1
值;
打包完之後,再次修改檔案,或者新增分支,新增的內容還是會在.git/refs
目錄下顯示,而不會被打包到packed-refs
檔案中,需要重新執行git gc
才會被打包。
以上就是本節的全部內容,經過這一節的學習,相信你已經能夠熟練運用
Git
標籤和別名來提高開發效率了。下一節將會詳細介紹git cherry-pick
與git rebase
,我們下一節再見!