Register your interest: Tag @Cody, get an agent
BlogResources

Connecting GitHub to Jira: two systems, one source of truth

Both tools think they know whether work is done. Deciding which one is authoritative, why bidirectional sync fails, and what to link rather than copy.

Aymeric ZhuoAymeric Zhuo11 min read

Summarize with AI

Connecting GitHub to Jira: two systems, one source of truth
On this page

Connecting GitHub and Jira usually starts with a reasonable-sounding goal: keep them in sync. That goal is the problem. Both systems hold a notion of what work exists and whether it is finished, and keeping two authoritative systems agreeing is a category of project that does not finish.

The version that works picks one system per question, links rather than copies, and accepts that the two tools are for different audiences — which is why both exist in the first place.

What we'll cover

Why bidirectional sync fails

The models do not match. Jira has configurable workflows and required fields; GitHub issues have labels and a binary state.

Fields have no equivalent. Story points, epics, sprints, components and custom fields have nothing to map onto.

Loops are easy to create. A change in one triggers a change in the other, which triggers the first again.

Conflicts have no natural resolution. Two edits to the same issue in two systems need a rule, and any rule loses somebody's change.

Comments duplicate, producing threads containing both the original and its copy in each system.

The maintenance is permanent, since both tools change their APIs and their models independently of you.

Deciding what each system owns

Jira owns planning: what work exists, its priority, its sprint, who it is assigned to at the planning level, and the workflow state that business stakeholders read.

GitHub owns code: branches, pull requests, reviews, checks, and what actually merged.

One direction of authority per question, which is the whole principle. "Is this done" should have exactly one answer.

Do not create Jira issues from GitHub issues as a general rule, or you have two backlogs.

Pick where engineers work day to day and make the other system reflect it, rather than asking people to update both.

Write it down. The confusion this prevents is between people, not between systems.

Linking rather than copying

A reference is enough. The Jira issue knows which branches and pull requests relate to it; it does not need their content.

Link from the commit or branch name, which requires a convention and costs nothing once it exists.

Show status, do not duplicate it. A Jira issue displaying that two pull requests are open and one is merged is useful; a copied description is not.

Never copy the description, which diverges immediately and then nobody knows which is current.

Copy nothing that can be edited in both places, which is the rule that keeps this maintainable.

A link survives a schema change on either side; a copy does not.

Building it with CodeWords

CodeWords connects to more than 3,000 integrations, so GitHub, Jira and your chat can meet in one automation.

  1. Open CodeWords and start a new automation.
  2. Describe what should happen in plain language to Cody, the automation builder: which events trigger which transitions, and what is linked rather than copied.
  3. Authorize the connections — GitHub and Jira.
  4. Describe the exceptions: a branch with no issue reference, a pull request touching several issues, an issue already closed.
  5. Run it in report-only mode for a week and check which transitions it would have made.

You describe the outcome; Cody builds it, connects it, and deploys it. The free plan covers light use, with Pro at $39 per month and Business at $100 per month as usage grows; details are on the pricing page.

Transitions worth automating

Branch created moves the issue to in progress, which is accurate and saves a click people skip anyway.

Pull request opened moves it to in review, which is the transition stakeholders most often want and engineers most often forget.

Merged moves it to whatever your workflow calls awaiting release or done, depending on whether you deploy on merge.

Deployed is the one worth the most, since "is it live" is the question Jira is usually asked and rarely answers.

Not closed automatically where closing implies verification somebody should do.

Handle the many-to-many case: one pull request touching three issues, and one issue spanning four pull requests, are both normal.

The branch naming convention

The mechanism everything above depends on, and it needs to be cheap or it will not be followed.

Put the issue key in the branch name, which is the simplest reliable link.

Accept it in commit messages and pull request titles too, since people will use whichever they remember.

Be lenient in parsing — case, separators and position should all be tolerated.

Do not block on it. A pull request without a key should warn, not fail, or you have made the tracker a gate on shipping.

Automate the creation of the branch name from the issue, which is the version people actually adopt.

Report the miss rate, since a convention nobody follows is a broken link, not a discipline problem.

What engineers will actually accept

Anything that removes a click they were going to make anyway.

Nothing that asks them to update two systems, which is what the integration exists to prevent.

Not a bot commenting on every pull request with tracker noise, which trains people to ignore pull request comments generally.

Not a required field appearing between them and merging.

Status visible where they already are, rather than requiring a visit to the other tool.

Ask them. The list of things that are actually annoying is short, specific, and different from what a planning tool's documentation assumes.

Reporting across both without merging them

Once the two systems are linked rather than synced, the reporting question returns: somebody wants one view of delivery, and neither tool has it.

Join on the link, not by copying data into one side. The issue key in the branch name is the join key you already have.

Cycle time is the useful measure: issue created to deployed, which spans both systems and is unavailable in either alone.

Separate the waiting from the working. Time in review and time awaiting deployment are different problems from time in development, and only a joined view distinguishes them.

Count what shipped, not what closed, since closed issues and deployed changes diverge in every team that batches releases.

Report unlinked work as its own number, because it is invisible in any joined report and is usually larger than anybody expects.

Build the report outside both tools. Pushing metrics into one system to satisfy reporting is how the copying starts again.

Making it survive

Make transitions idempotent, since webhooks retry and a doubled transition can move an issue past where it should be.

Handle the workflow rejecting a transition, which Jira does when a move is not permitted from the current state, and report it rather than failing silently.

Never loop. An automation acting on its own change is the classic failure here.

Handle deleted branches and closed pull requests without leaving issues stuck in review.

Report the outcome: transitions attempted, made, rejected, and pull requests with no linked issue.

Limits worth knowing about

Jira permissions and workflow rules will block transitions the automation believes are valid.

Required fields on transition are a common cause of a move that fails for reasons the automation cannot resolve.

GitHub and Jira rate limits both apply and both bite on busy repositories.

Jira's own GitHub integration covers some of this, and whether it is enough is worth checking before building anything.

Self-hosted and cloud differ in API surface and in what is available.

What to build first

The branch-name link plus the in-progress and in-review transitions. It is the highest-value part, it removes clicks people were skipping anyway, and it makes the tracker reflect reality without asking anybody to maintain two systems.

Two habits make the difference. Decide which system is authoritative for each question and write it down, since the confusion this prevents is between people rather than between tools. And link rather than copy anything that can be edited in both places, because a copied description diverges within a week and then neither version can be trusted.

Frequently asked questions

Why does bidirectional sync between GitHub and Jira fail?

The data models do not match, several Jira fields have no GitHub equivalent, changes loop, conflicting edits have no natural resolution, and comments duplicate. The maintenance is permanent because both tools evolve independently.

How should the two systems divide responsibility?

Jira owns planning — what work exists, priority, sprint, and the state stakeholders read. GitHub owns code — branches, reviews, checks, and what merged. One authoritative answer per question.

What should be copied between them?

Nothing that can be edited in both places. Link instead: the Jira issue references the branches and pull requests, and displays their status rather than duplicating their content.

Which transitions are worth automating?

Branch created to in progress, pull request opened to in review, merged to done or awaiting release, and deployed — which is the one stakeholders most want and Jira least often answers.

Should closing be automatic?

Not where closing implies a verification somebody should perform. Automating it removes a check rather than a click.

How should issues and branches be linked?

The issue key in the branch name, also accepted in commit messages and pull request titles, parsed leniently. Warn on a missing key rather than blocking, or the tracker becomes a gate on shipping.

What do engineers object to?

Being asked to update two systems, bot comments on every pull request, and required fields between them and merging. Anything that removes a click they were going to make is accepted immediately.

What happens when Jira rejects a transition?

It happens regularly — permissions, workflow rules and required fields all block moves the automation believes are valid. Report the rejection rather than failing silently, or issues sit in the wrong state with no explanation.

How do I report across GitHub and Jira without syncing them?

Join on the link you already have — the issue key in the branch name — and build the report outside both tools. Cycle time from issue created to deployed spans both systems and is unavailable in either alone.

Why report unlinked work separately?

Because it is invisible in any joined view and is usually a larger share than anybody expects. Reporting it as its own number is also the honest measure of whether the naming convention is working.

Is Jira's own GitHub integration enough?

Often, for the linking and the basic transitions. Check what it covers before building anything, since the marginal work is usually the deployment transition and the reporting rather than the link itself.

How do I handle one pull request that closes several issues?

As the normal case rather than an edge case. Both many-to-one and one-to-many are routine, and an automation assuming a single issue per pull request will transition the wrong things regularly.

Get started today

Your first workflow is free to build.

Describe what you need. Cody handles the build, the connections, and the deployment.