aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/dot_config/git/hooks/_dispatch.sh
diff options
context:
space:
mode:
Diffstat (limited to 'dot_config/git/hooks/_dispatch.sh')
-rw-r--r--dot_config/git/hooks/_dispatch.sh44
1 files changed, 29 insertions, 15 deletions
diff --git a/dot_config/git/hooks/_dispatch.sh b/dot_config/git/hooks/_dispatch.sh
index 7dcd89c..0b1135d 100644
--- a/dot_config/git/hooks/_dispatch.sh
+++ b/dot_config/git/hooks/_dispatch.sh
@@ -1,16 +1,26 @@
#!/bin/sh
-# Sourced by every hook in this directory. Runs the per-repo hook of the
-# same name from `<repo-top>/.githooks/` if it exists, then returns
-# control so the calling user-level hook can do its own work after.
+# Sourced by every hook in this directory. Runs the per-repo hook of
+# the same name and then returns control so the calling user-level
+# hook can do its own work after.
#
-# Repos opt in by just dropping `.githooks/<hookname>` (executable) in
-# the working tree — no per-repo `core.hooksPath` setting, no stubs.
-# If the per-repo hook exits non-zero we abort with that status so git
-# sees the failure.
+# Lookup order (first executable file wins):
+# 1. `<git-dir>/hooks-local/<hookname>` — untracked per-clone override,
+# lives inside .git/ so it stays personal. Use this when you want
+# to replace a tracked .githooks/<name> on a shared repo without
+# affecting teammates. Create with e.g.:
+# $ mkdir -p "$(git rev-parse --git-dir)/hooks-local"
+# $ $EDITOR "$(git rev-parse --git-dir)/hooks-local/pre-commit"
+# $ chmod +x "$(git rev-parse --git-dir)/hooks-local/pre-commit"
+# 2. `<repo-top>/.githooks/<hookname>` — tracked, the project's
+# shared hook. The intended default for opting a repo in.
+#
+# Either an empty file with exit 0 or no hook at all means "skip the
+# project layer entirely"; the user-level hook still runs its own
+# global logic afterwards.
#
# GIT_HOOK_DISPATCHED guards against re-entry: if some legacy repo has
# its own `.githooks/<hook>` that ends with `exec "$HOME/.config/..."`
-# (the old pattern), we won't dispatch back into it a second time.
+# (the old stub pattern), we won't dispatch back into it a second time.
# shellcheck shell=sh
dispatch_repo_hook() {
@@ -19,13 +29,17 @@ dispatch_repo_hook() {
[ -n "${GIT_HOOK_DISPATCHED:-}" ] && return 0
+ gitdir=$(git rev-parse --git-dir 2>/dev/null) || return 0
root=$(git rev-parse --show-toplevel 2>/dev/null) || return 0
- repo_hook="$root/.githooks/$hookname"
- [ -x "$repo_hook" ] || return 0
- GIT_HOOK_DISPATCHED=1 "$repo_hook" "$@"
- rc=$?
- if [ "$rc" -ne 0 ]; then
- exit "$rc"
- fi
+ for candidate in "$gitdir/hooks-local/$hookname" "$root/.githooks/$hookname"; do
+ if [ -x "$candidate" ]; then
+ GIT_HOOK_DISPATCHED=1 "$candidate" "$@"
+ rc=$?
+ if [ "$rc" -ne 0 ]; then
+ exit "$rc"
+ fi
+ return 0
+ fi
+ done
}