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
檔案還沒介紹,這些即是本篇文章的主題!
在 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
鉤子為實驗對象。
要啟動這個鉤子,我們得先讓它不再是範例檔案,可輸入以下指令:
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,並顯示剛剛在鉤子裡設定的錯誤訊息(截圖反白處):
提示訊息最後兩行還說到,如果想要關掉這樣的檢查機制,可以使用以下指令:
git config hooks.allownonascii true
這就帶到本文下一個要介紹的檔案: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
後會出現以下警告:
回到講解鉤子的尾聲,說可以把設定檔透過以下指令,改成可接受非 ASCII 字元:
git config hooks.allownonascii true
這時 config
檔案多了這兩行:
[hooks]
allownonascii = true
現在這個 .git/
所在的倉儲可接受非 ASCII 字元,我們就可以不受 pre-commit
鉤子的檢查,直接將 測試檔案.txt
完成 commit 如下:
像上面我如果不希望每次都重新更改 core.autocrlf
,也可以直接用以下指令,把全域都改成 input
:
git config - global core.autocrlf input
剛剛用 git config
設定的都僅限於局部(local)層級,也就是僅限於這個專案(嚴格來說是包含此 .git/
資料夾的倉儲)有效,如果要設定整個系統(例如某臺電腦)的 git,則要用 --global
,例如:
git config --global user.name "Ralph"
這樣只要在這臺電腦建立一個 git 資料夾,不管是哪個專案,預設的使用者名稱就都會是 Ralph
。
其實就是這份 git 專案的名稱,預設內文如下:
Unnamed repository; edit this file 'description' to name the repository.
可以透過以下指令修改:
"Day 28 Project" > .git/description
再透過 cat
指令檢視,就可發現 description
內文被改為 "Day 28 Project"
:
但這份檔案只在 GitWeb(git 官方提供的輕量化網頁介面)有用,我們一般用來放專案的 GitHub 或 GitLab 皆不使用。
本文總結 git init
之後出現的 .git/
資料夾中,剩下尚未在過往文章中被討論的檔案與資料夾,包含:
hooks/
資料夾:存放多種鉤子範本,表示在特定時機要觸發的行為設定。config
:git 的設定檔,可為局部或全域層級。description
:專案名稱,僅在 GitWeb 會用到。進行各類 git 操作後,.git/
資料夾還會出現更多的下層資料夾(例如 logs/
)與檔案(例如 ORIG_HEAD
),在前面的文章遇到時,我們都曾經介紹過。