63 lines
2.0 KiB
Bash
Executable File
63 lines
2.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Nothing uncommitted goes out with a push.
|
|
#
|
|
# ## Where this came from
|
|
#
|
|
# There was already a `pre-push` in `.git/hooks` on this checkout when the
|
|
# template was adopted on 2026-08-18. Setting `core.hooksPath` to this directory
|
|
# would have silently stopped it running — the whole class of failure these
|
|
# hooks exist to prevent, applied to a hook — so its useful half was moved here,
|
|
# where it is versioned and every clone gets it.
|
|
#
|
|
# ## What was kept, and what was dropped
|
|
#
|
|
# **Kept:** the two working-tree checks. A push that leaves edits behind is how
|
|
# documentation ends up one commit adrift of the code it describes, and
|
|
# `docs/WORK_CYCLE.md` is built on those travelling together.
|
|
#
|
|
# **Dropped:** its third check, which refused the push when the branch was ahead
|
|
# of its remote. That is the precondition for pushing at all, so it fired on
|
|
# every real push and its only instruction was to re-run with `--no-verify` — a
|
|
# guard that can never pass teaches people to bypass the two beside it that can.
|
|
#
|
|
# ## Escape hatch
|
|
#
|
|
# git push --no-verify
|
|
#
|
|
# Deliberately not silent about it: the checks below print what they found
|
|
# before refusing, so an intentional bypass is a decision with the evidence in
|
|
# front of it.
|
|
#
|
|
# Exit 0 nothing outstanding, 1 something is.
|
|
|
|
set -uo pipefail
|
|
|
|
cd "$(git rev-parse --show-toplevel)" || exit 1
|
|
|
|
say() { printf '\033[1mpre-push:\033[0m %s\n' "$*" >&2; }
|
|
|
|
fail=0
|
|
|
|
if ! git diff --quiet --exit-code; then
|
|
say "uncommitted working-tree changes:"
|
|
git diff --name-only | sed 's/^/ /' >&2
|
|
fail=1
|
|
fi
|
|
|
|
if ! git diff --cached --quiet --exit-code; then
|
|
say "staged but uncommitted changes:"
|
|
git diff --cached --name-only | sed 's/^/ /' >&2
|
|
fail=1
|
|
fi
|
|
|
|
if [ "$fail" -ne 0 ]; then
|
|
say ""
|
|
say "push refused. Commit or stash the above first — a push that leaves edits"
|
|
say "behind is how the documents end up describing a commit nobody is running."
|
|
say "To push anyway: git push --no-verify"
|
|
exit 1
|
|
fi
|
|
|
|
exit 0
|