Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .githooks/pre-merge-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/usr/bin/env bash
# The merge analogue of pre-commit, and the barrier had no such thing.
#
# MEASURED on git 2.50.1, marker hooks over five commit-creating events:
#
# event pre-commit commit-msg
# normal commit yes yes
# --amend yes yes
# --allow-empty yes yes
# merge --no-ff NO yes
# cherry-pick NO NO
#
# So every gate in `tri hooks pre-commit` -- the conflict-marker refusal above all --
# was silent on the one commit type conflict markers actually come from. `git merge`
# runs `pre-merge-commit` instead, and a non-zero exit from it stops the merge: verified,
# HEAD stayed on the pre-merge commit.
#
# The index at this moment holds the merge RESULT, which is exactly the operand
# `tri hooks pre-commit` reads since it was corrected to `--staged`.
#
# cherry-pick runs neither hook and git offers no hook that could stop it. That gap is
# stated in docs/now rather than papered over.
set -euo pipefail
ROOT="$(git rev-parse --show-toplevel)"
cd "$ROOT"

# Newest, not first: a stale binary prints PASSED for gates it does not carry.
TRI_BIN=""
for cand in "$ROOT/target/debug/tri" "$ROOT/target/release/tri"; do
[ -x "$cand" ] || continue
if [ -z "$TRI_BIN" ] || [ "$cand" -nt "$TRI_BIN" ]; then TRI_BIN="$cand"; fi
done
if [ -z "$TRI_BIN" ]; then
echo "note: no tri binary; the merge was not checked and nothing about it is claimed."
exit 0
fi
exec "$TRI_BIN" hooks pre-commit
25 changes: 25 additions & 0 deletions docs/now/2026-09-05-the-barrier-does-not-run-on-merges.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# NOW -- The barrier does not run on merges (2026-09-05)

## The barrier does not run on merges (Refs #3318)

- Measured with marker hooks on git 2.50.1, five commit-creating events: a normal commit,
`--amend` and `--allow-empty` run both `pre-commit` and `commit-msg`;
`merge --no-ff` runs `commit-msg` but NOT `pre-commit`; `cherry-pick` runs neither.
- So every gate in `tri hooks pre-commit` was silent on the one commit type conflict
markers actually come from.
- `git merge` runs `pre-merge-commit`, and a non-zero exit stops the merge. Verified:
HEAD stayed on the pre-merge commit.
- The index at that moment holds the merge RESULT, which is exactly the operand the barrier
reads since it was corrected to `--staged`.
- Controls, both sides: a merge whose result carries a marker exits 1 and does not happen;
a clean merge exits 0 and does.
- `cherry-pick` runs neither hook and git offers none that could stop it. Recorded as a
known gap rather than papered over.
- The class is the POPULATION OF EVENTS, not the predicate and not the operand. Yesterday
it was a push that could be a deletion; today a commit that could be a merge. Both were
found by asking "what else comes through here", and neither by any control.
- Two self-inflicted hazards while measuring, both caught and reverted: `git config` in a
worktree writes to the SHARED config, so setting `core.hooksPath` for a probe disabled
the real hooks in all 148 worktrees; and a `cd` that fails inside a subshell does not
stop it, so a probe ran its commits in my own tree. Nothing was pushed and master was
untouched.
Loading