A git branch naming convention with the ticket number your tracker can parse
Nothing reads your feat/ prefix. The only segment doing work is the issue key, and where it sits decides whether your tracker sees the branch at all. The matching rules, from source.
Most advice about branch naming is taxonomy. feat/ or feature/. Whether
chore earns a place next to refactor. A git branch naming convention with a
ticket number in it usually gets one line near the end, phrased as a
nice-to-have.
That is backwards. Take feature/MS-42-refactor-router. Three segments, and
exactly one has a machine reading it. The prefix is a note to your colleagues,
the slug a reminder to yourself. Only MS-42 does work, and whether it works at
all depends on where you put it.
Nothing parses the prefix
No tracker in this article reads the word feature. None of them branches on
it, sorts by it, or behaves differently because you wrote feat. The tooling
question is narrower: what does the thing on the other end scan, and what shape
does it need?
| Tool | What it scans | Where the identifier must sit |
|---|---|---|
| GitHub closing keywords | The pull request description, or a commit message | Not the branch name; it is not part of the mechanism |
| GitLab | The branch name | At the very start, followed by a hyphen |
| Linear | The branch name, the PR title, the PR description | Anywhere the issue ID appears |
| Kevta | The branch ref, the PR title, the PR body, commit messages | Anywhere, on a word boundary |
Four different answers to the same question, which is why a convention borrowed from someone else's stack produces branches your own tracker ignores.
Where the ticket number has to sit
GitLab is the clearest case, because its documentation states the position
outright: "To streamline the creation of merge requests, start your Git branch
name with the issue or task number, followed by a hyphen. For example, to link a
branch to issue #123, start the branch name with 123-"
(docs.gitlab.com).
The payoff is on the same page: "If the name of the created branch is prefixed
with the issue number, GitLab cross-links the issue and related merge request."
Prefixed with. Not containing. Put a type in front and the number is no longer
the prefix — a request filed against GitLab opens with the line "Prefixed branch
names (e.g. feature/1-add-some-feature) are not being related to GitLab
issues"
(gitlab.com/gitlab-org/gitlab-foss#58147).
On GitLab the conventional name and the linked name are two different names.
GitHub answers differently by not answering. Its linking mechanism is keyword
based: "You can link a pull request to an issue by using a supported keyword in
the pull request's description or in a commit message"
(docs.github.com).
Branch names do not appear in that mechanism at all. The same page adds a
constraint people discover late: if the pull request targets "any other branch"
than the default, "these keywords are ignored, no links are created, and merging
the PR has no effect on the issues." A branch is not shut out entirely — the
same page describes manually linking "a pull request or branch to an issue" from
the issue sidebar, capped at ten issues per pull request — but manual is the
opposite of a convention.
What Closes #42 actually does is its own
argument.
Linear takes the position-free route: "If your branch name includes a Linear
issue ID, Linear will automatically link the pull request to that issue." The
opt-out is not something you do to the branch: you put skip or ignore in
front of the ID in the pull request description
(linear.app/docs/github). It has also let you
change the copied format since 2020
(linear.app/changelog),
which it can afford because the matcher does not care about the format.
The branch naming convention, written as a spec
Five rules. Each one exists because of something above.
- The key is mandatory and the rest is optional. A branch with no identifier is invisible to every row in that table. A branch with no type prefix is merely untidy.
- Put the key where your tracker looks, not where the style guide says. On GitLab that means the number first and no prefix at all. Do not carry a convention across a tool boundary without rereading the rules.
- End the key with a non-alphanumeric character. Every matcher has to
decide where the identifier stops. The hyphen is what makes
MS-42-refactor-routerparse asMS-42rather than as one long token. - Generate the name, do not type it. The failure is always a keystroke —
MS_42,ms42, a digit off by one — and it fails silently. - Keep the identifier stable. A key's value is that it survives renames; anything that regenerates it defeats the point.
What this looks like in Kevta
We build one of the trackers in that table, so read this as the worked example rather than the recommendation.
Copy branch on an issue emits <type>/<KEY>-<slug> —
feature/MS-42-refactor-router. The type comes from the board's default and
falls back to feature; bugfix, chore and hotfix are the alternatives. The
slug is lowercased, stripped of accents, has every non-alphanumeric run
collapsed to a hyphen and is cut at 50 characters — which is why the key sits in
front of it. Truncation can eat the description but never the identifier.
The matcher is a word-boundary-anchored pattern on the board key followed by
alphanumerics, matched case-insensitively. So ms-42 matches, the key can sit
anywhere in the ref rather than at the front, and the capture stops at the first
non-alphanumeric, which is why the -refactor-router tail is ignored. A rule
can scan the branch ref, the PR title, the PR body and commit messages, or be
narrowed to branch only, or to title and body. No magic word, no linking step.
Extracted keys are looked up against that board's issues, so a false positive —
a board key that is also an English word — finds nothing.
The limits, plainly: one board to one repository, the key has to land somewhere the chosen strategy scans, and a branch pushed before the issue existed will not retroactively match. The settings are documented under task keys and branches.
The part a branch name cannot do
A parseable name introduces the branch to the issue. It does not move anything on its own — that takes a rule bound to a git event, a separate decision with its own set of things you should not automate.
But naming is the cheap half, and the half teams get wrong by optimising for the segment nobody reads. Pick the position your tracker needs, generate the string, stop arguing about the prefix.
If you want the version where the issue hands you the branch name and the pull request finds its own way back, join the Kevta waitlist.
- github
- git
- tooling