mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-08-06 04:21:33 +00:00
chore(githooks): add commit-msg hook for 80-column messages
Long commit subjects and bullets are hard to read in narrow terminals and mailed logs. Contributors using `.githooks` via core.hooksPath now get an automatic guard in addition to the two-file pre-commit cap. - Add `.githooks/commit-msg` to fail when any message line exceeds 80 chars - Skip length checks while `.git/MERGE_HEAD` exists for merge commits - Sync AGENTS.md, README.md, CONTRIBUTING.md, and commit.prompt.md
This commit is contained in:
Executable
+32
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
# Reject commit messages with any line longer than 80 characters.
|
||||
# Enable with: git config core.hooksPath .githooks
|
||||
#
|
||||
# Merge commits often carry Git-generated "Merge branch …" lines that can
|
||||
# exceed 80 columns when branch or remote names are long; skip the check then.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
msg_file=${1:?commit-msg hook requires path to message file}
|
||||
|
||||
if [[ -f .git/MERGE_HEAD ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
lineno=0
|
||||
while IFS= read -r line || [[ -n "${line}" ]]; do
|
||||
lineno=$((lineno + 1))
|
||||
len=${#line}
|
||||
if ((len > 80)); then
|
||||
echo "❌ COMMIT MESSAGE: line ${lineno} is ${len} chars (max 80)"
|
||||
echo ""
|
||||
echo "Wrap the subject, summary, and bullets to 80 columns or fewer."
|
||||
echo "See .github/prompts/commit.prompt.md"
|
||||
echo ""
|
||||
echo "Offending line (truncated for display):"
|
||||
printf '%s\n' "${line}" | cut -c1-120
|
||||
exit 1
|
||||
fi
|
||||
done <"${msg_file}"
|
||||
|
||||
exit 0
|
||||
@@ -38,9 +38,17 @@ git add path/a.jl path/b.jl
|
||||
- Avoid `git add .` and `git add -A` unless the user explicitly wants everything (still read the full staged diff after).
|
||||
- Never stage unrelated changes into the same commit.
|
||||
|
||||
## Optional git hook (max two staged paths)
|
||||
## Optional git hooks (`.githooks/`)
|
||||
|
||||
The repo ships `.githooks/pre-commit`. After `git config core.hooksPath .githooks`, commits with **more than two** staged files are rejected. This supports the common “impl + test” or “snippet + verifier” pair without allowing large batches. Split bigger changes across commits or adjust the hook deliberately.
|
||||
After `git config core.hooksPath .githooks`:
|
||||
|
||||
- **pre-commit:** rejects commits with **more than two** staged files. This
|
||||
supports the common “impl + test” or “snippet + verifier” pair without
|
||||
allowing large batches. Split bigger changes across commits or adjust the
|
||||
hook deliberately.
|
||||
- **commit-msg:** rejects the commit if **any** message line is longer than
|
||||
**80 characters** (including the subject). Wrap prose and bullets; merge
|
||||
commits skip this check while `.git/MERGE_HEAD` is present.
|
||||
|
||||
## Read the full staged diff
|
||||
|
||||
@@ -94,17 +102,24 @@ EOF
|
||||
|
||||
Use `-` bullet lists; omit sections that do not apply.
|
||||
|
||||
### Line length (enforced when hooks are enabled)
|
||||
|
||||
Keep **every** line at **80 characters or fewer**, including the subject and
|
||||
each bullet. This keeps `git log` readable in terminals and mail archives. If
|
||||
the hook is enabled, overlong lines cause the commit to fail—rewrap before
|
||||
retrying.
|
||||
|
||||
### Example (single file)
|
||||
|
||||
```
|
||||
refactor(basis): Replace per-element lagrange includes with generator entrypoints
|
||||
refactor(basis): fold lagrange includes behind generator entrypoints
|
||||
|
||||
The basis tree previously listed seven separate lagrange_*.jl includes; they are
|
||||
folded behind lagrange_generator.jl and lagrange_generated.jl so new elements
|
||||
register in one place.
|
||||
The basis tree listed seven separate lagrange_*.jl includes; they now load
|
||||
through lagrange_generator.jl and lagrange_generated.jl so registration lives
|
||||
in one place.
|
||||
|
||||
- Drop redundant includes from JuliaFEM.jl
|
||||
- Document the 'Basis' suffix convention in the include comment
|
||||
- Note the Basis suffix convention in the include comment
|
||||
```
|
||||
|
||||
### Example (multi-file — requires justification to user)
|
||||
@@ -160,6 +175,7 @@ Never use `git diff --staged | head` (etc.). Read the full diff.
|
||||
- [ ] If `.githooks` is active: are there **at most two** staged paths?
|
||||
- [ ] Did I read the **full** `git diff --staged`?
|
||||
- [ ] Subject line: Conventional Commits, specific, matches diff?
|
||||
- [ ] Is **every** message line (subject, summary, bullets) **≤ 80 characters**?
|
||||
- [ ] Body: blank line, then **1–3 sentence** summary, then **bullets scaled to diff size** (rich, grouped bullets for large / multi-concern commits)?
|
||||
- [ ] Did I **propose** the commit and wait for **approval** before `git commit`?
|
||||
|
||||
|
||||
@@ -205,8 +205,10 @@ These are non-negotiable. Tests and code analysis enforce them.
|
||||
## 5. Critical workflow rules
|
||||
|
||||
Contributor-facing workflow text lives in `.github/prompts/commit.prompt.md`
|
||||
and `.github/copilot-instructions.md`. Optional `.githooks/pre-commit`
|
||||
(enabling `core.hooksPath`) caps staged paths at two per commit.
|
||||
and `.github/copilot-instructions.md`. Optional `.githooks/` hooks (enable with
|
||||
`git config core.hooksPath .githooks`): **pre-commit** caps staged paths at
|
||||
two per commit; **commit-msg** rejects any log line longer than **80
|
||||
characters** (merge commits skip that check while `.git/MERGE_HEAD` exists).
|
||||
Editor-local Cursor rules under `.cursor/` are not part of the git tree.
|
||||
|
||||
- Commits: prefer **small** steps (default one file per commit). Combine
|
||||
@@ -215,8 +217,8 @@ Editor-local Cursor rules under `.cursor/` are not part of the git tree.
|
||||
deliberately. Read the **full** staged diff (no `head`/`tail`). Message
|
||||
format: Conventional Commits **subject**, blank line, **1–3 sentence**
|
||||
summary, then bullets **scaled to the patch** (small change → few or none;
|
||||
large / multi-concern → grouped, substantive bullets). **Propose** paths + full message
|
||||
and wait for **explicit approval** before each `git commit`. See
|
||||
large / multi-concern → grouped, substantive bullets). **Propose** paths and
|
||||
full message and wait for **explicit approval** before each `git commit`. See
|
||||
`.github/prompts/commit.prompt.md` for the full protocol.
|
||||
- **AI agents: commits are not a loop variable.** Never drive `git commit` from a
|
||||
shell or Python loop that stages paths and emits placeholder subjects such as
|
||||
@@ -225,7 +227,9 @@ Editor-local Cursor rules under `.cursor/` are not part of the git tree.
|
||||
`head`, `tail`, `less`, or other truncation when forming the message). The
|
||||
subject and body must describe the **actual** API and behaviour changes in
|
||||
those hunks; the optional two-path `.githooks/pre-commit` rule limits batch
|
||||
size, it does **not** replace reading the diff. If many low-quality commits
|
||||
size, it does **not** replace reading the diff. Keep every commit message line
|
||||
at 80 columns or fewer when hooks are enabled (see **commit-msg**). If many
|
||||
low-quality commits
|
||||
already exist locally, repair with `git reset --soft <good_base>` and rebuild
|
||||
following this file and `.github/prompts/commit.prompt.md`, or use
|
||||
`git rebase -i` to reword; do not apply a second scripted sweep of generic
|
||||
|
||||
@@ -85,9 +85,11 @@ what you changed.
|
||||
|
||||
**Git commits.** Keep history easy to read: small commits, usually one file;
|
||||
**two files** in one commit is fine when they are inseparable (e.g. a helper and
|
||||
its only caller). An optional hook (`.githooks/`, set `core.hooksPath`) caps
|
||||
staged paths at two. If that workflow feels unfamiliar, open your PR with tests
|
||||
passing and ask for help splitting history in review.
|
||||
its only caller). With `.githooks/` and `core.hooksPath`, **pre-commit** caps
|
||||
staged paths at two and **commit-msg** rejects log lines longer than **80
|
||||
characters** (wrap subject, summary, and bullets). If that workflow feels
|
||||
unfamiliar, open your PR with tests passing and ask for help splitting history
|
||||
in review.
|
||||
|
||||
**Code expectations.** Assembly hot paths must stay type-stable and allocation-free
|
||||
after warmup; CI and [`test/assemblers/test_dof_based_zero_alloc.jl`](test/assemblers/test_dof_based_zero_alloc.jl)
|
||||
|
||||
@@ -64,8 +64,10 @@ when rendering the website) rather than chasing false positives in the library.
|
||||
(e.g. implementation + its test). Never `git add .` or `git add -A`
|
||||
unless you mean it. The full protocol is in
|
||||
`.github/prompts/commit.prompt.md`. With
|
||||
`git config core.hooksPath .githooks`, the pre-commit hook allows at
|
||||
most **two** staged files per commit.
|
||||
`git config core.hooksPath .githooks`, **pre-commit** allows at most **two**
|
||||
staged files per commit, and **commit-msg** rejects messages with any line
|
||||
longer than **80 characters** (merge commits skip the length check while
|
||||
`.git/MERGE_HEAD` exists).
|
||||
- Match **commit message depth** to the patch: a short summary suffices for
|
||||
small edits; **large files, large diffs, or several concerns in one commit**
|
||||
should add **grouped bullets** (major API or behavior, wiring, migrations,
|
||||
|
||||
Reference in New Issue
Block a user