尝试执行 git commit 时出现错误“fatal: cannot run .git/hooks/pre-commit: No such file or directory”。预提交文件就在那里

Getting the error "fatal: cannot run .git/hooks/pre-commit: No such file or directory" when trying to execute git commit. The pre-commit file is there

提问人:johhny tex 提问时间:9/29/2023 更新时间:9/30/2023 访问量:84

问:

我的情况

我在项目的 .git/hooks 目录中安装了一个预提交钩子。但是,每当我尝试执行提交时,我都会收到一条错误消息,指出预提交文件不存在。该文件肯定存在。如果我删除该文件,提交将再次正常发生,但对于这个项目,我确实需要在提交到存储库之前有一个预提交钩子。git commit -m "whatever"

我的环境

我在Visual Studio Code(VSCode)开发容器中运行。devcontainer 使用 WSL 支持的 (适用于 Linux 的 Windows 子系统) Docker 和从 .python:3.10-slim-bullseye

主机操作系统

OS Name: Microsoft Windows 11 Enterprise
Version: 10.0.22621 Build 22621

VSCode

Version: 1.77.3 (system setup)
Commit: 704ed70d4fd1c6bd6342c436f1ede30d1cff4710
Date: 2023-04-12T09:16:02.548Z
Electron: 19.1.11
Chromium: 102.0.5005.196
Node.js: 16.14.2
V8: 10.2.154.26-electron.0
OS: Windows_NT x64 10.0.22621
Sandboxed: No

开发容器

$ uname -a
Linux 4fb27f5c92e0 5.10.102.1-microsoft-standard-WSL2 #1 SMP Wed Mar 2 00:30:59 UTC 2022 x86_64 GNU/Linux

$ cat /etc/issue           
Debian GNU/Linux 11 \n \l

$ git --version                                                           
git version 2.30.2

我试过什么

例如,下面是运行命令的输出。提交将失败,并且不会因此错误而发生。git commit

$ git commit -m "arbitrary git commit message"
fatal: cannot run .git/hooks/pre-commit: No such file or directory

我认为可能预提交文件中存在导致问题的问题,所以我将文件剥离到骨头,只运行一个命令。但即使这样也行不通(同样,该文件也肯定存在,所以这样一个文件或目录,Linux/Git!echo "test"

$ cat .git/hooks/pre-commit               
#!/bin/bash

echo "test"

此外,以下是该文件的权限:

-rwxrwxrwx 1 me root 816 Sep 28 17:22 .git/hooks/pre-commit

我在哪里.这不是预提交文件内容的问题,因为预提交文件本身非常简单。据我所知,这是 Git 能够实际读取/执行文件的问题。me

我尝试在谷歌上搜索或查看其他关于预提交钩子遇到此问题的 SO 帖子,但大多数(所有?)这些问题都是预提交钩子代码本身的问题,而不是直接运行预提交钩子。

值得注意的是,pre-commit 在 devcontainer 之外工作

如果我使用我的主机 git 并尝试进行提交,则预提交钩子将运行(尽管它会遇到问题,因为我的主机没有预提交钩子尝试使用的软件,这些东西安装在 devcontainer 中)。这只是 devcontainer 中的一个问题。

我期望发生的事情

我希望我的钩子文件在我执行时执行。pre-commitgit commit

git pre-commit-hook vscode-devcontainer

评论

2赞 phd 9/29/2023
可以尝试直接运行吗?你能编辑问题并向我们展示文本输出吗?我怀疑该文件具有 DOS 行尾 (CR+LF) 而不是 Unix(只是 LF)。.git/hooks/pre-commitcat -v .git/hooks/pre-commit
0赞 johhny tex 9/29/2023
哦不,我觉得自己很傻。这确实是问题所在,EoL 是 CRLF 而不是 LF。非常感谢!我希望它产生了更有用的错误消息。

答:

1赞 johhny tex 9/29/2023 #1

根据的评论,我被要求尝试直接运行脚本,这揭示了问题。phd

$ .git/hooks/pre-commit       
zsh: .git/hooks/pre-commit: bad interpreter: /bin/bash^M: no such file or directory

此外,我还被要求提供文件的输出。cat -v

$ cat -v .git/hooks/pre-commit
#!/bin/bash^M
^M
echo "test"^M

这也凸显了问题所在。

问题出在行尾字符上。在 *nix(在本例中为 Linux)中,行尾字符是 或 换行符 (LF) 字符。在 Windows 中,行尾字符是 ,或回车符 (CR) 和换行符 (LF) 字符(通常缩写为 CRLF)。\n\r\n

为了解决这个问题,我能够使用 VScode 通过单击底部栏上的行结束按钮并将其从 CRLF 更改为 LF 来更改行结束字符。

显示文件现在将 LF 显示为行结束字符的图像,而不是之前显示的 CRLF。

我本可以做到这一点的另一种方法是使用命令行删除那些讨厌的 CR。类似于下面的东西,也许(未经测试)(也要注意,如果脚本中有其他目的,比如不在一行的末尾,它可能会破坏它):\r

cat .git/hooks/pre-commit | tr -d '\r' > .git/hooks/pre-commit.tmp && mv .git/hooks/pre-commit.tmp .git/hooks/pre-commit

评论

1赞 phd 9/29/2023
cat .git/hooks/pre-commit | … > .git/hooks/pre-commit我会非常害怕一个文件,同时重定向到它。如果 shell 决定第一次重定向,则文件将被截断为零长度。我的建议是做catcat .git/hooks/pre-commit | tr -d '\r' > .git/hooks/pre-commit.tmp && mv .git/hooks/pre-commit.tmp .git/hooks/pre-commit
1赞 johhny tex 9/30/2023
很公平。我用那句话编辑了答案!谢谢