Skip to content

Branches and pull requests

How SpecsGraph names proposal branches, opens pull requests or commits directly, writes commit messages, handles conflicts and works with branch protection.

One branch per proposal

Every proposal has a branch under spec/, named from its title, such as spec/checkout-reserve for "Checkout reserves stock before payment". The name shows on the proposal while it is still open, and you can shorten it before approval. If the name is taken, SpecsGraph adds a number.

Nothing is pushed to GitHub before a person approves. On approval, SpecsGraph creates the branch from the tip of the base branch, commits the change inside the spec folder and, by default, opens a pull request. Each branch holds one proposal, so each pull request can be reviewed and merged on its own.

Warning

Leave spec/ branches to SpecsGraph

SpecsGraph may rewrite a proposal branch when it rebases it, so commits pushed there by hand can be lost. Put code changes on your own branch and link the spec pull request from it.

Publish mode

Each project has a Publish mode setting that decides how approved changes reach the base branch. An Admin or Owner changes it in the project settings.

ModeWhat happens on approvalUse it when
Pull request (default)SpecsGraph pushes the proposal branch and opens a pull request to the base branch. The spec reaches main when you merge it.Your base branch is protected, or you want CI and a GitHub review on every spec change.
Direct commitSpecsGraph commits straight to the base branch. No branch is pushed and no pull request is opened; the branch name stays on the proposal and in the commit message. The proposal is Published as soon as the commit lands.A small team without branch protection that treats SpecsGraph approval as the only review.

Direct commit fails on a protected base branch. The proposal then stays Approved with the error from GitHub, and you can switch the project back to Pull request and choose Retry publish.

What the pull request contains

The pull request is titled after the proposal. Its description lists the nodes it changes, grouped by context, and links back to the proposal in SpecsGraph with its review threads and approver. It changes files inside the spec folder only; for spec/checkout-reserve that is three requirement files, the decision file, the WS-3 workstream file, README.md and graph.json.

Commit message format

Each publish is one commit, authored by your GitHub App's bot account, such as specsgraph-northwind[bot]. The subject starts with spec: and the proposal title. The body lists what changed, and trailers name the proposal and the approver. The person whose token an agent used appears as a co-author, so GitHub credits them.

Commit messageText
spec: Checkout reserves stock before payment

Orders
  + ORD-12 Reserve stock for every line item at checkout
  + ORD-13 Release reservations after 15 minutes idle
Billing
  + BIL-04 Capture payment only once stock is reserved
Decisions
  + 0007 Reserve stock before payment
Workstreams
  ~ WS-3 Reserve stock at checkout

Spec-Proposal: spec/checkout-reserve
Spec-Approved-By: Kofi <kofi@northwind.example>
Co-authored-by: Ana <ana@northwind.example>

Lines start with + for an added node, ~ for a changed one and - for a retired one. Search for spec commits with git log --grep "Spec-Proposal:".

After the pull request

A proposal stays Approved while its pull request is open, and the pull request follows your repository's rules. Merging it marks the proposal Published, and from that moment the graph shows the change as the current revision, as described in How the spec workflow works.

  • Merged. The proposal becomes Published and shows the merge commit. Squash, merge commit and rebase merges all work. With a squash merge the base branch keeps one commit per proposal.
  • Closed without merging. The proposal stays Approved and shows a warning; the base branch and the current revision are unchanged. Reopen the pull request, or choose Retry publish to open a new one. To drop the change instead, an Editor or above withdraws the proposal.
  • Branch cleanup. Delete merged spec branches as you would any other. GitHub's setting to delete head branches automatically works for them too.

Conflicts and rebasing

Spec branches only touch the spec folder, so they never conflict with code. They can conflict with each other, because every publish updates shared files such as the index and the graph data.

  1. Two proposals are approved

    spec/checkout-reserve and a Catalog proposal are both approved on the same morning. Both branches start from the same commit on main, and both change README.md and graph.json.

  2. One merges first

    The Catalog pull request merges. GitHub sends a push event for main.

  3. SpecsGraph rebases the other

    SpecsGraph rebases spec/checkout-reserve onto the new main, writes the generated files again from the graph and updates the pull request. Nobody resolves the conflict by hand.

SpecsGraph stops instead of rebasing when a file it needs to write was changed on the base branch outside SpecsGraph. The proposal shows the files involved. Move the hand edit into a proposal, or revert it in Git, then choose Retry publish. The guard in Spec files in your repository keeps this from happening, and Troubleshooting lists other reasons a proposal stays Approved.

Branch protection and required checks

Spec pull requests follow the same rules as every other pull request. Required reviews and required status checks apply to them, and SpecsGraph does not bypass either.

  • Required checks. Your CI runs on spec pull requests like any other. The App has no checks permission, so it adds no status checks of its own. Workflows that validate the spec folder are yours to add.
  • Required reviews. SpecsGraph approval and GitHub review are separate. Some teams keep the GitHub review light, since the content was reviewed in SpecsGraph by an Editor or above. Others route spec changes to named reviewers with a code owners file.
  • Up-to-date branches. If you require branches to be current with the base branch, the rebase described above keeps spec pull requests mergeable.
  • Rulesets that restrict branch names. Allow spec/* for the App, or proposal branches cannot be created.
.github/CODEOWNERSText
# Every spec change goes to the architecture group
/specsgraph/  @northwind/architecture

# Orders spec changes go to the Checkout team as well
/specsgraph/contexts/orders/  @northwind/architecture @northwind/checkout

GitHub asks the owners of each changed file for a review, and with code owner review required in branch protection, one of them must approve. The last matching pattern wins, which is why the Orders line repeats the architecture group.

Next steps