Why is my Git pre-commit hook not executable by default?

If you see the accepted answer in: Aggregating and uglifying JavaScript in a Git pre-commit hook, you'll see that I had to do a chmod +x on my pre-commit hook to get it to work.

Why is this not executable by Git by default?

76826 次浏览

Because files are not executable by default; they must be set to be executable.

The sample files from a git init are all executable; if it's copied or renamed to a non-sample file, it will retain the original file's x flag.

New files will be created with current defaults. In your case, view those defaults with umask:

$ umask
0022

By default, new files won't be u+x unless explicitly set to be.

I had to do a chmod +x on my pre-commit hook to get it to work

The problem is to realize that it was not executable in the first place.
That will be easier with Git 2.15.x/2.16 (Q1 2018)

See commit f805a00 (06 Oct 2017) by Damien Marié (mdamien).
(Merged by Junio C Hamano -- gitster -- in commit 130b512, 06 Nov 2017)

run-command: add hint when a hook is ignored

When an hook is present but the file is not set as executable then git will ignore the hook.
For now this is silent which can be confusing.

This commit adds this warning to improve the situation:

hint: The 'pre-commit' hook was ignored because it's not set as executable.
hint: You can disable this warning with `git config advice.ignoredHook false`

To allow the old use-case of enabling/disabling hooks via the executable flag a new setting is introduced: advice.ignoredHook.

Just as an add-on answer, here is the function, you can use for initializing a Git repository, which automatically makes hooks executables; you should put it in .bashrc or a file you source when you start your terminal. The story is below :)

ginit () {
git init
gitpath=`git rev-parse --show-superproject-working-tree --show-toplevel | head -1`
chmod u+x "$gitpath"/.git/hooks/*
for submodule in "$gitpath"/.git/modules/*; do
chmod u+x "$submodule"/hooks/*
done
}

I was annoyed by the same thing as you. I do not want to remember that I have to make all hooks executables every time I initialize a repository. Plus, when you use submodules, their hooks are not in .git/hooks, but in .git/modules/NameOfSubmodule/hooks, and these should be made executables too.

I had the same symptoms, but a totally different cause:

In addition to setting the right permission bits via chmod +x .git/hooks/pre-commit, please make sure your file system is mounted in a way that allows those changes. This can, e.g., be an issue when you have a dual-boot system where you are working on an ntfs-3g mounted Windows drive under Linux.

You can fix it by changing the default permissions in /etc/fstab or the systemd equivalent.

My context - web development Node.js. I needed to add husky functionality, but got an error, probably to the disk access. This helped in my situation:

chmod ug+x .husky/*
chmod ug+x .git/hooks/*

Just as a reference, after making the file executable, if that appears in git file changes because of file mode changes, the following would work: (tried in Ubuntu/Linux)

chmod ug+x .husky/pre-commit # make file executable
git config core.filemode false # to ignore file mode changes

Reference: How do I remove files saying "old mode 100755 new mode 100644" from unstaged changes in Git?

The original template hook file must be executable.

In my case, it was a custom hook missing the executable bit:

$ git config init.templateDir
~/.git_template
$ stat -c "%A" ~/.git_template/hooks/pre-commit
-rw-r--r--
$ chmod u+x ~/.git_template/hooks/pre-commit

Now the pre-commit hook created on git init or git clone is properly set as executable:

$ git init hook-exec
$ stat -c "%A" hook-exec/.git/hooks/pre-commit
-rwxrwxr-x

See https://git-scm.com/docs/git-init#_template_directory

I was able to solve it by just running the command below.

chmod ug+x .husky/*

I init husky in Windows. After that, the problem occurred in WSL, and it is probably a problem that was not created considering the file permissions of Linux at the time of init in Windows.