diff options
Diffstat (limited to 'dot_config/git')
| -rw-r--r-- | dot_config/git/hooks/_dispatch.sh | 31 | ||||
| -rwxr-xr-x | dot_config/git/hooks/executable_commit-msg | 4 | ||||
| -rwxr-xr-x | dot_config/git/hooks/executable_post-commit | 14 | ||||
| -rwxr-xr-x | dot_config/git/hooks/executable_pre-commit | 15 | ||||
| -rwxr-xr-x | dot_config/git/hooks/executable_pre-push | 11 |
5 files changed, 74 insertions, 1 deletions
diff --git a/dot_config/git/hooks/_dispatch.sh b/dot_config/git/hooks/_dispatch.sh new file mode 100644 index 0000000..7dcd89c --- /dev/null +++ b/dot_config/git/hooks/_dispatch.sh @@ -0,0 +1,31 @@ +#!/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. +# +# 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. +# +# 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. + +# shellcheck shell=sh +dispatch_repo_hook() { + hookname=$1 + shift + + [ -n "${GIT_HOOK_DISPATCHED:-}" ] && 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 +} diff --git a/dot_config/git/hooks/executable_commit-msg b/dot_config/git/hooks/executable_commit-msg index 78dba63..e484ccb 100755 --- a/dot_config/git/hooks/executable_commit-msg +++ b/dot_config/git/hooks/executable_commit-msg @@ -12,6 +12,10 @@ set -eu +# shellcheck source=./_dispatch.sh +. "${0%/*}/_dispatch.sh" +dispatch_repo_hook commit-msg "$@" + msg_file=$1 # Keep this list in sync with executable_pre-push. diff --git a/dot_config/git/hooks/executable_post-commit b/dot_config/git/hooks/executable_post-commit new file mode 100755 index 0000000..45f13f0 --- /dev/null +++ b/dot_config/git/hooks/executable_post-commit @@ -0,0 +1,14 @@ +#!/bin/sh +# User-level post-commit. No global checks — exists purely so that +# `<repo>/.githooks/post-commit` gets picked up automatically without +# the project needing to override core.hooksPath. If there is no +# per-repo hook this is a no-op. post-commit's exit status is ignored +# by git, but we still propagate it for clarity. + +set -eu + +# shellcheck source=./_dispatch.sh +. "${0%/*}/_dispatch.sh" +dispatch_repo_hook post-commit "$@" + +exit 0 diff --git a/dot_config/git/hooks/executable_pre-commit b/dot_config/git/hooks/executable_pre-commit new file mode 100755 index 0000000..548925b --- /dev/null +++ b/dot_config/git/hooks/executable_pre-commit @@ -0,0 +1,15 @@ +#!/bin/sh +# User-level pre-commit. No global checks — exists purely so that +# `<repo>/.githooks/pre-commit` gets picked up automatically without +# the project needing to override core.hooksPath. If there is no +# per-repo hook this is a no-op. +# +# Bypass: git commit --no-verify + +set -eu + +# shellcheck source=./_dispatch.sh +. "${0%/*}/_dispatch.sh" +dispatch_repo_hook pre-commit "$@" + +exit 0 diff --git a/dot_config/git/hooks/executable_pre-push b/dot_config/git/hooks/executable_pre-push index ba7dc60..286958b 100755 --- a/dot_config/git/hooks/executable_pre-push +++ b/dot_config/git/hooks/executable_pre-push @@ -15,6 +15,15 @@ set -eu +# shellcheck source=./_dispatch.sh +. "${0%/*}/_dispatch.sh" +# Buffer stdin so both the per-repo hook and our own loop below get the +# full ref list (git only feeds it once). +_stdin_buf=$(mktemp) +trap 'rm -f "$_stdin_buf"' EXIT INT TERM +cat >"$_stdin_buf" +dispatch_repo_hook pre-push "$@" <"$_stdin_buf" + zero=$(git hash-object --stdin </dev/null | tr '0-9a-f' '0') expected_name=$(git config user.name || true) @@ -108,7 +117,7 @@ while read -r _local_ref local_sha remote_ref remote_sha; do printf '\non %s:\n%s\n' "$remote_ref" "$bad" >&2 fail=1 fi -done +done <"$_stdin_buf" if [ "$fail" -ne 0 ]; then printf '\nfix sig + committer:\n' >&2 |
