← The ADLC library
Field guides · 1

Linking Jira work to code, reliably

How Jira's development panel actually gets filled in, the handful of ways the link silently fails, and how to get linking rate close to 100 percent without adding ceremony.

You open a Jira issue that shipped last week and the development section is empty. No branch, no commit, no pull request. The issue is closed, the sprint report is green, and there is no way to answer the only question anyone actually asked, which is what code went with it.

This is not a Jira bug. Jira is doing exactly what it was told. The link is built out of text that humans type, and humans do not type it consistently. Here is how the mechanism really works and how to get it close to reliable.

Jira does not scan your repositories

Jira does not scan your repositories. Your source control tool pushes development information into Jira through a connected app or integration, and Jira attaches that information to an issue when it finds an issue key in the text.

The issue key is the whole mechanism. It is the project prefix, a hyphen, and a number, and it has to appear literally in something the integration reads. In practice that is three places:

  • The branch name. Detected when the branch is created and pushed.
  • The commit message. Detected per commit as commits land.
  • The pull request title, and usually the description. Which of those two is read varies between the Atlassian-supplied integrations and between Cloud and Data Center, so verify it against your own instance rather than assuming.

Get the key into any one of those and the issue picks up the link. Get it into all three and the link survives most of the ways history gets rewritten later.

On top of that base, Jira gives you three things worth using:

Commit-message commands. Atlassian calls these smart commits. Text in a commit message can add a comment, log time, or transition the issue. Which commands are available, and whether they are enabled at all, depends on the integration and how it was configured, so check what your instance actually accepts before you write it into a team convention.

Automation on development events. Jira Cloud’s automation can trigger on development activity: a branch appearing, a commit landing, a pull request opening or merging. The trigger names and the exact set available vary by product and version. The pattern that earns its keep is the one that moves an issue into review when a pull request opens against it, because it removes the most commonly forgotten manual status change in the whole workflow.

Development state in filters. Jira can filter issues by their development status, so you can build a board or a saved filter for issues that are in progress with no branch, or closed with no merged pull request. The field syntax for this differs between versions and it is not the same in every deployment, so look it up in your own instance’s field reference rather than copying a query from a blog post.

Those three, configured once, cover most teams.

A missing key produces no error anywhere

The failure mode that matters is that a missing key produces no error anywhere. Nothing turns red. The developer sees a normal pull request, the reviewer sees a normal pull request, and the issue quietly has nothing attached to it forever.

Six specific ways it goes wrong:

Squash merges eat the keys. If the key lived only in individual commit messages and your team squashes, the resulting commit on the trunk carries whatever the merge UI generated, which is usually derived from the pull request title. If the title has no key, the trunk has no key.

Bots never comply. Dependency update branches, automated formatting, generated client updates. These are real merged changes with no issue behind them and no key in the name. They set a permanent ceiling on your linking rate that is not a discipline problem.

Case and format drift. Jira keys are uppercase. Git branch names are case sensitive and people type lowercase. Whether the integration matches case-insensitively depends on the integration, so test both spellings in a scratch branch before you trust either.

Typos land on the wrong issue. A transposed digit still matches the key pattern, so it links, just to a different issue. This is worse than no link, because it looks correct.

Cross-project work. One change that serves two teams gets one key, and the other project’s issue never sees the code.

Unconnected repositories. A repo nobody wired into the integration produces zero links no matter how disciplined the branch names are, and there is no dashboard that tells you a repo is missing.

What the empty panel looks like

  • Issue closed, no development information
  • Nobody notices until an audit or an incident
  • Blamed on developer discipline

What it usually is

  • Key only in commits, then squashed away
  • Repository never connected to the integration
  • Bot branches counted in the denominator
Three of these are configuration, one is arithmetic, and none of them are fixed by asking people to try harder.

Measure first, because you cannot state your number

Measure first, because you almost certainly cannot state your current number. From a checkout of each active repository:

git log --format='%s' origin/main --since='90 days ago' | wc -l
git log --format='%s' origin/main --since='90 days ago' \
  | grep -cE '[A-Z][A-Z0-9]+-[0-9]+'

Two numbers, one ratio, per repository. Run it before you change anything. If the ratio is 0.9 you have a rounding problem; if it is 0.4 you have a structural one, and they need different responses.

Then make the compliant path the lazy path. Two conventions do most of the work:

  1. Create the branch from the Jira issue rather than from the terminal. Every mainstream integration offers this, and a branch created that way carries a correct key by construction. This single habit is worth more than any amount of policy.
  2. Require the key in the pull request title, not just in commits. The title survives squash. Commits do not.

Then enforce cheaply. A commit-msg hook catches it locally but is optional by nature, since hooks are not distributed with the repository and anyone can skip them. The check that actually holds is a required status check in CI that fails when neither the branch name nor the pull request title matches the key pattern, with an explicit allowlist for your bot accounts so the automation does not fight itself. Ten lines of regex, one required check, and the failure is now loud and immediate rather than discovered a quarter later.

Then automate the status change, so that the link has a payoff developers can feel: an issue that moves itself into review is an issue nobody has to remember to drag.

If you run one Jira project against a handful of repositories, stop here. The native path genuinely covers it.

The point at which it stops covering it is scale and heterogeneity: dozens of repositories, more than one source control host, and a leadership question that spans all of them. Then linking rate becomes something you have to compute and defend rather than glance at, and that reporting layer is what our own product, GroundTruth, exists to be. It syncs with Jira in both directions and reads GitHub, GitLab and Bitbucket. I have a commercial interest in you needing it, so discount accordingly and go run the two git commands above first.

Where this breaks down

100 percent is the wrong target. Bot merges, revert commits and emergency fixes will never carry keys, and chasing the last few points produces theatre. Pick a floor, exclude your bots from the denominator explicitly, and defend the floor.

Enforcement moves the problem rather than solving it. Make the check mandatory and you will get a placeholder issue created to satisfy it. That is a real cost, and the honest mitigation is to make issue creation fast enough that the placeholder is a real issue.

The link tells you nothing about correctness. A pull request attached to an issue is evidence that someone typed a key, not evidence the change does what the issue asked. Linking rate is a hygiene metric, not a quality one, and presenting it as the latter will get you caught.

Some teams genuinely should not do this. If work arrives as a continuous stream of small changes with no ticket at all, forcing a key onto every branch is inventing bureaucracy to satisfy a report nobody reads.

The takeaway

Jira’s development panel is a text-matching system with no error state. It works well when the key is placed where history cannot lose it, which is the branch name and the pull request title, and it fails invisibly otherwise.

If you take one thing into next week: run those two git commands against your three busiest repositories and put the ratios in front of your leads. The number itself is less interesting than the fact that nobody in the room could guess it.