61

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?

Anthony Sottile
  • 49,611
  • 12
  • 110
  • 158
Josh Smith
  • 14,110
  • 18
  • 68
  • 115

7 Answers7

61

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/*
Roman
  • 15,278
  • 11
  • 75
  • 80
  • 1
    Yeah, only this worked for me. – Arslan Shahab Oct 08 '21 at 07:54
  • From *"[What is Husky?](https://www.freecodecamp.org/news/how-to-add-commit-hooks-to-git-with-husky-to-automate-code-tasks/#what-is-husky)"*: *"Husky is a tool that allows us to easily wrangle Git hooks and run the scripts we want at those stages."* – Peter Mortensen Nov 24 '21 at 20:46
  • An explanation would be in order. E.g., what is the idea/gist? Why does it work? Why is *group* required? What is this *"husky"* thingy (for instance, I only have *dot* folders *".git"* and *".vscode"* in my repository)? What are the security implications of this change? What was context - some kind web development? Node.js? Please respond by [editing (changing) your answer](https://stackoverflow.com/posts/66757359/edit), not here in comments (***without*** "Edit:", "Update:", or similar - the answer should appear as if it was written today). – Peter Mortensen Nov 24 '21 at 20:47
45

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.

Dave Newton
  • 156,572
  • 25
  • 250
  • 300
  • I'm running git v1.7.6 on Mac OS X Lion. I'd done `git init` to reinitialize the repo and that still didn't work. I edited the file in TextMate, which might be the problem, but still doesn't explain why `git init` wouldn't do the `chmod u+x` properly. – Josh Smith Dec 22 '11 at 02:07
  • @JoshSmith `git init` only creates sample hooks, not actual ones. I'm running 1.7.5.4 on Lion, and 1.7.0 on Ubuntu--they both create the sample files as `u+x`--I guess I'm a little skeptical it isn't on yours. – Dave Newton Dec 22 '11 at 02:10
  • If nothing else I discovered my Linux box is running an old-ish version of git. – Dave Newton Dec 22 '11 at 02:11
  • So am I going to have to `chmod` every single time I modify the hook? – Josh Smith Dec 22 '11 at 02:12
  • @JoshSmith Uh, no, once it's set, you shouldn't need to change it again. – Dave Newton Dec 22 '11 at 02:13
  • I meant more when I do such a hook in any new git repo. That's going to get annoying. – Josh Smith Dec 22 '11 at 02:14
  • @JoshSmith Then change your `umask` setting, and hope you never accidentally execute something you didn't mean to. Not that typing "chmod u+x" is all that onerous. Or copy the samples that are already set. – Dave Newton Dec 22 '11 at 02:15
28

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.

VonC
  • 1,129,465
  • 480
  • 4,036
  • 4,755
3

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?

Dhaval L.
  • 46
  • 2
  • 6
2

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.

Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
ato
  • 714
  • 1
  • 5
  • 9
1

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.

Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Jakub Wagner
  • 398
  • 5
  • 14
0

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

Julien Carsique
  • 3,789
  • 3
  • 20
  • 28