55

I'm just starting to look into Git hooks, but I can't seem to get them to run.

I set up a local repository, so there is now a '.git' directory in my project folder. I have added a '.cmd' file into the C:/path/to/my/project/.git/hooks directory named 'pre-commit.cmd'. Here is the contents of this file:

echo "HOOK RUNNING"
echo. 2>C:/path/to/my/project/.git/hooks/EmptyFile.txt

This should echo the text "HOOK RUNNING" and create an empty text file in that directory. However, if I commit changes through my IDE (NetBeans) or use Git Bash to commit, neither of them seem to run my pre-commit hook, as no file is created.

My understanding is that all you have to do to get a hook to run is add an executable with the name of the hook (as I have done). Am I doing something wrong?

Note: This is on a Windows 7 PC.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user1578653
  • 4,888
  • 16
  • 46
  • 74
  • Related (the subject of some of the answers): *[Why is my Git pre-commit hook not executable by default?](https://stackoverflow.com/questions/8598639/)* – Peter Mortensen Nov 24 '21 at 18:35

9 Answers9

69

Name your hook pre-commit (without any file extension).

And add #!/bin/sh on the first line or #!/bin/bash.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Asenar
  • 6,732
  • 3
  • 36
  • 49
38

You probably don't have the permissions to run the pre-commit file

Run in your terminal:

chmod +x .git/hooks/pre-commit

Thanks to @vaughan for giving the idea

edi9999
  • 19,701
  • 13
  • 88
  • 127
22

TL;DR

Git hooks work on Git for Windows by default assuming the Git hook script is simple.

Background of Git and Windows

Please Note: Git was made for shell interpretation; thus, using Git hooks on a Windows command prompt or Windows-made PowerShell will inherently have its flaws, and complete interoperability is not to be expected.

Using Git hooks on Windows is possible, but it has many drawbacks.

Git for Windows uses a shell emulator that makes Bash and shell commands possible. This means that when a Git hook is activated by Git, the Windows version will run the command using the shell emulator. Which in turn, will convert those shell commands to commands that the Windows operating system can understand. Meaning, simple shell scripts will work right off the bat. For example, the Git hook pre-commit that ships with an initialization of a Git repository can be run without any modification.

Example of default behavior

  1. Initialize a Git repository with the command git init

  2. Navigate to the Git hooks directory with the command cd .git\hooks

  3. This directory holds all the Git hook scripts. Create a file named pre-commit. Note:

    The name of the file is important

  4. Replace the contents with the following shell script

    #!/bin/sh
    
    echo "Hello, World!"
    
    
  5. Navigate back to your root directory of the project and create a file named test.txt using the command echo "something" > text.txt

  6. Stage the file to commit using the command git add test.txt

  7. Commit the change and watch the pre-commit hook activate using the command git commit -m "test commit"

  8. Verify the output to look like the following

    git commit -m "test commit"
    Hello, World!
    [master f00ccea] test commit
    

Example of bad behavior

When using a very advanced shell script to do things in Git hooks, Windows shell interpretation doesn't always stack up. For example, when using the Husky Git hook plugin for NPM, along with the Prettier formatter, the commands do not map 1-1. Meaning that your pre-commit Git hook will fail on Windows.

Answering user1578653's question

A Git hook is an executable script; however, you are using a command prompt script (.cmd) and not a shell script (.sh). If you would like this behavior you described on a Windows operating system then create the file named pre-commit and place it in the .git\hooks directory (relative to the project you are working on). Then place the following content in that file.

.git\hooks\pre-commit

#!/bin/sh

echo "HOOK RUNNING"
thisCausesError 2> .git/hooks/EmptyFile.txt

You will notice that the Git hook works and outputs the words HOOK RUNNING to the console, and the thisCauseError will print an error message to standard error that will be printed to the file EmptyFile.txt.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • Indeed, even in a `git bash`, many commands in `pre-commit.sample`, created by default, do not work on my Windows installation. So I had to simplify it alot. – Joël Mar 02 '22 at 09:08
17

In my case, I had set core.hooksPath to the wrong directory.

Resetting it with git config --global core.hooksPath '~/.githooks' solved the issue :)

You can verify your hooks path using git config --get core.hooksPath

Synthesis
  • 463
  • 4
  • 5
mtraton
  • 179
  • 1
  • 8
  • I had enabled hooks for Cygwin by placing them into a subdirectory `./hooks` and making them visible to git with `cd .git; ln -sf ../hooks hooks`. As a consequence, git hooks were executed in Cygwin's git but not from within Emacs `M-x shell-command` or other places using `cmdproxy` or `cmd`, including `git gui`. After finding this answer, using `git config core.hookspath hooks` fixed it by being independent of whether git was invoked from within cmd or Cygwin's bash. – kdb Oct 13 '19 at 21:28
  • Thank you so much.. I had `error: cannot spawn .git/hooks/pre-commit: no such file or directory` This solution worked for me.. – Shokouh Dareshiri Sep 29 '21 at 10:12
  • helped to me, in windows! – mishaikon Mar 25 '22 at 14:50
  • something to not here is newer versions of husky hijack the hooksPath and point it to .husky folder. So if you're using husky run this command, verify your hookPath dir, and copy your client side hooks to the husky dir if husky kidnapped your hookPath var. – cobolstinks Mar 25 '22 at 17:59
  • solved thanks error is gone! – WorldOfEmre May 17 '22 at 08:28
2

For me, none of the previous solutions worked. I moved the pre-commit file from hooks to some other location, effectively deleting the file from hooks.

That worked for me :D

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Nilotpal
  • 3,237
  • 4
  • 34
  • 56
2

For me, I tried to run a .bat file.

I discovered that backslashes need to be escaped:

For example:

#!/bin/bash
C:\\somefolder\\somefile.bat
Shadi Alnamrouti
  • 11,796
  • 4
  • 56
  • 54
1

In my case, where I did npm install and accidentally deleted the .git folder, npm install pre-commit --save worked.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Theo
  • 1,932
  • 4
  • 17
  • 40
1

I tried solutions suggested in other answers and it didn't help to fix this problem:

cannot spawn .git/hooks/pre-commit: No such file or directory

The solution, which worked for me, was to rename the file .git/pre-commit.sample to .git/pre-commit and insert the script for formatting changed files with Prettier. The file with the name 'pre-commit' which I have created manually must have had some problems (encoding or end-line symbols remains unclear).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Lada
  • 21
  • 2
0

If it helps anyone:

I was getting the following error:

error: cannot spawn .git/hooks/pre-commit: No error

It turned out that in my pre-commit file I did not have 'newline' character after last exit command:

#!/bin/sh
# From gist at https://gist.github.com/chadmaughan/5889802

# Stash any unstaged changes
git stash -q --keep-index

# Run the tests with the Gradle wrapper
./gradlew test --daemon

# Store the last exit code in a variable
RESULT=$?

# Unstash the unstashed changes
git stash pop -q

# Return the './gradlew test' exit code
exit $RESULT
# << must have a newline after the above command >>

I was running a Gradle project on Windows and Gradle commands in the Cmder shell and cmd.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Yogesh
  • 125
  • 2
  • 13
  • 1
    Very unfortunately, many systems silently (and automatically) removes a 'newline' character at the very end of files, even if it is not an empty line (example: the [Arduino](https://en.wikipedia.org/wiki/Arduino) IDE). At the same time, many compilers can not handle a missing newline at the very end of a file. A workaround is to put some sort of comment at the very end of the file. – Peter Mortensen Nov 24 '21 at 16:29