Git commit 遇到的 precommit Not a git repository 錯誤

問題描述

在提交時遇到執(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/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末阱缓,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子举农,更是在濱河造成了極大的恐慌荆针,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件颁糟,死亡現(xiàn)場離奇詭異航背,居然都是意外死亡,警方通過查閱死者的電腦和手機棱貌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進店門玖媚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人键畴,你說我怎么就攤上這事最盅。” “怎么了起惕?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵涡贱,是天一觀的道長。 經(jīng)常有香客問我惹想,道長问词,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任嘀粱,我火速辦了婚禮激挪,結(jié)果婚禮上辰狡,老公的妹妹穿的比我還像新娘。我一直安慰自己垄分,他們只是感情好宛篇,可當我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著薄湿,像睡著了一般叫倍。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上豺瘤,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天吆倦,我揣著相機與錄音,去河邊找鬼坐求。 笑死蚕泽,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的桥嗤。 我是一名探鬼主播须妻,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼砸逊!你這毒婦竟也來了璧南?” 一聲冷哼從身側(cè)響起掌逛,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤师逸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后豆混,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體篓像,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年皿伺,在試婚紗的時候發(fā)現(xiàn)自己被綠了员辩。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡鸵鸥,死狀恐怖奠滑,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情妒穴,我是刑警寧澤宋税,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站讼油,受9級特大地震影響杰赛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜矮台,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一乏屯、第九天 我趴在偏房一處隱蔽的房頂上張望根时。 院中可真熱鬧,春花似錦辰晕、人聲如沸蛤迎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽忘苛。三九已至,卻和暖如春唱较,著一層夾襖步出監(jiān)牢的瞬間扎唾,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工南缓, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留胸遇,地道東北人。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓汉形,卻偏偏與公主長得像纸镊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子概疆,可洞房花燭夜當晚...
    茶點故事閱讀 45,060評論 2 355