从 Redmine 迁出,首先是数据问题,其次才是软件问题。工作项列表是最容易复制的部分,真正要紧的是历史:谁改了状态、日期为什么推迟、客户在第三条评论里说了什么、大家最终认可的是哪一版维基页面。Specivo 的迁移工具就是为了把这些历史连同人名一起完整带过去,并且明确告诉你哪些内容没有带过来。
适合谁
在自己的服务器上运行 Redmine、并希望继续保持这种模式的团队,规模不限。Specivo 是一个私有化部署的项目管理平台,集项目跟踪、知识库和自动化于一体。它运行在你自己的基础设施上,数据不出内网,AI 怎么用也由你决定:接云端服务、跑本地模型,或者在物理隔离网络里完全不用 AI。
团队离开 Redmine 的原因通常不外乎几种:依赖的某个插件拖住了升级,急需的功能只在付费分支里有,或者想让 AI 智能体直接读写结构化的工作项数据,而不必再外挂一套服务。不管原因是什么,迁移都不该从丢掉历史开始。
能迁移哪些内容
导出工具直接读取 Redmine 的数据库,在一个一致的快照里完成读取,并生成一个导入包。Specivo 加载这个导入包时沿用原有标识,因此迁移后项目、编号和链接都能对上。
- 项目与子项目,包括父项目和已启用的模块。
- 追踪器、状态和优先级,以及工时活动和角色,包括每个角色对用户和工时记录的可见性设置。
- 用户与用户组,包括每个用户的默认邮箱、状态和语言,以及用户组成员。
- 项目成员关系及其角色。只迁移直接授予的成员关系;通过用户组获得的访问权限会在导入后由用户组重新推导。
- 带完整历史的工作项。评论、私有备注和字段变更按原顺序迁移,保留原作者和时间戳,涉及的人员和记录都按名称显示。
- 评论与私有备注作为历史的一部分一并迁移。私有工作项仍保持私有。
- 附件与内嵌图片,从 Redmine 的 files 目录复制,相同文件只存一份。
- 关联与父任务,包括指向其他项目、或指向另外单独导出的导入包中工作项的关联。
- 工时记录,包括活动和用户。
- 版本与工作项类别。
- 自定义字段,包括字段值、可选项,以及字段适用的追踪器和项目。每个字段保留 Redmine 中的名称;用户类型或版本类型的字段会向有权查看的人按名称显示对应的人员或版本。
- 关注者,包括工作项和维基页面上的关注者。
- 维基页面及其全部修订版本,包括每个修订版本的作者、页面附件,以及 Redmine 在页面重命名后留下的重定向。
- 工作项的预计工时。
- 公开项目中非成员可读的内容,作为导入包中的一个单独文件。
文本会从 Textile 转换为 Markdown。对其他工作项的引用(如 #123)会变成指向该工作项新编号的链接,前提是该工作项在本次导入包或之前的导入包中。
哪些内容不会迁移,以及如何查看
Redmine 的部分功能在 Specivo 中没有对应项,有些数据也无法精确映射。但不会有任何内容被悄悄丢掉:导入包的清单文件列出所有被略过的内容,加载时导入报告会再次显示。例如:
- 代码库、论坛等模块;
- 按项目设置的优先级和工时活动;
- 工作项以外对象上的自定义字段;
- 版本、文档和论坛帖子上的附件;
- Specivo 没有的关联类型;
- 在 Redmine 的 files 目录中找不到文件的附件;
- 没有日期的工时记录。
运行导出前,还有几个行为值得了解:
- 如果引用的工作项要在之后才加载,引用会先保留为纯文本
#N,直到该工作项被加载。你可以调整加载顺序,让被引用的工作项先加载;也可以之后再加载其余部分,引用会在那次加载时自动变成链接。 - 如果描述在 Redmine 中被编辑过,历史记录里保存的新旧文本仍是 Redmine 的 Textile 格式。
- 如果某个值指向 Specivo 中不存在的对象(例如在 Redmine 中已删除的版本),历史记录中会显示为空值;父工作项除外,它会保留为
#123的形式。 - 在 Redmine 中已计划删除的项目会按活动项目导出。
迁移流程
- 导出。在能访问 Redmine 数据库的机器上,用一个只读的数据库账号运行工具。它会生成一个目录(或
.zip文件),每种记录一个文件,外加附件。 - 校验。检查导入包是否有架构错误、失效引用、缺失或被改动的文件以及数量不符,期间不会向 Specivo 写入任何内容。
- 试运行。Specivo 在一个最终必定回滚的事务中加载整个导入包,并报告将使用的项目标识、冲突情况、所有会跳过的内容及原因。
- 加载。正式加载同一个导入包。加载中断后可以续传。
- 核对。把 Specivo 中的数量和几个工作项与 Redmine 对照,确认无误后切换。
在一台能访问 Redmine 数据库和 files 目录的机器上,按发布标签安装工具:
uv tool install git+https://github.com/specivo/redmine-migration-tool@v0.1.0
然后依次导出、校验、加载:
# 1. Export (on a host that can reach Redmine's database and files directory)
export REDMINE_DB_URL='postgresql://redmine_reader:[email protected]/redmine'
specivo-redmine-migration \
--files-dir /var/lib/redmine/files \
--instance tracker.example.com \
--out redmine-export \
--validate
# 2 to 4. On the Specivo side, using the bundle directory
python -m specivo.cli.import_data --source bundle --path redmine-export --validate
python -m specivo.cli.import_data --source bundle --path redmine-export --dry-run
python -m specivo.cli.import_data --source bundle --path redmine-export
导出时用 --instance 给你的 Redmine 实例起一个可识别的名称。Specivo 会据此记住每条记录对应到了哪条新记录,这样之后再对同一个实例导出并加载时,只会新增新记录。
逐个项目迁移
大型实例,或者希望分阶段迁移的团队,可以用 --project 每次只导出一个项目,然后按顺序加载各个导入包。第一次之后的每次加载都加上 --continue-import,并通过共享的链接文件(--links-file)记录那些等待尚未加载项目的引用,等对应项目加载后自动解析。同一来源的每次加载都要使用同一个链接文件。
支持的版本与数据库
工具已在 PostgreSQL 16 和 MySQL 8.4 上针对 Redmine 7.0.1 测试通过。它需要 Python 3.12 或更高版本,直接读取这两种数据库,因此无需开启 Redmine 的 REST API。
前提条件与安全性
- 只在你自己的服务器上运行。导出和加载都在你控制的基础设施上进行。工具把导入包写到你的磁盘上,不向任何地方发送数据。文件由你自己通过自选的渠道转移。
- 对 Redmine 只读。给工具一个只能
SELECT的数据库账号。导出在一个只读事务中完成,不会改动 Redmine。 - 每次加载前先试运行。在写入任何记录之前,你就能看到完整结果,包括哪些内容会被跳过。
- Specivo 0.11.0 或更高版本才能加载导入包。内置的 Redmine 导入器已在该版本移除,由这个工具取代。
包含密码的导入包属于敏感数据,详见下文。
常见问题
迁移期间 Redmine 可以继续运行吗?
可以。导出只做读取。对于大型实例,建议在只读副本上或业务低峰时段运行,因为读取快照会在整个导出过程中一直保持。临近切换时,用同一个实例名称再导出一次,并加上 --continue-import 加载。第一次加载之后新增的记录会被补进来;已经导入过的记录会跳过而不是更新,所以第一次加载后对已有工作项的修改不会覆盖 Specivo 中的数据。规划切换时,请确保大家最终依赖的是最后一次加载的结果。
可以重复导入吗?
可以。带 --continue-import 再次加载同一个导入包,不会重复创建已存在的内容。如果某次运行中途停止,用 --resume 可以从停止处继续。
用户和密码怎么处理?
默认情况下,每个导入的账号首次登录时都必须设置新密码,管理员也会作为普通账号导入。如果希望大家沿用 Redmine 密码,导出时加上 --import-passwords,加载时也带同一选项,并且目标 Specivo 需要启用对应的密码哈希插件。管理员始终需要设置新密码。通过 LDAP 等外部目录登录的账号在 Redmine 中没有本地密码,导入包里自然也没有,报告中会列出这些账号。包含密码的导入包要像 Redmine 数据库副本一样妥善保护:导入完成后立即删除。
插件怎么办?
工具读取的是 Redmine 的核心表和 files 目录。由 Redmine 本身处理的模块(如代码库和论坛)会被标记为未迁移。插件存放在自有表中的数据不会被读取,所以在依赖任何插件数据之前,请先查看导出报告和清单文件。
必须一次性全部迁移吗?
不必。可以按项目导出,再按顺序加载各个导入包,方法见上文。
从哪里开始
- 先搭一个 Specivo 实例。按照 Docker 安装指南 大约十分钟就能完成,不会碰你的 Redmine。
- 用
--project导出一个小项目,对它做校验和试运行。 - 阅读报告,调整你不认可的地方,再来一遍。
- 准备好之后,执行完整的导出和加载。
迁移工具是开源的,托管在 github.com/specivo/redmine-migration-tool,那里有发布说明和安装步骤。Specivo 部署后如何运行,请参阅 Specivo 文档;如果你的数据必须留在无法访问互联网的网络中,离线部署指南 介绍了相应的做法。
Redmine 多年来功不可没,对很多团队来说它还能再用上几年。等到该迁移的时候,历史应该跟你一起走。