Linking Linear work to code, reliably
Linear's git integration is the best-designed one on the market and it still leaks. Here is exactly how the branch-name link works, the four ways it breaks, and what to do about each.
Your board says an issue is in review. There is no pull request against it. Somebody moved it by hand three days ago, or an automation moved it on a branch that has since been abandoned, and now the state of the board and the state of the code disagree by an unknown amount.
Linear’s git integration is genuinely the best of the ones I have worked with, and it gets you further out of the box than anything else in this category. It is also the one where teams most often assume the automation is complete, because most of the time it is, and the exceptions are quiet.
It all rests on the issue identifier
The mechanism rests on the issue identifier: a team key, a hyphen, a number. That string is short, human-typable and unique in the workspace, which is why the whole integration can hang off it.
The branch name is the primary link. Linear will give you a ready-made branch name for an issue, containing the identifier, usually with a slug of the title. Copy it, cut the branch from it, push, and the link forms on its own. No keyword, no description, nothing to remember. This is the mechanism to standardise on, because it happens at the moment the work starts, before there is anything to forget.
Pull request title and description also carry it. An identifier in either will link the pull request to the issue. Useful as a recovery path when the branch was already cut with the wrong name.
Status moves automatically. With source control connected, Linear can advance an issue when a pull request opens, when it is ready for review, and when it merges, and it can hand back a different state when a pull request is closed unmerged. Which states these map to is configured per team, so two teams in the same workspace can behave differently, and frequently do. Check the workflow configuration for the specific team before you conclude the integration is broken.
Pull request status appears on the issue. Review state, checks, merge state, visible without leaving the issue. This is the part that makes developers actually maintain the link, because it saves them a context switch rather than costing them one.
The API is GraphQL and will give you, per issue, its attachments and linked pull requests, which is what you build a linking report on rather than scraping text. Find the current field names in the schema explorer rather than in someone’s blog post, since the schema moves.
Work that starts in a terminal
Work that starts in a terminal. Someone cuts fix-login-redirect at nine in the morning because they are annoyed, and no amount of integration quality recovers that. Every failure below is a variation of this one.
The identifier changes when an issue moves teams. The identifier embeds the team key, so an issue that moves between teams does not keep its old string. The application handles the redirect for a human clicking a link. A branch name pushed last month is fixed text in git and will not follow. Verify the exact behaviour in your own workspace before you build reporting that assumes identifiers are permanent.
Automatic transitions describe the pull request, not the work. An issue moves to review when a pull request opens. A draft pull request opened to run CI on a spike will move an issue that nobody is reviewing. The transition is honest about what it observed; it is your reading of it that is wrong.
Multi-issue and multi-repository changes. One pull request touching three issues, or one issue needing changes in four repositories, both leave the one-to-one model. The link still exists; the status derivation stops making sense, because merging one of four pull requests is not done.
Work that has no issue. Bot updates, dependency bumps, small fixes people do not ticket. These will never link, and they are not a discipline failure.
Measure the gap in one direction only
Measure the gap first, in one direction only. Do not start with “how many pull requests have issues”, start with the direction that hurts: how many issues completed in the last month have no linked pull request. Query the API for issues that reached a done state in a date range, and check each for a pull request attachment. Issues that closed with no code attached are either work that was not code, work someone did off-branch, or work that did not happen. All three are worth knowing about and only the first is fine.
Then, in order of cost:
- Make copying the branch name the documented first action. Not an option in a wiki page, the first line of your definition of ready. It costs a keyboard shortcut and eliminates the dominant failure mode.
- Add a local
commit-msgorpre-pushhook that warns when the branch name contains no identifier. Hooks are per developer and skippable by design, so treat this as a helpful nudge rather than a control. - Add a CI check on protected branches that fails when neither the branch name nor the pull request title contains an identifier, with your bot accounts allowlisted and an explicit label for genuine exceptions. This is the only one of these that holds under pressure.
- Review the per-team workflow mapping once a quarter. Teams drift, someone renames a state, and an automation that used to move issues into review silently stops mapping to anything. Nothing announces this.
Do those four and you are done. There is no gap here that needs a purchase, and if your board still disagrees with your code after that, the problem is that people are dragging cards, not that the integration is insufficient.
Where this breaks down
Automatic status makes the board reflect git, not reality. That is usually an improvement, and it is not free. An issue sitting in review because of a stale draft pull request is a new class of wrong, and it looks exactly like a real one.
A CI check is a blunt instrument on a fast team. Linear is popular precisely with teams that value speed, and a blocking check on every merge is a tax on the thing they optimised for. If your merge volume is high and your incident rate is low, a weekly report on unlinked merges may be the better trade.
The one-directional measurement can be gamed. Once people know that closed-with-no-code is the number you watch, issues will stop being closed rather than start being linked. Watch for a growing pile of stale in-progress issues after you introduce it.
Linked is not verified. An issue with a merged pull request against it proves someone put an identifier in a branch name. Whether the change satisfies what the issue described is a question no integration answers.
The takeaway
Linear’s link is created at the moment work starts, which is the correct place, and that is why the integration works as well as it does. Everything that goes wrong afterwards traces back to work that started somewhere else.
If you take one thing into next week: list every issue your team completed last month with no pull request attached, and go through the list in your retro. It is a short list and it will tell you more about how your team works than the cycle-time chart will.