In January 2019 the Spring Framework team left Jira. Rossen Stoyanchev wrote the cutover report. Every issue and every comment from more than 15 years landed on GitHub.
That is 17,000 issues plus comments. Old jira.spring.io links still resolve. They redirect to the matching GitHub issue. Add ?redirect=false if you want the Jira page itself.
If you are looking at the same route, start with the Jira → GitHub Issues playbook. Rossen’s post is the field report.
Why they left
Rossen had used Jira for years. GitHub Issues looked too basic at first. Feature lists did not convince him.
Every Spring project already lived on GitHub. Users already had GitHub accounts. A second login for the issue tracker had become a pain.
Putting issues next to the code also buys you links Jira cannot give you. Mention a commit or a pull request, even in another repo, and GitHub wires the timelines together. Issues and pull requests share one number sequence. They look the same and they show up in the same release notes.
On Jira, the team wanted a ticket for every pull request. People never knew where to talk. After the move they asked for one or the other, not both. Start with an issue if you need a discussion. A later pull request supersedes it.
Spring Boot had always used GitHub Issues. Spring Framework was the odd one out. Boot was not going to move to Jira.
Wiki markup was another push. Rossen used it daily and still found it painful for code. To show curly braces and asterisks you had to write something like {{/endpoint/\{server-id\}/\{session-id\}/\{transport/\*\}}}. Markdown does not fight those characters.
What they mapped
Imported issues keep a Jira block at the bottom of the description. Affected versions, attachments, related issues, pull requests, backport versions, vote counts, and watcher counts sit there. You do not have to bounce back to Jira for the facts.
Votes and watch subscriptions did not come across. Even with full privileges, spring-issuemaster can only vote once. People had to re-react and resubscribe.
Jira fields became labels:
- Issue type →
type: * - Status and resolution →
status: * - Component →
in: *
They also added has: votes-jira for issues with 10 or more votes, and has: backports. Twenty-five Jira components collapsed into five in: labels. The set matches Spring Boot.
Jira lets one issue have many fix versions. GitHub gives you one milestone. Look at SPR-17226. Jira had fix versions 4.3.19, 5.0.9, and 5.1 RC3. On GitHub the milestone is 5.0.9, and 4.3.19 is a backport. They left 5.1 RC3 out of the notes because the fix already shipped in 5.0.9.
That rule also changed how they commit. They apply the fix on the current production branch first, then forward-merge to master, then cherry-pick older production branches.
Historic backports went into about 45 holder issues, one per release. Rossen ran the numbers. If they had picked the in-development version as the milestone from day one, they would have needed about 2,500 backport issues. Picking production first drops that to about 1,000.
Jira keys in comment text became GitHub references. Keys for other Spring projects became links. After the import they did a second pass so those numbers existed first.
Markup
Rossen called markup the biggest and most painful part of the migration.
Fifteen years of comments follow fifteen years of programming style. Early issues are full of pasted XML. Markdown treats that as HTML, so the tags vanish. Those snippets were never wrapped in {code:xml} because they rendered fine in Jira.
Curly braces and asterisks needed escaping. @ in plain text was worse. @Bean, @Configuration, and @Component are real GitHub users. First names like @andy and @arjen collided too. In 17,000 issues that is a lot of accidental mentions. They escaped them. Going forward he asked people to wrap annotations in backticks.
The import
They used GitHub’s unofficial issue import API, the same one Rossen’s jira-to-gh-issues tool calls. The gist says imports do not notify watchers or mentioned users. Testing looked fine.
On the real run, every issue and every comment fired an email. They stopped after about 2,600 issues. Rossen estimated tens of millions of messages. GitHub support had already noticed.
A day later, support fixed the leak and turned off notifications for the Spring Framework repo. The rest of the import took 8 to 9 hours. A second pass replaced Jira keys with GitHub numbers. Markup cleanup took several more days.
What I would copy
Keep old Jira URLs alive with redirects. Put leftover Jira fields in the issue body so people stop opening two tabs.
Map fix versions before you import. One GitHub milestone per issue is not a small difference. It changes release notes and it changes how you commit.
Do the ID rewrite after the issues exist. Cross-issue links need a second pass.
Do not trust a quiet test import. Tell GitHub you are about to create tens of thousands of issues. Escape @ in old comments before you post them.
The Jira → GitHub Issues playbook covers inventory, pilots, and the checks I would run before a cutover like this. Use Rossen’s post for the parts the importer will not warn you about.