mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 02:54:26 +00:00
git writes MERGE_HEAD only after the pre-merge-commit hook returns, so the gate never found it and aborted every non-fast-forward merge with "No merge in progress"; git then wrote the merge state via abort_commit(), leaving a half-finished merge that git status reported as "still merging". The gate had therefore never verified a single signature. git also skips pre-merge-commit entirely once a merge conflicts, so the conflict-resolution commit was unguarded as well. prepare-commit-msg fires with MERGE_HEAD present on both paths and no-ops on ordinary commits. Verified in a scratch repo with a real pre-commit install: ordinary commit passes silently, clean automerge and conflict-resolution commit both block an unsigned incoming commit, and the extra stash/restore cycle round-trips unstaged changes byte-identically. pre_commit install never removes hook types dropped from the config, so the install script now also uninstalls the stale pre-merge-commit hook.
23 lines
773 B
Bash
Executable File
23 lines
773 B
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# Merge gate: every commit the merge brings in (HEAD..MERGE_HEAD) must carry
|
|
# a signature. `git log %G?` yields N for unsigned; any other status counts
|
|
# as signed, matching the test-signed HEAD gate.
|
|
|
|
git_dir="$(git rev-parse --git-dir)"
|
|
if [ ! -f "${git_dir}/MERGE_HEAD" ]; then
|
|
exit 0
|
|
fi
|
|
|
|
unsigned="$(git log --pretty='%H %G? %s' HEAD..MERGE_HEAD | awk '$2 == "N"')"
|
|
if [ -n "${unsigned}" ]; then
|
|
echo "❌ Unsigned commit(s) coming in from the merged branch:" >&2
|
|
printf '%s\n' "${unsigned}" >&2
|
|
echo "Sign them (git rebase --exec 'git commit --amend --no-edit -S' or git-sign-push) and retry the merge." >&2
|
|
exit 1
|
|
fi
|
|
|
|
count="$(git rev-list --count HEAD..MERGE_HEAD)"
|
|
echo "✅ All ${count} incoming commit(s) are signed."
|