iT邦幫忙

2025 iThome 鐵人賽

DAY 28
0
Software Development

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

Day 28-深入一點點認識 Git:那些在 .git/ 內還沒提過的資料夾與檔案(hooks/、config 與 description)

  • 分享至 

  • xImage
  •  

Medium 好讀版點此


回顧 Day 8 文章,我們提到一個空資料夾經過 git init 指令後,會出現 .git/ 資料夾如下:

.git/
├── hooks/                          # 尚未提及
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── fsmonitor-watchman.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   └── ...
│
├── info/                            # Day 19主題
│   └── exclude
│
├── objects/                         # Day 11、Day27主題
│   ├── info/
│   └── pack/
│
├── refs/                            # Day 11主題
│   ├── heads/
│   └── tags/                        # Day 15主題
│
├── config                           # 尚未提及
├── description                      # 尚未提及
└── HEAD                             # Day 9主題

以目前資料夾結構而言,我們只剩下 hooks/ 資料夾、config 檔案與 description 檔案還沒介紹,這些即是本篇文章的主題!

Git 的鉤子(hooks)

hooks/ 資料夾裡面有一個個副檔名為 .sample 的範例腳本,這些腳本即如資料夾名稱所示,稱為「鉤子(hooks)」,我們可以自定義在特定時機點要觸發什麼事件。

例如在名為 pre-commit.sample 檔案中,可以看到:

if [ "$allownonascii" != "true" ] &&           # 如果沒有說可以允許非ASCII內容
 # Note that the use of brackets around a tr range is ok here, (it's
 # even required, for portability to Solaris 10's /usr/bin/tr), since
 # the square bracket bytes happen to fall in the designated range.
 test $(git diff --cached --name-only --diff-filter=A -z $against |   # 且把所有ASCII字元都刪掉後還有剩餘字元(代表有非ASCII字元)
   LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
then
 cat <<\EOF
Error: Attempt to add a non-ASCII file name.    # 顯示錯誤訊息

上面寫得很複雜,但以大方向來說,可以理解成:

if 沒有說可以有非ASCII字元 && 
   把所有ASCII字元都刪掉後還有剩餘字元(代表有非ASCII字元)
then
 顯示錯誤訊息

也就是在形成 commit 之前,要先跑 pre-commit 這個鉤子,鉤子裡的內容包含檢查是否有非 ASCII 字元,如果有,就不能形成 commit。

其他鉤子一如其名,如 post-commit 是在形成 commit 之後跑、pre-rebase 是在進行 git rebase 之前跑...,依此類推。透過設定鉤子,我們得以細膩地設計在發生什麼事情前後要觸發客製化的腳本。

pre-commit 鉤子實驗

我們先以剛剛介紹的 pre-commit 鉤子為實驗對象。

要啟動這個鉤子,我們得先讓它不再是範例檔案,可輸入以下指令:

mv .git/hooks/pre-commit.sample .git/hooks/pre-commit

接著把 pre-commit 變成可執行檔案:

chmod +x .git/hooks/pre-commit

建立一個內容檔名含有非 ASCII 字元(如中文字)的檔案:

echo "This file has Chinese name." > "測試檔案.txt"

把這個檔案加到預存區:

git add 測試檔案.txt

試著形成一個 commit:

git commit -m "Test commit with invalid file name"

此時觸動 pre-commit 鉤子的檢查機制,因為發現有非 ASCII 字元,因此阻擋了這次 commit,並顯示剛剛在鉤子裡設定的錯誤訊息(截圖反白處):
https://ithelp.ithome.com.tw/upload/images/20250927/20178513oMhR7Fc0wS.png

提示訊息最後兩行還說到,如果想要關掉這樣的檢查機制,可以使用以下指令:

git config hooks.allownonascii true

這就帶到本文下一個要介紹的檔案:config

config

就是一些跟這個 git 資料夾有關的設定,在僅單純經過 git init 指令時,config 檔內容如下:

[core]
 repositoryformatversion = 0
 filemode = false
 bare = false
 logallrefupdates = true
 symlinks = false
 ignorecase = true
 autocrlf = input

[core] 表示這個 git 資料夾最核心的設定,包含:

  • repositoryformatversion:表示此倉儲的形式是用哪種版本。
  • filemode:看 git 要不要關注工作目錄中的可執行位元(executable bit),在 macOS 或 Linux 預設為 true、在 Windows 預設為 false
  • bare:看是不是 bare 倉儲,基本上會出現工作目錄的都不是,因此為 false
  • logallrefupdates:看在 .git/logs/ 資料夾是否持續更新歷史紀錄,預設為 true,這樣才能在做錯時,透過 git reflog 挽回。
  • symlinks:看是否用純文字處理符號鏈接(symbolic links),Linux 跟macOS 預設為 true,但在 Windows 為 false
  • ignorecase:看檔案系統是否要區分大小寫,Linux 預設為 false,但在 Windows 與 macOS 為 true
  • autocrlf:在每行結尾是否進行 Windows 的回車換行(Carriage Return + Line Feed, CRLF)與 Linux / macOS 系統的換行(Line Feed, LF)間之轉換,Linux 與 macOS 為 input、Windows 為 true

值得一提的是,我雖使用 Windows 系統,但在每次經 git init 初始化後,都會輸入以下指令更改 core.autocrlf

git config core.autocrlf input

讓其與 Linux / macOS 同步,否則經 git add 後會出現以下警告:
https://ithelp.ithome.com.tw/upload/images/20250927/201785130W1neVW66R.png

更改 config 的 hook

回到講解鉤子的尾聲,說可以把設定檔透過以下指令,改成可接受非 ASCII 字元:

git config hooks.allownonascii true

這時 config 檔案多了這兩行:

[hooks]
 allownonascii = true

現在這個 .git/ 所在的倉儲可接受非 ASCII 字元,我們就可以不受 pre-commit 鉤子的檢查,直接將 測試檔案.txt 完成 commit 如下:
https://ithelp.ithome.com.tw/upload/images/20250927/20178513Asv1GkbnDa.png

像上面我如果不希望每次都重新更改 core.autocrlf,也可以直接用以下指令,把全域都改成 input

git config - global core.autocrlf input

設定全域資訊

剛剛用 git config 設定的都僅限於局部(local)層級,也就是僅限於這個專案(嚴格來說是包含此 .git/ 資料夾的倉儲)有效,如果要設定整個系統(例如某臺電腦)的 git,則要用 --global,例如:

git config --global user.name "Ralph"

這樣只要在這臺電腦建立一個 git 資料夾,不管是哪個專案,預設的使用者名稱就都會是 Ralph

description

其實就是這份 git 專案的名稱,預設內文如下:

Unnamed repository; edit this file 'description' to name the repository.

可以透過以下指令修改:

"Day 28 Project" > .git/description

再透過 cat 指令檢視,就可發現 description 內文被改為 "Day 28 Project"
https://ithelp.ithome.com.tw/upload/images/20250927/201785133LYpZFKbhJ.png

但這份檔案只在 GitWeb(git 官方提供的輕量化網頁介面)有用,我們一般用來放專案的 GitHub 或 GitLab 皆不使用。

小結

本文總結 git init 之後出現的 .git/ 資料夾中,剩下尚未在過往文章中被討論的檔案與資料夾,包含:

  1. hooks/ 資料夾:存放多種鉤子範本,表示在特定時機要觸發的行為設定。
  2. config:git 的設定檔,可為局部或全域層級。
  3. description:專案名稱,僅在 GitWeb 會用到。

進行各類 git 操作後,.git/ 資料夾還會出現更多的下層資料夾(例如 logs/)與檔案(例如 ORIG_HEAD),在前面的文章遇到時,我們都曾經介紹過。

參考資料

  1. 8.3 Customizing Git - Git Hooks
  2. git-config
  3. 1.6 Getting Started - First-Time Git Setup
  4. What is Git's description file?
  5. 4.7 Git on the Server - GitWeb

上一篇
Day 27-深入一點點認識 Git:透過 git gc 指令觀察 git 的打包機制
下一篇
Day 29-深入一點點認識 Git:git fetch/pull 與 git clone 不只使用時機不同
系列文
深入一點點認識 Git31
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言