Update an issue's status on pull request merge, and which git events to leave alone
Update an issue's status on pull request merge and you have done the easy half. Which git events are worth binding to a state, which are not, and the guard that stops rules dragging work backwards.
The pull request merged on Tuesday. On Friday somebody drags the card to Done, because there is a call on Monday and the board is embarrassing.
Nothing was discovered in that action. Updating an issue's status on pull request merge is a second copy of a fact the repository already recorded, made by hand, three days late. That holds for most of the status field on any board with code behind it: the state is knowable from git, so typing it again does not keep the two in sync. It guarantees drift.
So the question is not whether to bind git events to statuses. It is which ones. This assumes the matching half is solved already — a duller problem, covered in what linking a pull request to an issue actually does and branch names your tracker can parse.
Update an issue's status on pull request merge
Merge is the settled case, and the tools that have an answer agree on it.
GitHub Projects ships two built-in automations enabled by default and both write the same value: "When issues or pull requests in your project are closed, their status is set to Done" and "When pull requests in your project are merged, their status is set to Done" (docs.github.com). Linear states its defaults outright: "By default, we will move linked issues to 'In Progress' when PRs are open and 'Done' when PRs merge" (linear.app/docs/github). Jira ships no default rule, but once a source-code management tool is connected it exposes a "Pull request merged" trigger to build one from — "The flow executes when a pull request is merged" (support.atlassian.com).
The detail worth taking seriously is the branch. Merged into what? GitHub's
closing keywords are strict: "If the pull request targets any other branch,
then these keywords are ignored, no links are created, and merging the PR has no
effect on the issues"
(docs.github.com).
A webhook is not. A merge into a release branch, or a stacked PR merged into its
parent, fires the same event as a merge into main, so a rule with no base-branch
condition marks work finished that shipped nowhere. Linear's docs give the shape
of the fix: when a PR is merged to "staging, the issue status should change to
'In QA'" and to "main, the issue status should change to 'Deployed'"
(linear.app/docs/github).
The test for whether an event deserves a status
Bind a git event to a status only when the event marks a change in who is waiting on whom.
Merge changes it: nobody is waiting. A pull request opening changes it: the author has stopped, a reviewer has not started. An approval changes it: the constraint moves to whoever tests or deploys. A push at three in the afternoon does not — the same person is still doing the same thing.
| Git event | What it actually tells you | Worth binding to |
|---|---|---|
| Branch pushed with the issue key | Someone has started | In Progress, guarded |
| Pull request opened | The author has stopped, a reviewer has not started | In Review |
| Marked ready for review | The same, for work that began as a draft | In Review |
| Review approved | The reviewer is done; the constraint moved on | Ready for QA |
| Pull request merged | The change is in the branch you care about | Done |
Five moments, roughly where the tools that have thought about it land — Linear's configurable set is "when PRs are drafted, opened, have a review requested, are ready for merge, and merged" (linear.app/docs/github).
We build Kevta, so treat what follows as an argument we have a stake in. It seeds eight rules on a new board's first connection to a repository, and exactly the five in that table ship enabled.
The events to leave alone
Kevta exposes fifteen triggers. Eight get a seeded rule and five are on. The gap is the interesting part, because the events left alone are the ones nobody writes down.
Synchronize. GitHub's own workflow default says what this event is: "By
default, a workflow only runs when a pull_request event's activity type is
opened, synchronize, or reopened", and "if no activity types are
specified, the workflow runs when a pull request is opened or reopened or when
the head branch of the pull request is updated"
(docs.github.com).
So it fires on every push for the life of the pull request. Right trigger for
CI, wrong one for a status: high-frequency, and it only ever says work is
continuing. SonarSource's Jira sync action does bind it, setting "In Progress"
when a PR is opened or synchronized with no reviewers assigned. Note what it
needed alongside: "Disclaimer: this JIRA automation can be skipped by adding the
common-branch label to Pull Request"
(github.com/SonarSource,
archived January 2025). A trigger that needs a documented escape hatch is
telling you something.
Comments and labels. A comment carries no direction you can compute: "looks good, one nit" and "this needs rethinking" are the same event. A label is already a status set by a human elsewhere, so binding it makes the board a copy of a copy. Neither belongs on by default.
The guard that keeps the board from going backwards
The branch-pushed rule teaches the general principle. In Kevta it seeds with a condition attached: fire only when the issue is currently in To Do.
Pushes do not stop when the pull request opens. You push after review comments, and after approval to fix a merge conflict. Without the guard, that push drags a Ready for QA issue back to In Progress and the person who approved it has to work out why the board disagrees.
Generalise it: any rule bound to a repeatable event needs a condition on the current status, because the event carries no memory of what happened since. "Branch pushed → In Progress" is not a rule about pushing. It is a rule about starting, and starting happens once. Kevta expresses that as a current-value condition on the status column, alongside conditions on base branch, approval count, draft state and labels.
Reverse transitions are a decision, not a default
Three of the eight seeded rules ship switched off: converted back to draft → In Progress, changes requested → In Progress, and closed unmerged → To Do. All three are reverse transitions.
The case for switching them on is real. A board that only moves forward lies in the other direction: a pull request that sat approved and then got closed leaves the issue parked in Ready for QA, asserting something untrue.
The case for off is that reverse transitions behave differently in three ways.
- A forward transition usually agrees with what a person would have done anyway. A reverse one overwrites a decision made on purpose: an issue moved to Blocked, quietly replaced with In Progress because a reviewer left a note.
- The events are not proportional to what they mean. Changes requested on a naming nit and on a design that has to be rebuilt are the same webhook.
- The failure is asymmetric. A board that moves work forward on its own earns trust; the cost of getting one reverse transition wrong is that somebody turns off automation altogether, including the rules that were working.
Both of GitHub Projects' default automations are forward and terminal, which is not an oversight either. If you turn one of the three on, start with closed-unmerged: nothing was merged, and no reading of that event says the work progressed.
Read the run log before adding a sixth rule
Automation you cannot audit is worse than a stale board, which at least fails visibly. Kevta records every evaluation as a run marked applied, skipped or failed, with a reason. Read a fortnight of it before adding a sixth rule. A rule that keeps firing when you did not want it to is usually a missing condition rather than an argument for another rule, and the log is where you find out which.
None of it works unless the pull request matches back to the issue without a human doing the linking. Kevta scans the branch ref, the title, the body and the commit messages for the board key, so there is no magic word and no linking step — the settings are in the boards docs. And it matters because, as why nobody updates the project board argues, the board is least accurate exactly when the team is busiest.
Kevta is in beta. If a board that moves because the code moved is the part you want, join the waitlist — an early invite, a founding-member price at launch, and a direct line to shape what we build next.
- github
- issue-tracking
- tooling