WRITELOOP

EASY WAY TO DISTRIBUTE GIT HOOKS

I needed a way to run a script to sync my local repo to a machine that cannot have git installed, right after I made a git push. I didn't want to install `pre-commit` or any other tool for that (and I wanted the hooks versioned on the repo), so I searched for a way to do that the simplest way possible and I was able to came up with a solution. Here I describe how I was able to achieve that.

2026 April 27

How I did that?

You are able to config git for all your repositories, and you can also customize that per repository.

So I created a Makefile on the root of the repository with a command to customize the path where it would find the git hooks, and the path is a folder called .githooks on the repository root.

The command must run only once, and it will then setup the configuration for the repository.

That way I am able to version and share the hooks with anyone that clones the repo, and I can then achieve the sync that I need using the pre-push hook.

Directory structure

## Directory structure

.
├── .githooks/
│ └── pre-push # fires before every successful git push
├── sync-to-xplab.sh # script called by the hook
└── Makefile

IMPORTANT: all files under .githooks must be executable (they are simple shellscripts ).

The hook

I had to go with the pre-push hook, since there is not a post-push.

You can understand which other hooks are available running an ls on you repo .git/hooks folder. E.g.:


❯ ls -lha .git/hooks/
total 68K
drwxr-xr-x 2 tiago tiago tiago 4.0K 2023-08-05 18:58 .
drwxr-xr-x 9 tiago tiago tiago 4.0K 2026-04-03 07:08 ..
-rwxr-xr-x 1 tiago tiago tiago  536 2023-08-05 18:58 applypatch-msg.sample
-rwxr-xr-x 1 tiago tiago tiago  954 2023-08-05 18:58 commit-msg.sample
-rwxr-xr-x 1 tiago tiago tiago 4.7K 2023-08-05 18:58 fsmonitor-watchman.sample
-rwxr-xr-x 1 tiago tiago tiago  247 2023-08-05 18:58 post-update.sample
-rwxr-xr-x 1 tiago tiago tiago 1.7K 2023-08-05 18:58 prepare-commit-msg.sample
-rwxr-xr-x 1 tiago tiago tiago  482 2023-08-05 18:58 pre-applypatch.sample
-rwxr-xr-x 1 tiago tiago tiago 1.7K 2023-08-05 18:58 pre-commit.sample
-rwxr-xr-x 1 tiago tiago tiago  474 2023-08-05 18:58 pre-merge-commit.sample
-rwxr-xr-x 1 tiago tiago tiago 1.4K 2023-08-05 18:58 pre-push.sample
-rwxr-xr-x 1 tiago tiago tiago 4.9K 2023-08-05 18:58 pre-rebase.sample
-rwxr-xr-x 1 tiago tiago tiago  602 2023-08-05 18:58 pre-receive.sample
-rwxr-xr-x 1 tiago tiago tiago 2.8K 2023-08-05 18:58 push-to-checkout.sample
-rwxr-xr-x 1 tiago tiago tiago 3.7K 2023-08-05 18:58 update.sample

The automation

To setup the versioned hooks folder as the default for the repository, I created a Makefile


SHELL := /bin/bash  # necessary to use the source command, which is not on sh, Makefile's default shell ;)

help:  ## This help
	@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) | sort

setup-hooks:  ## Setup the git hooks on this repository
	git config core.hooksPath .githooks

After cloning the repository (or at any moment), I (or any other contributor) can run the setup command to point git at the local hooks directory:

make setup-hooks

This sets core.hooksPath = .githooks in your local .git/config.

Without this step, git uses .git/hooks/ instead and the hooks will not fire.

How the pre-push hook works

# .githooks/pre-push
#!/usr/bin/env bash
set -euo pipefail

echo "→ Syncing to xplab..."
"$(git rev-parse --show-toplevel)/sync-to-xplab.sh"

The hook resolves the repo root dynamically via git rev-parse --show-toplevel, so it works regardless of which subdirectory you run git push from.

Adding a new hook

  1. Create the hook file in .githooks/ using the exact git hook name:
    touch .githooks/<hook-name>
    chmod +x .githooks/<hook-name>
    
  2. Write your script using #!/usr/bin/env bash and set -euo pipefail.
  3. Commit the file

Verify the setup is correct

# Should print: .githooks
git config core.hooksPath

# Should show -rwxr-xr-x permissions
ls -la .githooks/

# Manually test a hook without pushing
bash .githooks/pre-push

Important notes

  • .git/hooks/ is not tracked by git. So, never put hooks there directly.
  • core.hooksPath is a local config setting. So, every contributor must run make setup-hooks
  • If git push is called with --no-verify, all hooks are skipped
  • post-push does not exist in git — use pre-push instead

TAGS