Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Putting git hooks into repository

Tags:

git

githooks

hook

People also ask

Are Git hooks pushed to repo?

The pre-receive hook is executed every time somebody uses git push to push commits to the repository.

How do you add a hook to github?

To set up a webhook, go to the settings page of your repository or organization. From there, click Webhooks, then Add webhook. Alternatively, you can choose to build and manage a webhook through the Webhooks API. Webhooks require a few configuration options before you can make use of them.

Are Git hooks pushed to github?

No. Hooks are per-repository and are never pushed.

Where are git hooks stored?

The hooks are all stored in the hooks subdirectory of the Git directory. In most projects, that's . git/hooks .


I generally agree with Scytale, with a couple additional suggestions, enough that it's worth a separate answer.

First, you should write a script which creates the appropriate symlinks, especially if these hooks are about enforcing policy or creating useful notifications. People will be much more likely to use the hooks if they can just type bin/create-hook-symlinks than if they have to do it themselves.

Second, directly symlinking hooks prevents users from adding in their own personal hooks. For example, I rather like the sample pre-commit hook which makes sure I don't have any whitespace errors. A great way around this is to drop in a hook wrapper script in your repo, and symlink all of the hooks to it. The wrapper can then examine $0 (assuming it's a bash script; an equivalent like argv[0] otherwise) to figure out which hook it was invoked as, then invoke the appropriate hook within your repo, as well as the appropriate user's hook, which will have to be renamed, passing all the arguments to each. Quick example from memory:

#!/bin/bash
if [ -x $0.local ]; then
    $0.local "$@" || exit $?
fi
if [ -x tracked_hooks/$(basename $0) ]; then
    tracked_hooks/$(basename $0) "$@" || exit $?
fi

The installation script would move all pre-existing hooks to the side (append .local to their names), and symlink all known hook names to the above script:

#!/bin/bash
HOOK_NAMES="applypatch-msg pre-applypatch post-applypatch pre-commit prepare-commit-msg commit-msg post-commit pre-rebase post-checkout post-merge pre-receive update post-receive post-update pre-auto-gc"
# assuming the script is in a bin directory, one level into the repo
HOOK_DIR=$(git rev-parse --show-toplevel)/.git/hooks

for hook in $HOOK_NAMES; do
    # If the hook already exists, is executable, and is not a symlink
    if [ ! -h $HOOK_DIR/$hook -a -x $HOOK_DIR/$hook ]; then
        mv $HOOK_DIR/$hook $HOOK_DIR/$hook.local
    fi
    # create the symlink, overwriting the file if it exists
    # probably the only way this would happen is if you're using an old version of git
    # -- back when the sample hooks were not executable, instead of being named ____.sample
    ln -s -f ../../bin/hooks-wrapper $HOOK_DIR/$hook
done

No, putting them into the repository is fine, I’d even suggest doing so (if they are useful for others as well). The user has to explicitly enable them (as you said, for example by symlinking), which is on one hand a bit of a pain, but protects users on the other hand from running arbitrary code without their consent.


Nowadays you can do the following to set a directory that is under version control to be your git hooks directory, e.g., MY_REPO_DIR/.githooks would be

git config --local core.hooksPath .githooks/

Still not directly enforceable but, if you add a note in your README (or whatever), this requires a minimum of effort on each developer's part.


Store in the project and install in the build

As others state in their answer, If your hooks are specific for your particular projects then include them in the project itself, managed by git. I would take this even further and say that, given that it is good practice to have your project build using a single script or command, your hooks should be installed during the build.

I wrote an article about managing git hooks, if you are interested in reading about this in a little more depth.

Java & Maven

Full disclaimer; I wrote the Maven plugin described below.

If you are handling build management with Maven for your Java projects, the following Maven plugin handles installing hooks from a location in your project.

https://github.com/rudikershaw/git-build-hook

Put all your Git hooks in a directory in your project, then configure your pom.xml to include the following plugin declaration, goal, and configuration.

<build>
  <plugins>
    <plugin>
      <groupId>com.rudikershaw.gitbuildhook</groupId>
      <artifactId>git-build-hook-maven-plugin</artifactId>
      <configuration>
        <gitConfig>
          <!-- The location of the directory you are using to store the Git hooks in your project. -->
          <core.hooksPath>hooks-directory/</core.hooksPath>
        </gitConfig>
      </configuration>
      <executions>
        <execution>
          <goals>       
            <!-- Sets git config specified under configuration > gitConfig. -->
            <goal>configure</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
      <!-- ... etc ... -->
  </plugins>
</build>

When you run your project build the plugin will configure git to run hooks out of the directory specified. This will effectively set up the hooks in that directory for everyone working on your project.

JavaScript & NPM

For NPM there is a dependency called Husky which allows you to install hooks including ones written in JavaScript.

// package.json
{
  "husky": {
    "hooks": {
      "pre-commit": "npm test",
      "pre-push": "npm test",
      "...": "..."
    }
  }
}

Others

Additionally, there are a number of different hook management applications/plugins including pre-commit for Python projects, Overcommit for Ruby projects, and Lefthook for Ruby or Node projects.


From http://git-scm.com/docs/git-init#_template_directory, you could use one of these mechanisms to update the .git/hooks dir of each newly created git repo:

The template directory contains files and directories that will be copied to the $GIT_DIR after it is created.

The template directory will be one of the following (in order):

  • the argument given with the --template option;

  • the contents of the $GIT_TEMPLATE_DIR environment variable;

  • the init.templateDir configuration variable; or

  • the default template directory: /usr/share/git-core/templates.