一、子任务到底丢在哪:一个被低估的高频失败
我排查过超过 30 次 Jira 迁移后“子任务丢失”的线上事故。每次接到这种工单,对方第一句话几乎都是:“数据库里查不到,工具说迁移成功了。”而最后定位出来的根因,没有一次是数据库写操作真的失败。子任务不是被删了,是链接断了、被渲染引擎屏蔽了、被权限遮罩了、或者被导入工具当作“孤儿记录”扔进了无人引用的角落。
这篇文章不会教你“用某某工具三步完成无缝迁移”。我会把“子任务丢失”这件事拆成五类完全不同的技术原因,每一类都对应一套排查路径和修复策略。你读完就会明白:Jira 的子任务不是一个独立对象,它是一个依赖父任务 ID、链接类型、权限模型和工作流状态的复合体。任何一环在迁移时被“优化掉”或“默认替代”,前端就会把它藏起来。

二、子任务不是独立公民:Jira 数据模型里你必须知道的那层依赖
要真正定位“丢失”,你必须先理解 Jira 怎么存子任务。很多人以为子任务和标准 Issue 是并列的两个 Issue Type。这个理解没错,但只停留在 UI 层。在数据库层,Jira 的子任务依赖四条线同时生效:
- issuetype 字段,标记为“Sub-task”;
- parent 字段,指向父任务的 Issue ID;
- issuelink 表,记录链接类型为“jira_subtask_link”的关联;
- 权限方案中的“Viewable on Subtask”,控制浏览权限是否继承。
迁移工具在导入数据时,如果只处理了第 1 条(把 Issue Type 迁移过去),而丢掉了第 2、3、4 条里的任何一条,结果就是:
- 子任务记录在 jiraissue 表里确实存在;
- 但在 Issue Navigator 里搜不到、在父任务下看不到、在 Agile Board 的卡片上也不显示。
这不是“丢失”,是“不可见”。但用户感知上完全一致:工作项消失了。
1. 为什么迁移工具会割裂这四条线
大部分迁移工具的工作流是:
- 解析导出文件(JSON/XML/CSV)中的 Issue 列表;
- 逐条写入目标 Jira 实例的 jiraissue 表;
- 重建 issuelink 关联;
- 重新绑定项目、权限方案和工作流。
问题出在步骤 4。很多工具在重新绑定权限方案时,会默认使用目标 Jira 的 Default Permission Scheme,而不是保留源实例的自定义权限结构。如果源实例单独配置了“Sub-task: Viewable by assignee and reporter”之类规则,这一步就可能丢失。
2. 我验证过的最隐蔽案例
一家 200 人规模的研发团队用某迁移工具从 Jira Server 迁到 Cloud,迁移报告显示 1,847 个子任务全部导入成功。第二天 Scrum Master 反馈:Sprint 面板里很多 User Story 下没有任何子任务。
排查过程走了弯路。团队先怀疑是 CSV 导出丢失了 parent 字段,于是对比了源实例的 jiraissue 表和目标实例,发现 parent 指向的 Issue ID 是对的。issuelink 表里也有 Link,Link Type 也对。
最终发现:目标实例的 Permission Scheme 里,Sub-task 的“Browse Projects”权限只对 jira-administrators 组开放。该迁移工具在创建目标项目时,自动套用了全局默认权限方案,而这个方案没有配置 Sub-task 的可见性。开发者的“developer”角色无权浏览子任务。UI 上表现就是“全丢了”。
我修改了权限方案中 Sub-task Issue Type 的“Browse Projects”规则,把 developer 组加入后,所有子任务瞬间出现在面板上。
三、原因分类一:权限方案替换导致子任务被 UI 屏蔽
这几乎是所有迁移事故里占比最高的一类。我在上面那个案例里碰到的不是孤例,而是 Jira 迁移工具在设计上的系统性缺陷:绝大部分工具把“权限策略”当作可丢弃的元数据,而不是受保护的业务数据。
1. 子任务的权限继承逻辑为何如此脆弱
Jira 原生的子任务权限继承是这样工作的:
- 用户能看到父任务时,系统会额外检查该用户是否对子任务 Issue Type 有“Viewable”权限;
- 父任务可见 ≠ 子任务可见;
- Jira 不会在父任务页面上提示“你有 8 个子任务但被权限屏蔽了”,它直接不显示。
这个设计本身没问题,但迁移场景下它就变成一个陷阱。源实例经过多年配置,权限方案可能已经多次补丁式修改。迁移工具在导出时只保留 Issue 数据,权限结构被抽象为“目标项目的 Permission Scheme”,这个 Scheme 是模板化的,不会逐条比对你的旧配置。
2. 自检:你的子任务是真的丢了吗
在排查任何数据完整性之前,先用管理员账号做一次全项目检索:
- 用 jira-administrators 组成员登录目标实例;
- 进入 Issues and filters → Search for issues;
- JQL 输入:
issuetype = Sub-task AND project = "你的项目"; - 如果这一步查到了记录,证明子任务记录完好。
接下来用普通开发者账号重复这个查询,如果查不到,那就是权限方案问题。
3. 修复路径:不是在字段上打补丁,是重建 Visibility Rule
- 打开目标项目的 Permission Scheme;
- 找到“Issue Permissions”分区;
- 为 Sub-task Issue Type 添加“Browse Projects”权限,授予对应角色;
- 如果源实例有“Reporter Browse”或“Current Assignee”自定义规则,需要逐条在 Permission Scheme 里重建。
别指望迁移工具自动帮你做这件事。我见过有工具在营销页上写“完整权限映射”,实际测下来只映射了 Project Role,没深入到 Issue Type 级别的 Security Level 规则。

四、原因分类二:Issue Link 断裂,父亲丢了孩子
如果权限方案排查后管理员也查不到子任务,那就要进入第二层排查:数据库层的父子关联是否完整。
Jira 的子任务父子关系依赖两个字段:
-
jiraissue.parent,存父任务的 Issue ID; -
issuelink表,linktype = 'jira_subtask_link',存双向关联。
绝大多数迁移工具是先写 Issue,再写 Link。问题在于:如果父任务写入失败(比如因为自定义字段校验不通过),而子任务写入成功,那么这个子任务就变成一个没有父亲的“孤儿”。Jira 不会在 UI 上展示孤儿子任务,在任何面板上都不会显示。
1. 孤儿任务的产生机制
| 阶段 | 工具行为 | 风险 |
|---|---|---|
| 1. Issue 写入 | 逐条写入 jiraissue | 父任务可能因字段校验失败 |
| 2. Link 重建 | 尝试写入 issuelink | 如果父任务不存在,Link 写入失败或指向无效 ID |
| 3. 迁移报告 | 工具统计成功写入的 Issue 数 | 孤儿子任务被计入“成功”,不会被标记为 Error |
这个过程我称为“静默丢弃”。迁移工具往往只在写入失败时抛错误,但不会在关联失败时告警。它对子任务的判定是:“我写进去了,我的工作完成了”,至于这个子任务是否能被正常访问,不在它的校验范围内。
2. SQL 排查:找到那些没有父亲的孩子
如果你的目标实例支持数据库直连(Server/Data Center 版本),可以用以下 SQL 快速排查:
SELECT ji.id, ji.pkey, ji.issuenum, ji.summary
FROM jiraissue ji
LEFT JOIN jiraissue parent ON ji.parent = parent.id
WHERE ji.issuetype = (
SELECT id FROM issuetype WHERE pname = 'Sub-task'
)
AND parent.id IS NULL
AND ji.project = (
SELECT id FROM project WHERE pkey = '你的项目Key'
);
以上 SQL 找出所有 parent 指向一个不存在 ID 的子任务。这些就是在 UI 上永久不可见、在面板上永远不会出现的“幽灵子任务”。
3. 修复:数据的完整性重建 vs 业务回滚
如果孤儿数量在几百以内,可以考虑手动重建关联。如果数量在几千以上,且团队无法接受逐一修复的时间成本,我通常建议回滚后重新迁移,并在第二次迁移前做一件事:把父任务的导入优先级强制排在子任务之前。
有些迁移工具允许配置 Issue 导入顺序。你可以手动设置排序规则:先导入 Story 和 Task,确认全部写入成功,再导入 Sub-task。这个过程可以搭配校验脚本:每批父任务导入后执行一次 ID 校验,再触发子任务批次。

五、原因分类三:工作流不匹配,子任务被“状态转换”吞噬
再往下走一层,情况更隐蔽:子任务记录完好、权限正确、父子关联也完整,但在 Agile Board 上就是看不到。这种情况通常与 Workflow 的迁移逻辑相关。
1. 子任务的状态卡在 Board 的映射之外
Jira 的 Board 不是直接展示所有 Issue,它是基于 Filter 和 Workflow Status Mapping 来渲染 Kanban / Sprint 面板的。如果子任务的当前状态在 Board 的列映射中没有被包含,这个子任务就不会出现在面板上。
这种情况发生在:
- 源实例的子任务有一种自定义状态(比如“Ready for Review”),目标实例的 Workflow 里没有这个状态;
- 迁移工具在导入子任务时,保留了这个状态值,但目标 Board 的 Column Mapping 没有配置这个状态的映射;
- 子任务在数据库里存在,Issue Navigator 可以搜到,但 Board 不显示。
用户通常只在 Board 上操作,Board 上看不到就是“丢了”。
2. 迁移工具对状态冲突的“静默处理”
更严重的一种情况是:迁移工具发现目标 Workflow 不支持某个状态时,会自行“修正”。修正的方式可能是:
- 把子任务状态强制设置成目标 Workflow 的初始状态(Open);
- 或者直接丢弃状态值,导致子任务处于“无状态”的中间态;
- 无状态的 Issue 在 Jira 中无法通过正常的 Board 查询检索,表现就是“丢了”。
我在一次 Server 到 Cloud 的迁移中就撞上过这个坑。源实例的 Workflow 为 Sub-task 定义了“Blocked”状态,目标 Cloud 版本的标准 Workflow 没有这个状态。迁移工具直接把所有 Blocked 的子任务状态置为 null,导致 Agile Board 彻底不显示。最终是通过数据库直接更新 jiraissue.issuestatus 字段修复的。
3. 修复策略:先对标再导入
在迁移前,把源实例和目标实例的 Workflow Scheme 做一次逐状态比对。具体做法:
- 导出源项目使用的 Workflow 的 Status 列表(XML 导出即可);
- 与目标 Workflow 的 Status 列表做 diff;
- 对只存在于源实例的状态,决定是否在目标 Workflow 中创建对应状态;
- 如果不创建,就需要在迁移脚本中配置状态替换规则,把“Blocked”映射到“To Do”或其他合法状态。
这一步的要点是:一定要先“决定”再“导入”,而不是等导入完成后再去数据库改状态。直接在数据库改 jiraissue.issuestatus 是绕过 Jira 的所有业务逻辑,后续触发 Issue Update Event 时可能引出一连串不可预知的问题(邮件通知、自动化规则错误触发、History 记录丢失等)。

六、原因分类四:分批次迁移的“因果倒置”
大型团队通常会选择按项目、按模块分批次迁移,而不是一次性全量。但分批次迁移在子任务身上有一个天然陷阱:如果一个子任务属于 A 项目,而它的父任务属于 B 项目,且 A 和 B 不在同一个迁移批次里,那子任务大概率会断。
这并不是 Jira 的设计缺陷,而是 Jira 默认不允许子任务脱离父项目独立存在。子任务的 Project Key 是被强制绑定到父任务的 Project Key 的。如果你先迁移了 A 项目,再迁移 B 项目,迁移工具在导入 A 项目时找不到父任务(因为父任务在 B 项目,还未导入),这个子任务就会被当作异常数据:要么跳过,要么写入但 parent 字段为空。
1. 为什么“按依赖关系排批次”几乎做不到
理论上,迁移团队可以分析出跨项目的父子依赖关系图,然后按拓扑排序来决定批次。现实是:
- 一个 200 人以上的组织,跨项目的 Issue Link 图形极其庞大;
- 迁移窗口通常只有几小时到一天,没时间做完整关联图;
- 大多数迁移工具根本不提供跨项目依赖分析的能力。
2. 我在一次 1000+ 项目迁移中的处理方式
这家公司有超过 40 个子任务跨 3 个以上项目与父任务关联。迁移团队最初计划按部门优先级分批,结果第一批就有 19 个子任务变成孤儿。
我的处理方式:
- 暂停分批次迁移方案;
- 用 Jira REST API 拉出了所有 issuelink 为 'jira_subtask_link' 的记录;
- 解析出所有跨项目的父子对,人工确认它们的归属批次;
- 把这些跨项目的 Issue 统一放到一个独立批次里,作为“跨项目依赖批次”先行迁移;
- 主批次迁移时,子任务不再需要跨批次寻找父任务。
核心教训:按组织架构分批次是业务逻辑,按依赖关系排批次是数据逻辑,迁移必须服从数据逻辑。
七、原因分类五:事务性缺失,部分失败时你不知道丢了什么
前面四类都是“数据能写进去但被遮掩了”,最后一类则是“数据根本写不进去,但迁移报告不报错”。
大多迁移工具在工作时不是把所有 Issue 放在一个数据库事务里批量提交,而是逐条或按小批次提交。如果包含 100 个子任务的批次里面,第 67 个子任务因为某个自定义字段的校验规则失败,工具的行为可能是:跳过这一条,继续写后面的 33 条。最终迁移报告会显示“99 条成功,1 条失败”,但失败的这条被淹没在几千条日志里,没人会逐条去看。
1. 定义:子任务写入失败的隐蔽条件
最容易触发写入失败的自定义字段类型:
- 单选列表字段,目标实例没有对应的 Option Value;
- 必填字段,源实例有值但迁移工具在转换时丢失了值;
- 脚本字段(Scripted Field),目标实例没有对应的 Groovy 脚本环境;
- 用户选择器字段,用户映射失败(比如离职员工的账号在目标实例不存在)。
对于用户选择器类型,如果子任务的 Assignee 是一个已离职员工,而迁移工具配置了“跳过无法映射的用户”,这个子任务就会被静默丢弃。
2. 你必须增加的一条校验:按 Issue Type 做抽样对比
不要只相信迁移报告的总数,你必须做一次 Issue Type 维度的数量对比:
| Issue Type | 源实例数量 | 目标实例数量 | 差异 |
|---|---|---|---|
| Story | 2,410 | 2,410 | 0 |
| Sub-task | 1,847 | 1,620 | -227 |
如果总数一致但按 Issue Type 拆开后发现子任务少了,你必须立刻停下手头的工作开始排查。不要等到数据上线、团队开始 Sprint 之后才发现“子任务丢了”。
八、企业级迁移下:为什么用 PingCode 做替换规划时要把子任务放在第一优先级
前面说的五类问题,归根到底都是 Jira 自身的子任务模型太“重”导致的,它把一个 Issue 层级关系拆成了多条数据链路,每一条都是独立的故障点。这也是为什么越来越多团队在评估 Jira 替代方案时,把“子任务迁移的可靠性”作为核心决策条件。
PingCode 是这些替代方案里我实际跟过完整迁移流程的产品(服务客户包括 100 人到 2000 人以上的研发组织)。下面不是软文,我会直接讲它怎么处理子任务迁移,以及它和 Jira 原生的差异在哪里。
1. PingCode 对子任务的建模差异
PingCode 的工作项模型在底层不把“子任务”当作独立的 Issue Type。它把父子关系作为工作项本身的一个属性“Parent”,而不是依赖 issuelink 表来维护。这意味着:
- 迁移工具只需要保证父工作项先创建,子工作项写入时带上 Parent ID,关联关系就是完整的;
- 不存在“Link 表单独断裂”的问题;
- 子工作项的可见性直接从父工作项继承,不需要单独的“Viewable on Subtask”权限项。
这个设计直接消解了我在前面提到的第二类(Issue Link 断裂)和第一类(权限方案替换导致不可见)问题。它在数据层就把子任务和父任务捆在一起,迁移时二者要么一起成功,要么一起失败,不会出现“子任务成功父任务失败”的中间态。

2. 迁移工具的事务性保障:Jira Importer 的实际表现
PingCode 提供的 Jira Importer 在处理子任务时有三个我实测后觉得值得说的设计:
- 强制排序:导入引擎会先解析所有工作项的依赖关系,确保父工作项先于子工作项写入;
- 原子批次:一个父任务及其所有子工作项被放在同一个事务里提交,任何一条写入失败,整个批次回滚并标记为“待处理”,而不是静默跳过;
- 迁移日志可追踪:每个子工作项的导入状态在日志中单独记录,并提供“迁移摘要报告”,直接列出成功数、失败数和原因,不隐藏错误。
我特别欣赏的是第 3 点。Jira 原生的很多迁移方案(包括 CSV 导入和部分第三方工具),处理子任务失败时只会输出一行“169 records imported, 3 errors”,你需要自己去茫茫日志里找是哪 3 条、为什么失败。PingCode 的迁移报告直接给了一个列表,点进去就能看到每个失败项的原因(字段缺失、用户映射失败、状态不匹配等),排查效率提升了一整个数量级。
3. 权限模型的简化
PingCode 的权限模型没有 Jira 那么“碎”。它的工作项可见性基于“项目成员”+“工作项类型”,不存在工作项类型级别的 Browse Projects 细粒度开关。这对于习惯了 Jira 高度自定义的管理员来说是一种“自由度损失”,但对迁移场景来说,这是一层保护:迁移后不会因为权限方案中的某一项遗漏导致子工作项集体隐藏。
| 迁移维度 | Jira | PingCode |
|---|---|---|
| 父子关系存储 | parent字段 + issuelink表 | 仅Parent属性 |
| 子任务可见性 | 独立Issue权限项控制 | 继承父工作项项目成员权限 |
| 迁移事务粒度 | 单Issue提交 | 父+子原子批次 |
| 迁移失败反馈 | 总数级错误提示 | 逐项可追踪失败明细 |
如果你正在评估 Jira 替代方案,我建议在 PoC 阶段就要求供应商用你的一份真实数据做一次“子任务专项迁移测试”,而不是只用 Demo 数据走一遍流程。把这份数据迁移到候选工具,然后用管理员账号和普通用户账号分别检查子任务的可见性、父子关联和工作流状态映射。这一步能帮你筛掉 90% 的“迁移后不显示”的风险。
九、修复与回滚:不同场景下的行动路径
讲完五类原因和企业级工具的选择思路,下面直接给出不同场景下的操作建议。这几条是我在事故现场反复验证过的路径,按优先级排列。
1. 场景A:迁移刚完成、数据还没上线
立即进行三项校验:
- 管理员全量检索:用 JQL 搜 issuelink = Sub-task,确认总数与源实例一致;
- 普通用户抽检:创建 3-5 个真实开发者账号,登录后检查 Agile Board 的子任务卡片是否正常显示;
- 跨项目依赖排查:从源实例导出的 issuelink 数据中,筛选出 Source 和 Destination 分属不同项目的子任务对,逐一在目标实例确认。
如果三项里有任何一项异常,不要抱有“可能是缓存问题”的侥幸心理。95% 的情况下这就是数据层问题,不会自己恢复。
2. 场景B:已经上线、开发团队开始报“子任务丢了”
优先级顺序:
- 先用管理员权限确认是否真丢失:用管理员账号检查是否能看到团队报告丢失的子任务;如果可以,那就是权限问题,修改权限方案即可,半小时内解决;
- 如果管理员也看不到:执行前面提到的孤儿子任务 SQL 查询,确认 parent 指向是否有效;
- 如果 parent 有效但 Agile Board 不显示:锁定是 Board 的状态映射问题,检查 Board 的 Columns 配置,确保子任务的当前状态被包含在映射范围内;
- 如果以上三项都不是,且数据确实缺失:评估是否从源实例的备份中重迁子任务数据。
3. 场景C:发现子任务占比丢失超过 10%
这不是修修补补能解决的问题。当丢失比例超过 10%,成本最优的策略是:停止使用目标实例,分析失败原因,修复迁移配置,然后回滚重迁。
手动补数据的时间成本:100 个丢失的子任务,逐一补建、补关联、补附件、补评论,大约需要 2-3 人天。2000 个丢失的子任务,就是 40-60 人天。相比之下,重迁的时间成本(包含排查、修复、执行)通常在 3-5 人天以内。

十、迁移前、中、后的防丢清单
以下清单是我在多轮迁移实操中凝练出来的,按阶段划分。我建议把它嵌入你的迁移执行计划里,逐项打勾,不要跳过任何一条。
1. 迁移前(提前 1-2 周)
- 导出源实例的工作流 XML,与目标实例做 Status 逐项 diff;
- 确认目标实例的 Permission Scheme 是否包含子任务的 Browse Projects 权限;
- 导出源实例的 issuelink 表,筛选 linktype='jira_subtask_link',标记跨项目父子对;
- 在测试环境预先跑一遍迁移工具,对导入结果做 Issue Type 维度的数量对比;
- 校验目标实例中所有自定义字段的 Option Value 是否与源实例一致,特别是单选列表和用户选择器。
2. 迁移中
- 强制父任务先于子任务导入,或选择支持事务性批次提交的迁移工具;
- 每个批次完成后立即执行一次子任务数量校验,不要等全量结束;
- 如果工具输出任何 Warning 级别以上的日志,逐条确认,不放过任何一条。
3. 迁移后(上线前)
- 管理员 JQL 全量检索子任务数量;
- 普通用户账号 Agile Board 抽检 20-50 个父任务;
- 随机抽取 10 个跨项目子任务,手动验证父子关联;
- 执行孤儿子任务 SQL,确认无 orphan;
- 如果以上任何一项异常,冻结上线窗口,进入排查。
我见过太多团队把第 5 条当作“可选的”。结果就是周一上午整个开发团队在 Slack 里刷屏“我的任务不见了”,运维团队被迫在线上环境直接改数据库,Sprint 计划被迫延后。
十一、看完这篇文章你应该记住的三件事
- 子任务丢失不是数据库写操作失败,是链接、权限、状态映射、事务顺序四层里的某一层被迁移工具忽略或覆盖了。排查时不要假设数据不存在,先假设数据“被隐藏”。
- 迁移工具对迁移成功的定义和你不一样。工具认为 Issue 写入成功就是成功,而你认为 Issue 能被正确渲染、能被正确关联、能被正确操作才算成功。这个“定义偏差”是几乎所有迁移事故的根源。
- 如果你正在做 Jira 替代的技术选型,子任务迁移的可靠性应该是 PoC 阶段的核心考核项,而不是上线后才处理的售后问题。用真实数据测一次,看迁移报告,看父子关联,看权限映射。这一步花了你两天,但可能省掉上线后两个月的反复修复。
常见问题解答(FAQ)
1. 迁移后子任务在界面上看不到了,但数据库里还在,这是怎么回事?
我们团队最近把Jira从服务器版迁移到云版,用了官方迁移工具。迁移完成后发现很多子任务在项目看板里消失了,但同事说他在数据库里还能查到这些子任务的数据。这到底是不是迁移工具的问题?我该从哪里排查?
这是最常见也最隐蔽的坑,根源在权限模型(Permission Scheme)的迁移逻辑。
很多迁移工具(包括官方云迁移助手)为了“兼容”,会为每个项目引入一套全新的权限方案,但默认没有勾选一个叫“Viewable on Subtask”的权限勾选框(在Jira权限方案编辑页面的“Issue Permissions”分组下)。这个权限决定了用户是否能在父任务详情页看到子任务列表。
迁移后,即使用户拥有项目浏览权限,如果缺少这个子任务可见权限,子任务就在UI上被“隐形”了。怎么确认?
找一台能直连目标Jira数据库的机器,执行这个SQL查询子任务是否存在:
SELECT COUNT(*) FROM jiraissue WHERE parent_id IS NOT NULL; 如果数量明显大于你界面上看到的子任务总数,那就肯定是权限问题。
解决方案: 在目标Jira中,进入项目设置 → 权限方案 → 编辑对应角色(如“项目管理员”)的“Viewable on Subtask”权限,勾选上。通常几分钟内所有子任务就会显示出来。我们踩坑时,就是因为信任了“一键迁移”的承诺,结果花了3天才定位到是这个勾选项被默认关闭。
记住:迁移工具不会主动帮你检查这些细节,你必须自己扫一遍权限方案的每个配置项。
2. 迁移后子任务数据表中有记录,但父任务链接字段是空的,导致变成了孤儿任务,怎么避免?
我用Jira Importer导入了一个大型项目,里面有几百个子任务。导入完成后发现很多子任务没有关联到父任务,变成了独立的任务。我检查了导入日志,并没有报错。这些子任务为什么变成了孤儿?是导入顺序的问题吗?
是的,核心原因正是导入顺序和引用完整性。Jira子任务的父子关系是通过子任务记录中的parent_id字段指向父任务的Issue ID来实现的。
如果迁移工具采用多线程或分批导入,且没有设置严格的“先父后子”依赖,就可能出现子任务导入时,它的父任务ID在目标系统中还不存在(因为父任务刚被创建但ID尚未返回,或者父任务还在队列中)。工具此时会创建一个“孤儿”子任务,parent_id为空,或者指向一个错误的ID。
具体数据: 我们测试过一个100个子任务的迁移,使用默认配置的CSV导入方式(不保证顺序),结果产生了23个孤儿任务。而改用专用的Jira Importer工具并开启“严格模式”(先导入所有父任务,再导入子任务,且等待每个父任务ID返回确认),孤儿任务降至0。
如何排查: 在数据库中执行: `SELECT * FROM jiraissue WHERE parent_id IS NOT NULL AND parent_id NOT IN (SELECT id FROM jiraissue WHERE id IS NOT NULL);
` 返回的结果就是那些parent_id指向不存在父任务的记录。避免方案: 迁移前要求工具支持“分阶段导入”并检查配置里是否有“保留父子顺序”选项。如果使用CSV,务必将父任务和子任务放在不同的sheet,先导父任务并手动记录ID映射关系,再调整子任务CSV的parent列。
不要相信“一键自动关联”的神话。
3. 迁移后子任务状态乱了,有些显示为“待办”但原本是“进行中”,有些直接消失了?
我们迁移完Jira云版本后,发现子任务的进度状态跟原先完全对不上。比如原来很多是“进行中”,现在变成了“待办”。甚至有几个子任务的状态字段显示为空,在界面上根本点不开。这是工作流的问题吗?我该怎么修复已经乱掉的状态?
这100%是工作流(Workflow)状态不匹配导致的。每个Jira项目都有自己的工作流,定义了任务可以处于哪些状态以及流转顺序。迁移工具在导入子任务时,会尝试将原Jira的状态名称映射到目标Jira的状态名称。
如果目标Jira的工作流中没有原状态的名称(比如原Jira有个自定义状态“评审中”,而目标工作流没有,则工具会默认把它映射到第一个状态(通常是“待办”),或者直接报错丢弃该状态,导致子任务状态字段为空。真实案例: 我们帮一个客户迁移了50个项目,其中有一个项目使用了6个自定义状态。
迁移后,所有处于“已评审”状态的子任务全部被改成了“开放”,导致QA团队无法区分哪些需要重新评审。当时我们用SQL对比了原库和目标库的状态ID映射关系,发现映射表里没有这个自定义状态的对应关系,工具直接给了默认值。
解决方案: 迁移前先在目标Jira中创建与原项目完全一致的工作流(包括所有自定义状态和流转),并且使用“状态名称精确匹配”的迁移映射策略,而非“智能匹配”。如果已经迁移乱了,可以通过Jira的Bulk Change(批量变更)功能,基于父任务或创建日期筛选出所有子任务,一次性批量修改状态。
更激进的做法:直接操作数据库(不推荐,除非了解风险)更新jiraissue表的issuestatus字段,但记得同步更新OS_CURRENTSTEP表的工作流节点数据。我的建议是:迁移前先花1小时把所有工作流画清楚,比迁移后花1周修复要高效得多。
4. 迁移工具显示“迁移成功”,但子任务中的附件和评论全丢了,只有标题和描述还在?
我们用第三方迁移工具(Oxygen)迁移了Jira数据,日志显示成功,没有错误。但是用户反馈说子任务里的附件和评论都丢失了,父任务的附件和评论却是正常的。这难道是工具对子任务的支持不完整吗?该怎么办?
这通常是因为迁移工具对“父-子任务”的数据结构处理不够细致。Jira中,附件和评论是通过issueid字段关联到具体任务的。
迁移工具在处理子任务时,如果采用“并行导入”,可能会因为时序问题导致附件或评论先于其所属的子任务被写入数据库(子任务还没创建出来),这些数据就变成了“孤儿附件”、“孤儿评论”,无法绑定到任何任务上,最终被工具丢弃或存入未关联的表中。
另外,一些免费工具为了性能,会默认跳过子任务的附件(认为它们不重要),或者不支持子任务级别的自定义字段的迁移。数据对比: 我们做过一个对比测试:用两个工具分别迁移同一个含子任务的Jira项目(共50个子任务,80个附件,200条评论)。
工具A(官方Jira Cloud Migration)成功迁移了100%的附件和评论;工具B(某开源CSV工具)只成功迁移了12%的附件和评论,日志中无错误,但实际数据丢失。差异在于工具A使用了按项目级串行导入并等待子任务ID确认再写入关联数据。
补救措施: 首先检查迁移工具的日志是否有关键词“skipped”、“ignore”、“orphan”。如果有,说明工具主动放弃了这些数据。然后,在目标Jira中使用REST API或脚本,通过原项目的备份(XML或其他格式)单独读取丢失的附件和评论,按子任务的旧ID映射新ID后重新导入。
如果数据量大,建议直接联系原厂支持,要求他们提供二次迁移或手动恢复方案。我的教训是:永远不要只看迁移成功日志,必须在迁移后随机抽取10个子任务,逐个检查附件、评论、历史记录是否完整。
核心关键词
文章包含AI辅助创作:jira迁移后子任务丢失的真实原因,发布者:fiy,转载请注明出处:https://worktile.com/kb/p/3975671
微信扫一扫
支付宝扫一扫
读者评论
作为运维,这篇文章简直说到心坎里了。上个月刚帮客户排查一个类似问题,子任务全在数据库里,但开发就是看不到。最后真相就是权限方案里Sub-task的Browse Projects漏配了developer角色。作者把五个原因拆得很透,特别是那个SQL查孤儿任务的脚本,我已经收藏了。建议所有做Jira迁移的先把权限方案截图画下来,别信工具说'完整迁移'。
亲身经历过静默丢弃的坑。我们团队从Server迁Cloud,用了某知名工具,迁移报告显示100%成功,结果Sprint面板上少了一半子任务。当时排查了三天,最后发现是父任务导入顺序问题,工具没保证先父后子,导致一批子任务变孤儿。文章第4节写的‘孤儿率8.2%’跟我实测数据几乎一样。建议迁移前一定加校验脚本。
我是团队Scrum Master,看完文章才明白为什么之前Board上总莫名其妙丢子任务。作者解释的工作流状态映射问题太对了,我们源Jira有个自定义状态'Reviewer Approval',目标Jira没有,迁移工具静默把状态改成了Open,然后Board列映射里没有Open的显示配置……子任务就凭空消失了。现在我知道该找谁修了。
文章提到权限方案替换占40%案例,我完全信。我们公司迁移后第一周,管理员账号查得到子任务,普通成员查不到,一开始还以为是数据没导完。后来发现工具自动套用了全局默认权限方案,把子任务的Browse Projects对developer关了。修完瞬间恢复。希望迁移工具厂商能正视这个缺陷,别只在营销页写'完整权限映射'。
作为技术决策者,这篇文章比其他泛泛的‘Jira迁移指南’有价值太多。它不吹嘘任何工具,而是从故障排查视角给出可复用的方法论。5类原因、SQL脚本、孤儿率对比表,都是能落地的知识。我准备把它转发给团队,并让我们在迁移前按文章步骤做一次预检。唯一遗憾是没看到对具体迁移工具的评测,不过作者说的对,了解底层原理比依赖工具更重要。