Issue→Branch Naming Rules — Prefix, Issue Number, Collisions
If you only tell an agent “open an issue and cut a branch,” you often get random names, missing issue links, or overwrites of an existing branch. Treat branch naming like any other team convention: lock prefix · issue number · collision procedure into Rules and Done criteria.
This post covers three axes only: prefix? · issue number? · collisions? agent-pr-body is PR body text; agent-patch-commits is commit splitting. Here the focus is issue → branch name. No pricing, plans, affiliates, or invented reviews.
Grounded in Git — git-check-ref-format (ref name rules), GitHub Docs — Linking a pull request to an issue, GitHub Docs — Creating a pull request, and common type/issue-slug branch practice.
What prefix should you use?
One-line answer: A prefix is a short token so humans see the change kind at a glance. Fix an allowlist; agents must not invent prefixes outside it.
Common prefixes (public practice/convention; not product pricing):
| Prefix | Meaning | When |
|---|---|---|
feat/ | Feature | New behavior, API, UI |
fix/ | Bug fix | Restore broken behavior |
chore/ | Chore | Deps, config, CI tuning (not a feature) |
docs/ | Docs only | README, guides, doc-only edits |
refactor/ | Behavior-preserving refactor | Structure only |
test/ | Tests only | Coverage, fixtures |
ci/ | CI/CD | Workflows, pipelines |
Format examples (pick one team pattern):
# Pattern A — type + issue + slug
feat/123-add-login-rate-limit
fix/456-null-ptr-on-empty-list
# Pattern B — issue-first (some teams)
123-feat-add-login-rate-limit
# Pattern C — explicit issue word
issue/123-add-login-rate-limit
One line for the agent:
Branch name = <allowed-prefix>/<issue-number>-<kebab-slug>
Allowed prefixes: feat, fix, chore, docs, refactor, test, ci
Slug: lowercase ASCII, hyphens only, max ~50 chars, no spaces.
Do not invent prefixes outside the allowlist.
Do not:
- Mix
Feature/,FIX/, spaces, or heavy underscores → parsers and humans diverge. Default to lowercase + hyphens. - Names that are only
temp/,wip/, oragent/→ issue and kind disappear from review/cleanup. - Bare
just-fixingwith no prefix → weaker search, filters, and automation hooks.
Git ref constraints (git-check-ref-format): avoid spaces, .., control chars, and specials like ~^:?*[\\. Putting # in the branch name is uncommon and awkward in shells/URLs—use digits only for the number segment.
Where does the issue number go?
One-line answer: Put the tracker issue number as digits in the branch name, and use GitHub’s linking keywords in the PR body/commits. Fail Done if the agent invents a nameless “vibes” branch.
| Place | Prefer | Why |
|---|---|---|
| Branch name | feat/123-short-slug | Number shows up in git branch, CI filters, local search |
| PR title | feat: … (#123) or team template | Visible in review/notifications |
| PR body / commits | Fixes #123 / Closes #123 / Resolves #123 | GitHub linking keywords close/link on merge |
| No issue | Explicit exception token e.g. chore/no-issue-bump-deps | Separates “forgot the number” from “intentionally no ticket” |
Copy-paste rule:
If the task cites an issue URL or #N:
1. Extract N as digits only for the branch segment.
2. Never put literal "#" in the branch name.
3. In the PR body, include "Fixes #N" (or Closes/Resolves) when the PR should close it.
If no issue exists:
Stop and ask, OR use the team’s no-issue prefix token — do not invent a fake number.
Note: GitHub closes issues via keywords on PRs that merge into the default branch. A number in the branch name alone does not auto-close. Put PR-body keywords in Done—not “I put the number in the branch, done.”
Multiple issues: put the primary issue in the branch name; list others in the PR body as Related to #A, #B to keep names short and collisions rarer.
What if the name collides?
One-line answer: If the same name already exists locally or on the remote, do not overwrite or force-push. Check existence → decide reuse → append a suffix for a new name.
Typical collision cases:
| Situation | Symptom | Agent action |
|---|---|---|
| Local same name | Already on git branch / checkout -b fails | Same issue → reuse/rebase per policy. Other work → new name |
| Remote same name | git ls-remote --heads origin <name> hits | May be someone else’s WIP → new name or ask a human. No -f push |
| Slug clash only | feat/123-login vs fix/123-login | Different prefixes OK if team allows. Same type+number → change slug/suffix |
| Concurrent agents | Two sessions create for the same issue | feat/123-slug-<short-id> or -2. Whether to merge into one PR is a human call |
Check order (copy-paste):
Before creating a branch named NAME:
[ ] git show-ref --verify --quiet refs/heads/NAME
[ ] git ls-remote --heads origin NAME
If either exists:
- Same issue + abandoned → ask human before reset
- Same issue + active → checkout existing; do not recreate
- Different work or unclear → use NAME-2 or NAME-<yyyymmdd> or NAME-<agent-short>
Never: git push --force to “win” a name collision
Never: delete someone else’s remote branch to free the name
Suffix examples:
feat/123-add-login-rate-limit
feat/123-add-login-rate-limit-2
feat/123-add-login-rate-limit-20260924
One-line wrap-up: Build allowed prefix + issue digits + kebab slug; on collision reuse or suffix—never steal the name with force.
FAQ
Can the branch include #123?
It can, but shells/URLs/tools often need escaping. Prefer digits 123 in the branch; keep #123 for PR/commit text.
Should Conventional Commit types match branch prefixes?
Matching helps search (feat/ branch → feat: commit). Not required, but a Rule like “branch prefix = commit type” keeps agents consistent. See agent-patch-commits for commit splitting.
Hotfix with no issue?
Allow only the team’s exception (hotfix/ + timestamp, or chore/no-issue-…). Ban inventing fake issue numbers. Prefer opening an issue first, then the branch.
What if the agent commits straight on main?
That bypasses issue→branch rules. Add Done: “work branch ≠ default branch.”
Sources
- Git — git-check-ref-format — ref name constraints
- GitHub Docs — Linking a pull request to an issue —
Fixes/Closes/Resolves - GitHub Docs — Creating a pull request — PR/branch flow
- Adjacent: agent-pr-body (PR body), agent-patch-commits (commit units), agent-deny-paths (path deny)