Skip to content

Drop the local pre-push test hook — CI already runs the same suite, better, and the hook now breaks pushes #355

Description

@fdaviddpt

What is there

Maintainer clones carry an untracked .git/hooks/pre-push:

#!/bin/bash
# Pre-push hook: run the test suite before pushing
echo "Running tests before push..."
cd "$(git rev-parse --show-toplevel)"
python3 -m pytest tests/ -q
exit $?

Nothing in the tree installs it and nothing documents it — grep pre-push over the repo finds only
CHANGELOG.md, hooks.d/after_save/50-git-backup.sh and tests/test_git_backup_push_rejected_253.py,
and all three are about parsing around a pre-push hook's output, not about installing one. So this
is per-machine state that every push pays for and no new contributor inherits.

Why it should go

CI is strictly stronger. .github/workflows/tests.yml runs on push: [main] and on every
pull_request, across ubuntu-latest/macos-latest/windows-latest × Python 3.9–3.12 — 12 legs.
The hook runs one OS and one interpreter, which is the platform this repo's own contributor guidance
calls "the weakest evidence available" about the platforms it was not run on. A green hook and a red
matrix is the normal outcome, not the surprising one, and the hook is what makes the push slow enough
that the matrix result is the one nobody waits for.

It has stopped being merely slow and started failing pushes. Measured on 2026-08-18 pushing one
one-line config change to chore/oss-scaffold:

  • push 1 — killed at the 1500 s budget, still inside the hook, remote unmoved;
  • push 2 — budget raised to 1800 s. The suite passed (1576 passed, 43 skipped in 1674.11s) and then
    the push died on Connection to github.com closed by remote host. The transport is opened before the
    hook runs, so a 28-minute hook holds an idle SSH connection until the remote hangs up. git reported
    no ref status at all: the push was stopped before it reached the remote;
  • push 3 — --no-verify, pushed in 5.8 s.

About 53 minutes to push one line, and the failing mode is the bad one: the suite passes, the push does
not, and the receipt says the remote closed the connection. The workaround that works is skipping the
hook, which is the same thing as not having it, arrived at once per push under time pressure.

It also runs the wrong suite. pytest tests/ -q with no -p no:cacheprovider, no coverage gate and
no marker selection is not what CI runs, so a pass here is not evidence about the gate that actually
blocks a merge.

Proposed change

  1. Remove .git/hooks/pre-push from maintainer clones. There is nothing to delete in the tree.
  2. Say so in CLAUDE.md under Before you open a pull request: the suite is run locally on demand and
    the gate is CI, so nobody re-adds this hook from memory. That sentence is the only durable part of
    this issue — everything else is one rm on one machine.

If a local gate is wanted, the honest shape is a fast one that cannot hold a transport open: a hook that
runs a marked subset in seconds, or a pytest invocation the contributor runs before git push rather
than during it.

Not this issue

Whether the 28-minute suite is itself too slow. It is the same 1576 tests CI runs in parallel across 12
legs; serialising them on one machine is the cost being questioned here, not the test count.

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority:lowReal, but neither blocking nor compounding fast

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions