Full conventions for branches, commits, and pull requests on pbr-cpp-memory-pool. The short version is in AGENTS.md §5; this document expands it with examples and edge-case guidance.
Agents are trusted to:
- Create and switch branches.
- Stage, commit, and push to feature branches.
- Draft pull request titles and bodies.
- Run
gh pr create --draftonly when the user has explicitly authorized PR creation in the current session.
Agents must never:
- Push directly to
master. - Force-push to
masterunder any circumstance. - Merge or squash-merge a pull request (no
gh pr merge, nogit mergeintomaster). - Skip git hooks (
--no-verify) or signing (--no-gpg-sign) unless the user has explicitly asked for it. - Delete branches the user has not asked to delete.
The human reviews and merges. When in doubt, push the branch and ask.
Format:
<type>/<short-kebab-description>
type values:
| Type | Use when… |
|---|---|
feat |
a new user-visible capability is added |
fix |
a defect is corrected |
refactor |
code is restructured without behavior change |
perf |
a change targets measurable performance |
docs |
only documentation is touched |
test |
tests are added or revised, no production code change |
build |
build system, CMake, presets, toolchain |
chore |
tooling, formatting config, repo housekeeping |
ci |
continuous-integration pipeline changes |
Description guidance:
- Lowercase kebab-case, ≤40 characters.
- Describe the what, not the issue number (issue links live in the commit body).
- Avoid generic names like
feat/updateorfix/bug— they age badly.
Examples:
feat/free-list-alloc
feat/cpp-wrapper-raii
fix/destroy-double-free
perf/cacheline-aligned-blocks
docs/adr-thread-safety
build/cmake-presets
ci/valgrind-job
<type>(<scope>): <imperative subject ≤72 chars>
<body — explain WHY, wrap at ~72 cols>
<optional footers>
typematches the branch-type vocabulary above.scopeis a short noun referring to a subsystem:pool,freelist,threading,api,build,tests,bench,docs,adr,ci.- Subject in imperative mood: "add free-list allocation path", not "added free-list allocation path" and not "adds free-list allocation path".
- Body explains motivation, trade-offs, and links to ADRs or spec sections. The diff already shows the what; the commit message must add the why.
- Footers:
BREAKING CHANGE: <description>— any source- or binary-incompatible change.Refs: ADR-0003/Refs: #42— link to ADRs or issues.
Example:
feat(freelist): implement implicit free-list allocation
Store the next-free pointer inside the first bytes of each unallocated
block. This keeps metadata overhead at zero for live blocks and gives
us O(1) alloc and free without an auxiliary bitmap.
The block_size minimum becomes sizeof(void*); enforced in
memory_pool_create() and documented in the public header.
Refs: ADR-0002
One logical change per commit. If a PR contains preparatory refactors and the feature itself, split them: reviewers can then evaluate each independently. Rebase / squash before opening the PR if intermediate commits ("wip", "fix typo") survived.
PR title equals the lead commit subject — same Conventional Commits format, ≤72 characters.
## Summary
One or two sentences: what changes and why it matters.
## Motivation
Link to the spec section, ADR, roadmap item, or issue that prompted this work.
## Changes
- bulleted list of meaningful changes (not a file list)
## Design Patterns
- pattern adopted/refined/rejected, with a one-line rationale and link to the ADR
- (or) None — straightforward implementation.
## Verification
- [ ] Builds cleanly on the full toolchain matrix
- [ ] Unit tests pass
- [ ] `clang-tidy` clean on the diff
- [ ] ASan + UBSan clean (TSan when threading is involved)
- [ ] Valgrind: `ERROR SUMMARY: 0 errors from 0 contexts`
- [ ] Benchmark numbers attached (when perf-relevant)
## Documentation Impact
- [ ] README.md updated (if user-facing surface changed)
- [ ] ROADMAP.md checkbox flipped
- [ ] ADR added/updated (if a non-trivial design decision was made)
- [ ] docs/patterns/README.md updated (if a pattern was introduced, refined, or rejected)
- [ ] Spec updated (if behavior diverges from `docs/specs/`)
- [ ] CHANGELOG.md updated (for user-visible changes; see ADR-0004 §3)The canonical, kept-in-sync version of this template lives in .github/PULL_REQUEST_TEMPLATE.md — GitHub auto-populates new PR bodies from that file.
- Branch off
master:git switch -c feat/<short-name>. - Make changes; commit in logical units.
- Push:
git push -u origin feat/<short-name>. - Prepare the PR body. If the user has authorized it:
gh pr create --draft --title "..." --body "$(cat <<'EOF' ... EOF)". Otherwise, print the proposed command and wait. - Stop. The user opens the PR for review and merges manually.
- Address review comments with new commits on the same branch. Avoid
--amendon commits that are already pushed — create fresh commits instead. - Squash only when the user requests it.
- After merge, the user deletes the branch. Agents do not delete branches.
The repository is configured so that the PR title and PR body become the merge commit's subject and extended description verbatim, regardless of which merge strategy is used:
| Setting | Value | Effect |
|---|---|---|
squash_merge_commit_title |
PR_TITLE |
When "Squash and merge" is picked, the squash commit subject = PR title. |
squash_merge_commit_message |
PR_BODY |
When "Squash and merge" is picked, the squash commit body = full PR description. |
merge_commit_title |
PR_TITLE |
When "Create a merge commit" is picked, the merge commit subject = PR title (not Merge pull request #N). |
merge_commit_message |
PR_BODY |
When "Create a merge commit" is picked, the merge commit body = full PR description. |
Practical consequences:
- Write the PR body as you want it to read in
git log— Summary, Motivation, Changes, Design Patterns, Verification ticks, Documentation Impact ticks. The body is the durable record of the change. - Strip HTML comments and placeholder hints before merging. GitHub's merge dialog lets you edit the pre-filled commit message; do that pass before clicking the green button so the resulting
git logentry reads cleanly. - Preferred strategy is squash-and-merge for one PR = one commit in
master. Use a regular merge commit only when a multi-commit branch is genuinely worth preserving as multiple commits (rare for this repo's scale). - Rebase-and-merge is allowed but discouraged — it bypasses the PR title/body and falls back to the individual commit messages on the branch, which defeats the structured-PR-body approach above.
.gitignorealready excludes build outputs, IDE folders, and CMake artifacts — extend it rather than committing generated files.- Never commit secrets, credentials, or local toolchain paths.
- Large binary fixtures do not belong in this repo; if needed, discuss with the maintainer first.