并行期最容易出的事故,不是代码推不上去,而是同一个需求在两套系统里有两个状态。Jira 里还停在"测试中",新 Git 的合并请求已经进了主干;复盘时,产品经理看 Jira,开发看 Git,测试看流水线,三边都能给出"最新状态"。
私有化研发协同系统并行期,旧 Jira 与新 Git 并存,难点不在装好两套系统,而在把数据主权、关联关系和切换时间定成规则。下面 6 条规则按"先定边界、再定写入、再定退出"的顺序展开,适合 DevOps 负责人、研发主管和平台工程师直接改成本团队的迁移检查表。
并行期最怕的不是两套工具,而是三类"脑裂"
工具并存本身不是问题。问题是同一条业务事实被两套系统分别解释,最后没有统一口径。并行期常见的脑裂有三类。
- 身份脑裂:Jira 用账号 ID,Git 用提交邮箱,目录服务里还有工号。同一个人在三处可能是三个标识。表现是提交记录归不到人,权限复核对不上。
- 写入脑裂:Jira 的自动化、Git 的 webhook、人工操作都能改状态。表现是同一个缺陷先被关闭又被打开,或者 Jira 显示"已解决",新系统仍显示"处理中"。
- 时间脑裂:旧任务没关,新任务已开;旧分支还在提交,新仓库已经冻结。表现是发布清单里出现两套版本号,回滚时找不到对应的代码。
三类问题指向同一件事:并行期缺的不是更多同步,而是一份字段级的数据契约。只发通知、拉群、开会,解决不了"谁能写"的问题。
先把数据主权划清:Jira、Git 与新协作层各管什么
数据主权不是"谁更重要",而是"这个字段允许谁写"。并行期最容易犯的错,是让两套系统都保存全量数据,再做双向同步。同步一多,冲突就不是异常,而是日常。
| 数据对象 | 唯一写主库 | 另一侧保留什么 | 关联键 |
|---|---|---|---|
| 需求、任务、缺陷的标题、描述、状态、评论 | Jira(切换前) | 只读镜像或链接 | legacy_id |
| 代码、分支、提交、合并请求、评审记录 | 新 Git | 链接与摘要 | commit SHA / MR ID |
| 用户身份 | 企业目录(LDAP/AD/HR) | 各系统本地账号 | 工号或目录 ID |
| 构建、制品、发布记录 | 新 Git 或发布系统 | Jira 只存版本引用 | build ID / artifact ID |
| 审计日志 | 各系统各自留存 | 不互相覆盖 | event_id + 时间戳 |
如果新平台同时带来新的项目协作模块,不要把 Jira 的全部字段搬过去再双写。切换前,Jira 仍是问题主库;新协作层只承接新项目,或者做只读镜像。切换后再反过来,旧 Jira 只读。

图 1:数据主权矩阵。Jira 保留历史问题与流程记录,新 Git 持有代码、评审和构建证据,映射层只负责关联,不复制业务字段。
这张矩阵的用法很直接:任何新字段上线前,先填"唯一写主库"一列。填不出来,就不要接同步。以 GitFox 这类私有化 Git 平台为例,代码库、分支、合并请求、流水线、制品库的元数据应由 Git 侧持有;需求与缺陷仍由协作侧持有。两边通过 ID 关联,而不是互相复制整张表。
规则一:一个字段只能有一个写主库
这条规则听起来像废话,落地时却最容易被"先同步起来再说"打破。字段级的主库要写进接口权限,不是写在文档里。
- 写接口只开给主库 :Jira 的
status、assignee、sprint、fixVersion等字段,只允许 Jira 或其授权自动化写;新 Git 只能读,或者提交变更请求事件,由 Jira 侧裁决。 - 读副本可以多,写入口只能一个:报表、看板、搜索索引都可以复制;复制失败不影响主库。反过来,任何"为了看板方便"直接写副本的做法都要禁止。
- 跨系统只追加三类东西:引用链接、同步事件、审计备注。不要新增"另一个状态字段"来表达同一件事。
- 例外进队列,不要进数据库:冲突、缺失映射、权限不足,统一进人工复核队列;不要让脚本"猜一个值"写回去。
判断是否双写,有一个简单测试:把新 Git 的写接口关掉 24 小时,业务是否还能正常流转?如果答案是否定的,说明你把主库放错了位置,或者把不该由 Git 承担的字段搬了过去。
规则二:用不可变 ID 建映射,别把项目键当主键
Jira 的 issue key 很好用,但它不是数据库主键。Atlassian 的文档把 issue key 定义为"项目键 + 问题序号"的可读标识;项目键在迁移、改名或重组时可能调整,迁移文档也提醒,改键后要同步配置、过滤器和看板。拿它当跨系统主键,后面会不断修关联。
- 三层 ID 分开存 :
legacy_id(Jira 内部 ID,用于稳定关联)、legacy_key(人看的 issue key,如PROJ-123)、new_id(新系统 ID)。关联以legacy_id为准,legacy_key只用于搜索和展示。 - 自定义字段按 ID 映射,不按名称:Atlassian 明确建议使用自定义字段 ID,因为名称可以改。字段名"故事点"明天可能叫"工作量",按名称映射会断。
- 用户按目录 ID 映射,不按显示名:同名、改名、离职再入职都会让显示名不可靠。最少保留工号或目录 ID、邮箱、Git 提交邮箱三列,做归一。
- 代码按 commit SHA 绑定,不按分支名:分支会移动,发布标签也可能被重写。发布证据要落到 commit SHA;release tag 要开启保护,不要允许随意的强制推送。
- 不要复用旧编号 :新系统不要从
PROJ-123继续编号,也不要给新项目分配旧项目键。旧键保留为别名,新键独立生成;否则历史搜索和审计会混在一起。
映射表最少要有这些列:legacy_system、legacy_id、legacy_key、new_id、object_type、migrated_at、mapping_status、checksum。mapping_status 至少区分 mapped、missing、conflict、ignored。没有这四态,迁移报告只会告诉你"大概迁完了"。
Atlassian 的迁移故障排查文档还提到,空必填字段会导致迁移失败,历史记录引用缺失时该条历史不会迁移。这说明迁移不是把页面复制过去,先把数据清洗和引用补齐,比切工具更重要。
规则三:提交、分支和评审只走一条关联链
很多团队在并行期会同时保留两套关联:Jira 的提交信息解析,和新 Git 的自动关联。两边都能识别单号,两边都能改状态,最后同一件事被写两次。
Atlassian 的 Bamboo 文档说明,提交信息里出现默认格式的 issue key 时,构建会自动建立关联。提交信息本身就是一条数据入口;入口越多,重复写入的概率越高。
- 提交信息用固定结构 :
feat(scope): 摘要 [WORK-123]。如果需要兼容旧 Jira,再加一行Legacy-Key: PROJ-123。新系统只解析WORK-123或legacy_id,旧键只做展示。 - 分支名和合并请求标题带工作项 ID :分支用
feature/WORK-123-short-name,hotfix 同样。合并请求标题带 ID,正文写影响范围;不要用"最终版""再改一版"这类无法解析的名字。 - 只保留一个解析器:要么 Jira 侧解析旧提交,要么新 Git 侧解析新提交;不要让两边同时消费同一批 webhook。谁负责写状态,就在谁那里配置规则。
- 发布标签保护:release tag 绑定 commit SHA,开启保护,禁止普通开发者移动或删除。回滚时按 tag 找 SHA,再找构建和制品,不要按"最新分支"找。
规则四:同步用事件流,别做双向全量覆盖
并行期需要同步,但不需要"两边一样"。同步的目标是让新系统能解释旧系统的事实,而不是把旧系统的每个字段复制一遍。
- 事件而不是轮询全表 :主库发生变更时发事件,事件带
event_id、object_type、object_id、version、occurred_at、source。消费端按event_id幂等,重复消费不产生第二条记录。 - 版本号解决乱序:网络重试和并发会让事件乱序。消费端只接受高于本地版本的事件;低版本进日志,不覆盖。
- 失败进死信队列:重试三次仍失败的事件集中存放,附原始 payload 和错误码;不要静默丢弃,也不要用"下次全量同步"掩盖。
- 全量对账只在低峰做:每天或每周一次对账,比对数量、校验和、抽样字段;全量对账是兜底,不是实时同步的主路径。
- 冲突按字段类型处理:状态、负责人、权限这类字段以主库为准;描述、备注这类只追加的内容可保留双方;无法判断的进人工队列。不要把所有字段都交给"最后写入获胜"。

图 2:一条可追溯链路。工作项 ID 只负责定位,commit SHA 负责代码证据,构建和制品负责交付证据,审计记录负责把证据串起来。
私有化环境还要多一层:如果系统在隔离内网,公网 webhook 进不来,就要在内网或隔离区搭一个轻量 relay;事件签名、时间戳、重放窗口都要校验。服务器接同一套 NTP,时间偏差会让签名失效,也会让事件顺序失真。
规则五:用冻结窗口切时间,不用通知切时间
并行期最危险的不是同步失败,而是切换当天还有人往旧系统写。通知只能提醒,冻结才能阻断。
| 时间点 | 动作 | 通过条件 | 失败时 |
|---|---|---|---|
| T-14 天 | 完成字段、用户、仓库映射,做一次全量演练 | 映射覆盖率、抽样一致率达到约定值 | 延期,不带问题切换 |
| T-1 天 | 公告冻结范围,导出备份,关闭旧系统写权限 | 备份可恢复,关键人确认 | 回滚到旧系统 |
| T0 | 冻结 Jira 写入;迁移在途问题;新 Git 只接新提交 | 旧系统写请求为 0,新系统可建单 | 暂停切换,保留双读 |
| T+1 天 | 新工作只在新系统创建;旧 Jira 只读 | 新单量、构建量正常 | 开例外通道,限期关闭 |
| T+7 天 | 复核关联、权限、审计 | 关联完整率达标,孤儿引用有 owner | 补映射,不删记录 |
| T+30 天 | 退出并行期或延长 | 退出条件全部满足 | 延长并复盘 |

图 3:并行期切换时间轴。准备、冻结、只读三个阶段单向推进,每个阶段都有明确的通过条件。
冻结范围要写清楚:哪些项目、哪些字段、哪些自动化、哪些 API。只冻结页面不够,脚本和 webhook 也要停。
在途问题要有归属:已经打开的需求和缺陷,要么迁到新系统,要么在旧系统关闭并写迁移备注;不要留下"半开半关"的记录。
旧系统不删除:切只读、保留查询和审计,设置跳转链接;删除旧库会让历史证据消失。
回滚路径要演练:至少验证一次"旧系统恢复写入、新系统停止接收"的路径;没有回滚演练,冻结窗口就不算准备完成。
规则六:退出并行期要靠可复核的证据
并行期什么时候结束?不是大家口头说"都用新系统了",也不是旧 Jira 到期。退出要有可复核的证据,最好能写成查询。
- 写入证据:连续 14 天旧 Jira 没有新增问题、评论、状态变更;如果有例外,逐条有审批和关闭日期。
- 映射证据:在途问题、附件、评论、关联链接的映射覆盖情况;未映射项有 owner 和原因。
- 关联证据:随机抽样提交或合并请求,能从工作项追到 commit SHA、构建、制品;反向也能追回工作项。孤儿引用(找不到对应工作项的提交、合并请求或制品)要逐条可解释。
- 重复证据:同一业务对象没有两条有效记录;重复事件被幂等吞掉,不靠人工删数据。
- 权限证据:离职、转岗、外包账号已回收;旧系统只读权限和新系统最小权限一致。
- 审计证据:关键操作日志可导出,时间戳一致,保留周期满足公司或行业要求。
把这些检查做成一张退出看板:红、黄、绿三档。红色项不清零,不退出;黄色项要有 owner 和截止日期。退出条件不是"新系统功能齐全",而是"旧系统不再产生新事实,历史事实仍可追溯"。
14 天零写入、关键对象映射无遗漏、孤儿引用逐条解释,可以作为起点,再按团队的风险和监管要求调整。不要用"大家都登录新系统了"代替验收,登录量只能说明入口换了,不能说明数据已经收口。
私有化部署额外要补的三道检查
公有云上的集成经验,搬到私有化环境经常会失效。网络、身份、日志这三件事,必须在切换前单独验收。
网络与时间
内网 DNS、证书、代理和防火墙要先配置好。隔离环境里公网 webhook 进不来,就在内网或隔离区搭一个 relay,事件签名、时间戳和重放窗口都要校验。所有节点接同一套 NTP;时间偏差会让签名失效,也会让事件顺序失真。
身份与权限
Jira、Git、目录服务各有一套账号体系。并行期要先定身份源:LDAP、AD 还是 HR 系统,工号是否唯一,离职和转岗多久回收权限。空间、仓库、分支、目录四级权限要逐项复核;外包账号只给必要范围,不要用"先给管理员,后面再收"这种临时方案。
以 GitFox 为例,私有化部署下可以把空间、仓库、分支、目录权限和操作日志放在同一套管控里;具体配置以当前版本为准。能力是现成的,规则仍要写清楚:谁能在哪个空间建仓库、谁能合并主干、谁能改保护分支。
日志与备份
应用日志、审计日志、流水线日志分开保留,时间统一到同一时区或明确标注 UTC。备份清单不要只写数据库,代码仓库、附件、制品、配置和密钥都要覆盖;至少做一次恢复演练,确认备份不是"看起来有"。
结语:并行期不是长期架构
旧 Jira 与新 Git 并存,可以是几周,也可以是几个月,但不应该变成常态。并行期越长,双写、孤儿关联和权限漂移越多,最后不是迁不完,而是没人敢关旧系统。
把 6 条规则落成三样东西:一张字段级数据主权表、一张 ID 映射表、一张退出验收看板。每周复核一次,红色项不清零就不扩大范围。新 Git 平台负责代码事实,Jira 负责历史问题事实,映射层负责让两边可解释;三者各守边界,并行期才有终点。
如果新 Git 采用 GitFox 这类私有化平台,代码、评审、流水线、制品和审计记录可以落在同一套底座上,但迁移规则仍要自己定。工具能提供能力,不能替团队决定哪条数据算数。
本文事实核验参考了 Atlassian 的 Automation smart values - issues、Linking JIRA issues to a build 和 Jira Cloud Migration Assistant 故障排查文档。