在 Fork 使用 Husky 進行 pre-commit 發生錯誤

Ref

情境

因為平常習慣用用 Git-Fork 來進行 git 相關作業, 但在試圖使用 husky 的 pre commit hook 時遇到一些問題.

.husky/pre-commit: line 4: npx: command not found
husky - pre-commit hook exited with code 127 (error)

按照錯誤訊息的描述, 是在執行 .husky/pre-commit 這個指令的時候, 讀取該腳本的的第 4 行發生 npx command not found.

先說解法

老實說, 這是我第一次接觸 Husky 就拿著關鍵字亂查了一下. 而問題發生的原因, 依據 Command-not-found 的描述, 有可能是 npx 沒辦法執行, 或是 node 環境發生問題. 推測大概是系統環境變數無法正常被 Fork 工具存取到. 另外建立了 ~/.huskyrc 確實解決了我的問題.

# ~/.huskyrc
# This loads nvm.sh and sets the correct PATH before running hook
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

上面的腳本大概解釋如下

  • 第一部分 -s "$NVM_DIR/nvm.sh" 會檢查 $NVM_DIR 目錄下的 nvm.sh 檔案是否存在.

  • 第二部分 && \. "$NVM_DIR/nvm.sh 中的 && 是一個邏輯運算符,它表示當第一部分條件成立時才會執行第二部分. \. 會執行 nvm.sh 檔案中的程式碼.

Why

事實上, 我確定我有上面的相關設定, 我是用 NVM (Node Version Manager) 管理我的 Node 版本沒錯. 依據 NVM 的官方文件, 我在 ~/.bash_profile 裡面有了這段設定.

# nvm
export NVM_DIR="$HOME/.nvm"
. "/usr/local/opt/nvm/nvm.sh"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads

我另外分別於 ~/.bash_profile~/.zshrc 加入 echo 確認過載入順序是

  1. ~/.zshrc

  2. ~/.bash_profile

fork-dev Issue 1227

在這個討論串內, 確實有提到 Fork 運行時, 是一個獨立的 shell 環境, 不會特別去載入使用者的 PATH 環境變數. 意思是不會讀取到 ~/.zshrc 這些 PATH, 導致沒有載入到 NVM 的相關環境變數.

fork-dev Issue 1261

然而在這個討論串內, 提到用指令打開 Fork open -a Fork, 會讓 Fork 繼承 Parent process, 也就是會繼承 runtime 指令的環境變數. 在這個階段下打開 Fork 又可以 commit 了. 但我自己的習慣都是用 Mac Spotlight 來開啟相關工具, 所以這個解法對我來說有點不順手 XD.

反正 Fork 執行 git commit 的時候會觸發 husky (我並不是很確定 husky 運作方式 XD) 所以我在 ~/.husky/pre-commit 檔案內加入 echo $PATH, 間接的確認到 Fork 的 runtime 的環境變數了.

/usr/local/Cellar/git/2.32.0/libexec/git-core
/Applications/Fork.app/Contents/Resources/git-instance/git-lfs
/Applications/Fork.app/Contents/Resources/gitflow-avh
/opt/homebrew/bin
/usr/local/bin
/usr/bin
/bin
/usr/sbin
/sbin

裡面當然沒有 NVM 相關環境變數 XD, 也沒有 ~/.zshrc~/.bash_profile.

總結

解法 1

採用 ~/.huskyrc 作法, 讓 husky 指令能夠讀取到 nvm 環境變數.

# ~/.huskyrc
# This loads nvm.sh and sets the correct PATH before running hook
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

但目前 huskyrc 似乎已經廢棄了, 但可以依據 官方 說明, 檔名路徑修改為 ~/.config/husky/init.sh.

解法 2

用 terminal 打開 Fork,

open -a Fork

解法 3

把當下的 node 相關指令, 用建立捷徑的方式 (symbolic link), 把 node 相關的 bin 連結到 /usr/local/bin, 但這樣設定下去 node 就變成全域 (有好有壞).


ln -s $(which node) /usr/local/bin/node