iT邦幫忙

2025 iThome 鐵人賽

DAY 15
0
Software Development

深入一點點認識 Git系列 第 15

Day 15 - 深入一點點認識 Git:可以是、也可以不是物件的 tag

  • 分享至 

  • xImage
  •  

在 Day 3 的文章中,我們提到 git 有 blob、tree 跟 commit 三種物件,但事實上還有第四種:tag(標籤)。

標籤可以用 git tag 指令做出來,但不是每次做出標籤時,都會形成物件,本文的實驗將帶大家觀察何時會有物件形成、何時不會。

前置準備

Git 標籤本身其實也是 Day 9 提到的一種「參考(refs)」,因此產生標籤也會影響 .git/refs/tags 目錄。

首先我們依照 Day 14 的前置準備流程,先建立兩個 commit,經 git log 後如下:
https://ithelp.ithome.com.tw/upload/images/20250915/20178513IqLacuPjO3.png

圖示如下:
https://ithelp.ithome.com.tw/upload/images/20250915/20178513LG4N3dbTPK.png

Git 的兩種標籤

Git 的標籤有兩種,分別為:

  1. 輕量級標籤(lightweight tag):這種就是不會形成 git 物件的標籤,只是指向某個 commit 的參考,僅有名字、沒有任何元資料及自己的雜湊碼。
  2. 有註解的標籤(annotated tag):一個完整的標籤物件,包含標籤名、標籤者等元資料與自己的雜湊碼,跟 commit 十分類似,但 commit 指向 tree,標籤則是指向 commit。

要加上兩種標籤的指令十分簡單,分別為:

  1. 輕量級標籤:直接下 git tag <tag name> <commit>,如果是要把標籤加在當下所在分支的最新 commit,就不用特別打 <commit>
  2. 有註解的標籤,以 -a 表示要加上註解,因此為 git tag <tag name> -m "tag message" <commit>,一樣若是要加在當下所在分支的最新 commit,最後面的 <commit> 可以忽略。

在我們的實驗中加上輕量級標籤

現在我們要在 a49055d... 這個 commit 加上輕量級標籤,只要輸入以下指令:

git tag v1.0 a49055d

這時候下 git tag 就可發現目前多了 v1.0 這個標籤:
https://ithelp.ithome.com.tw/upload/images/20250915/2017851365OpmPQPxC.png

現在在 .git/ 發生了哪些變化呢?

.git/
├── hooks/
├── info/
├── objects/         # 無變化
├── refs/
│   ├── heads/
│   └── tags/
│         └── v1.0   # 多了v1.0
│
├── COMMIT_EDITMSG
├── config
├── description
├── HEAD
├── index
└── packed-refs      # 多了這個檔案
  • objects/ 無變化

建立的是輕量級標籤,因此只會產生參考,不會產生新的 tag 物件。

  • refs/tags/ 多了一個名為 v1.0 的檔案

建立了一個名為 v1.0 的標籤,而這標籤是一個指向 a49055d... 這個 commit 的參考,因此 refs/tags/ 中多一個檔案。

  • 多了 packed-refs 檔案

Git 中可能有很多參考,而像 tag 這種參考通常不太會改動,如果「一個標籤一檔案」、全部都塞到 refs/tags/ 將浪費儲存空間、且效率較低,因此 git 有時會把這些參考都放到「同一個檔案」中,有助於提升效能。Git 如果要找一條參考,沒在 refs/tags/ 找到的話就會在這個 packed-refs 檔案中找。

目前內文為 # pack-refs with: peeled fully-peeled sorted 這條註解,表示所有的參考都被「剝皮」(也就是所有 tag 物件都已經追溯到其最後指的 commit),而且已經排序完成,若要用二元搜尋找目標將更為容易。

有關 git 的打包機制,我們將在 Day 27 的文章深入說明。

在我們的實驗中加上有註解的標籤

相對於輕量級標籤,有註解的標籤需要多一個 -a,我們把它放在 ebb02d4... 上:

git tag v0.0 -m "Original version" ebb02d4

再下 git tag 就可發現新增的 v0.0 標籤也出現了:
https://ithelp.ithome.com.tw/upload/images/20250915/20178513FbJoLgKJ8z.png

那此時的 .git/ 資料夾結構長怎樣呢?

├── hooks/
├── info/
│
├── objects/
│   ├── ...
│   └── eb/
│       ├── 26c6f827cfff7ee6d4dd3503ce6511721912f8  # 新增的tag物件
│       └── b02d4722d536a59a7c8e111342586a614d569e  # 原有Initial commit物件
│
├── refs/
│   ├── heads/
│   └── tags/
│         ├── v0.0   # 再多v0.0
│         └── v1.0
│
├── COMMIT_EDITMSG
├── config
├── description
├── HEAD
├── index
└── packed-refs     # 內容不變
  • objects/ 多了一個物件

有註解的標籤會形成 tag 物件,因此多了一個雜湊碼為 eb26c6f... 的物件,若用 git cat-file 指令檢視,可得其物件資訊,跟 commit 很像,其中 type commit 表示這個標籤指著一個 commit 物件。

https://ithelp.ithome.com.tw/upload/images/20250915/20178513bwDDd9UkLi.png

  • refs/tags/ 多了一個名為 v0.0 的檔案

在原有的 v1.0 之外,我們還建立了一個名為 v0.0 的標籤。

綜合兩個標籤來看,可得目前結構下圖:
https://ithelp.ithome.com.tw/upload/images/20250915/20178513Cr49Pp9drr.png

小結

我們可以用 git tag 指令新增標籤,如果新增的是「輕量級標籤」,只會單純形成一個參考;如果新增的是「有註解的標籤」,則還會做出一個完整的 tag 物件。

參考資料

  1. 2.6 Git Basics - Tagging
  2. git-pack-refs
  3. 談談.git 目錄

上一篇
Day 14 - 深入一點點認識 Git:git diff 到底在比較什麼?
系列文
深入一點點認識 Git15
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言