問題描述
在提交時遇到執(zhí)行 hooks 失敗,錯誤提示“Not a git repository”
具體錯誤如下所示:
xyf$ git commit -m 'feat: test commit'
husky > pre-commit (node v8.11.3)
> pt-lego-service@1.0.0 precommit /Users/lego
> lint-staged
? Running tasks for **.{js, es6, jsx}
Not a git repository
To compare two paths outside a working tree:
usage: git diff [--no-index] <path> <path>
husky > pre-commit hook failed (add --no-verify to bypass)
husky 的配置如下:
"husky": {
"hooks": {
"pre-commit": "npm run precommit && git diff",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
},
"devDependencies": {
"husky": "^1.0.0-rc.8"
}
問題原因
參考網(wǎng)上資料,經(jīng)定位是運行 hooks 時的 Git 環(huán)境變量 GIT_DIR 錯誤造成
https://stackoverflow.com/questions/3542854/calling-git-pull-from-a-git-post-update-hook
驗證本地執(zhí)行 hooks 時的 GIT_DIR=.git单料,正確的 GIT_DIR 應(yīng)該為空(即未設(shè)置),在正常的電腦執(zhí)行 hooks 的 GIT_DIR 確認為空
確認原因
確認 GIT_DIR 的值使用這兩種方式点楼,一是在 pre-commit hooks 配置里增加 echo $GIT_DIR扫尖,二是在 .git/hooks/pre-commit 文件增加打印 echo $GIT_DIR
方法一,hooks 配置增加 echo $GIT_DIR
"husky": {
"hooks": {
"pre-commit": "echo $GIT_DIR && npm run precommit && git diff --check --staged",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
執(zhí)行結(jié)果如下:
xyf$ git commit -m 'fix: test comit 2'
pre-commit
husky > pre-commit (node v8.11.3)
.git
> pt-lego-service@1.0.0 precommit /Users/xieyufang/Documents/projects/pt-lego/service
> lint-staged
? Running tasks for **.{js, es6, jsx}
Not a git repository
To compare two paths outside a working tree:
usage: git diff [--no-index] <path> <path>
husky > pre-commit hook failed (add --no-verify to bypass)
方法二掠廓,.git/hooks/pre-commit 文件增加 echo $GIT_DIR
#!/bin/sh
# husky
# Hook created by Husky
# Version: 1.3.1
# At: 2020-7-15 22:10:18
# See: https://github.com/typicode/husky#readme
# From npm package
# Name: husky
# Directory: /Users/lego/node_modules/husky
# Homepage: https://github.com/typicode/husky#readme
echo $GIT_DIR;
scriptPath="service/node_modules/husky/run.js"
hookName=`basename "$0"`
gitParams="$*"
echo $hookName;
echo $gitParams;
debug() {
[ "${HUSKY_DEBUG}" = "true" ] && echo "husky:debug $1"
}
debug "$hookName hook started..."
if ! command -v node >/dev/null 2>&1; then
echo "Can't find node in PATH, trying to find a node binary on your system"
fi
if [ -f "$scriptPath" ]; then
# if [ -t 1 ]; then
# exec < /dev/tty
# fi
if [ -f ~/.huskyrc ]; then
debug "source ~/.huskyrc"
source ~/.huskyrc
fi
service/node_modules/run-node/run-node "$scriptPath" $hookName "$gitParams"
else
echo "Can't find Husky, skipping $hookName hook"
echo "You can reinstall it using 'npm install husky --save-dev' or delete this hook"
fi
運行結(jié)果如下:
xyf$ git commit -m 'fix: test comit 2'
.git
pre-commit
husky > pre-commit (node v8.11.3)
> pt-lego-service@1.0.0 precommit /Users/lego
> lint-staged
? Running tasks for **.{js, es6, jsx}
Not a git repository
To compare two paths outside a working tree:
usage: git diff [--no-index] <path> <path>
husky > pre-commit hook failed (add --no-verify to bypass)
解決問題
即然發(fā)現(xiàn)是 GIT_DIR 錯誤造成换怖,那就想辦法更改,試驗以下這幾種方法
// 1 通過指定 --git-dir 參數(shù)改變當前執(zhí)行的 Git 命令的環(huán)境變量
git --git-dir=.git {command}
// 2 重置 Git 運行的所有環(huán)境變量
unset $(git rev-parse --local-env-vars)
// 3 直接清除 GIT_DIR 的環(huán)境變量
unset GIT_DIR
// 4 Git 命令前追加 env -i 執(zhí)行
env -i git {command}
// 5 移除 husky 配置中相關(guān)的 Git 命令
git diff
直接修改 hooks 的配置
// 方法一:指定 --git-dir 參數(shù)蟀瞧,注意這里的執(zhí)行 hooks 和 .git 的相對目錄
// 這里執(zhí)行 hooks 是在倉庫的下一級目錄沉颂,所以這里指定 ../.git
"husky": {
"hooks": {
"pre-commit": "npm run precommit && git --git-dir=../.git diff",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
// 方法二:重置 Git 運行環(huán)境變量
"husky": {
"hooks": {
"pre-commit": "unset $(git rev-parse --local-env-vars) && npm run precommit && git diff",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
// 方法三:直接清除 GIT_DIR 的值
"husky": {
"hooks": {
"pre-commit": "unset GIT_DIR && npm run precommit && git diff",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
// 方法四:在 Git 的命令前加上 env -i
"husky": {
"hooks": {
"pre-commit": "npm run precommit && env -i git diff",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
// 方法五:移除有關(guān)的 Git 命令
// 即然是 GIT_DIR 環(huán)境變量錯誤造成的執(zhí)行 Git 命令錯誤,那直接移除相關(guān)命令也可以解決
"husky": {
"hooks": {
"pre-commit": "npm run precommit",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
經(jīng)驗證悦污,以上幾種方式都可以成功铸屉,完成 git commit
分析原因
上面的解決辦法只是臨時解決了問題,并沒有找到問題的根本原因切端,為什么會有 GIT_DIR 的不同的值彻坛,一開始是懷疑執(zhí)行 hooks 的環(huán)境造成,試圖找出 hooks 怎么執(zhí)行的踏枣,查找 Git Hook 和 husky 文檔依然未發(fā)現(xiàn)如何執(zhí)行昌屉,在接著試圖通過比較正常和出問題的電腦的本地環(huán)境和配置找出它們的差異性,依然沒有發(fā)現(xiàn)問題茵瀑。
針對同一個倉庫间驮,比較它們 husky 的安裝版本,比較它們 hooks 的命令马昨,這些都沒有差異
node_modules/husky
.git/hooks/pre-commit
再后來不經(jīng)意看到 husky 文檔提到的 hooks 不能正確執(zhí)行的原因有一句話
If not, you may have another Git hooks manager defined in your package.json overwriting husky's hooks. Check also the output during install, you should see:
husky > Setting up git hooks
husky > Done
然后就從 npm install 的 husky 日志方向上入手蜻牢,首先分別在正常和出問題的電腦上執(zhí)行 npm i 查看結(jié)果沒有差異烤咧,接著試著在出問題的電腦上新建 git 倉庫在安裝 husky 發(fā)現(xiàn)了差異點
當前倉庫 npm i 的結(jié)果,husky hooks 安裝成功
> husky@1.3.1 install /Users/lego/node_modules/husky
> node husky install
husky > setting up git hooks
husky > done
出問題的電腦抢呆,新倉庫的 npm i husky 記錄煮嫌,husky hooks 安裝失敗
xyf$ npm install husky --save-dev
> husky@4.2.5 install /Users/pt/node_modules/husky
> node husky install
Husky requires Node 10 (runtime: v8.11.3), skipping Git hooks installation.
> husky@4.2.5 postinstall /Users/pt/node_modules/husky
> opencollective-postinstall || exit 0
Thank you for using husky!
If you rely on this package, please consider supporting our open collective:
> https://opencollective.com/husky/donate
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN pt-lego-service@1.0.0 No license field.
+ husky@4.2.5
added 48 packages from 22 contributors and audited 48 packages in 8.645s
found 0 vulnerabilities
比較發(fā)現(xiàn)出問題原因是 husky@4.0 依賴 node > 10,而本地環(huán)境只有 8.11.3 造成 husky hooks 安裝失敗抱虐,而安裝成功的 husky 版本是 1.3.1 在當前的 node@8.11.3 版本下能安裝成功
綜合上面結(jié)果昌阿,比較出兩臺電腦的環(huán)境如下
husky@1.3.1 & node@8.11.3
husky@1.3.1 & node@v10.15.3
雖然基于上面的環(huán)境 husky hooks 都能安裝成功,但 node@8.11.3 下執(zhí)行 hooks 失敗恳邀,依然是因為 GIT_DIR = .git
在接著發(fā)現(xiàn)這個文章懦冰,Git 2.18.0 后不在設(shè)置 GIT_DIR
$GIT_DIR is no longer set when pre-commit hooks are called
As of the release of 2.18.0, $GIT_DIR is no longer set before calling pre-commit hooks. This change was introduced in "set_work_tree: use chdir_notify" (8500e0de) and is still present in master. I reviewed the discussion when this change was initially submitted, and I don't think this behavior change was intentional. I have several hooks that were broken like this, and from a quick Google search, using $GIT_DIR without setting a default does seem pretty common in hooks.
于是再查看兩臺機器的 Git 版本,一個是 2.15.1(有問題的機器)谣沸,一個是 2.21.0(正常的機器)刷钢,這解釋了為什么在node@8.11.3機器(有問題的機器)上執(zhí)行 hooks 時的環(huán)境變量 GIT_DIR 有值
在有問題的機器上新倉庫實驗 hooks 是成功的,但發(fā)現(xiàn)只要 node_module 和 .git 不是同一級目錄就會出現(xiàn)這個錯誤
結(jié)論
造成問題的原因還是版本的問題相互影響造成乳附,husky@1.3.1 + node@8.11.3 + git@2.15.1内地,基于這樣的環(huán)境的可以成功安裝 husky,但只能在 node_module 和 .git 目錄同級才能成功執(zhí)行 husky赋除,如果 .git 和 node_module 在不同目錄就會遇到當前的問題
附加
關(guān)于 git rev-parse --git-dir 命令的用法的解釋
The "right" way to find the directory has always been "git rev-parse --git-dir" (which will use GIT_DIR if set, and otherwise do the normal discovery process).
參考資料
https://github.com/typicode/husky/issues/364
https://stackoverflow.com/questions/3542854/calling-git-pull-from-a-git-post-update-hook
http://jakescruggs.blogspot.com/2010/07/using-git-inside-git-hook.html
https://mirrors.edge.kernel.org/pub/software/scm/git/docs/git.html
https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks
https://git-scm.com/docs/git-rev-parse
https://www.npmjs.com/package/husky#ci-servers
https://public-inbox.org/git/20180826004150.GA31168@sigill.intra.peff.net/t/