Skip to content
oss-kit
Install

oss-writing: Commits and change requests

The durable body defaults to none. The subject carries the change, and most changes end there.

Prose earns its place when it carries one of four things. The reason the behavior exists, the constraint that forced an unobvious choice, the alternative rejected and why, or the compatibility, security, or operational consequence. A body that paraphrases the diff is noise.

A body is earned when a change’s safety rests on a fact the diff cannot show, and diff size does not decide that.

A body that exists says what is wrong now, what this change does about it, why this way, and what was discarded, in that order. Answer each problem in the same breath as you raise it. The count of fix statements is the count of problems, not the count of files the change touches.

Write the problem clause in the present tense: the date picker shows the wrong month, not the date picker used to show the wrong month. The commit is what turns that sentence into history. Write the fix in the imperative: show the selected month, not this patch makes the date picker show the selected month.

A body that has to describe more than one change is the signal the commit should have been split. Split the commit, never the description of what landed.

Structure: Conventional Commits. Content: git SubmittingPatches.

  • Follow the subject convention the repository declares. Where that is Conventional Commits, the specification carries the type list and the breaking-change marker; do not recite either from memory.
  • Keep the subject to 72 characters or fewer, counting any number the forge appends on squash.
  • Explain motivation in the body, not the subject.
  • The body explains WHY the change is needed and HOW it differs from the prior behavior. Do not restate the diff.
  • State discarded alternatives when they help a future reader.
  • Keep it self-contained.
fix(parser): handle empty input
perf(search): cache results per normalized query
Results are recomputed on every keystroke, which pins a CPU core during peak hours. Caching for 5 minutes drops p99 from 1.4s to 210ms and costs 40 MB of resident memory.
Redis was rejected. A deploy clears the in-process cache, which is acceptable at one replica. The operational dependency is not worth it until we scale out.

A branch is <type>/<kebab-topic>, where the type is the same one the commits on it use. feat/forge-detection-controls, fix/site-omit-unreleased, docs/readme-structure. A release branch is chore/release-X.Y.Z.

  • The type has to match the commits, and the change request title has to match both. A ci: title on a chore/ branch is three names for one change and a reader has to open the diff to learn which is right.
  • One branch, one type. A branch whose commits span types is two changes, so split it rather than picking whichever type the first commit happened to use.
  • Follow the convention the repository declares where it declares one. This is the default where it does not, because it is the same vocabulary the commits already carry, so there is nothing extra to learn.

A change request is a GitHub pull request or a GitLab merge request.

  • Follow the convention the repository declares.
  • Use the repository’s template when it ships one, such as pull_request_template.md or .gitlab/merge_request_templates/.
  • A description is rendered on the forge and read before the diff. Use the markup the forge renders.
  • Give a change with separable parts one bullet each. A reviewer reads that list to decide where to start.
  • The default-to-silence rule above governs a commit body. A description earns its length from what review needs.