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
.
├── .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 ).
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
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.
# .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.
.githooks/ using the exact git hook name:touch .githooks/<hook-name>
chmod +x .githooks/<hook-name>
#!/usr/bin/env bash and set -euo pipefail.# 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
.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-hooksgit push is called with --no-verify, all hooks are skippedpost-push does not exist in git — use pre-push instead