跳到主要内容

JEP 296:将 JDK 森林整合到一个单一的存储库中

QWen Max 中英对照 JEP 296 Consolidate the JDK Forest into a Single Repository

概述

为了简化和优化开发,将 JDK 代码库的众多存储库合并为一个单一的存储库。

非目标

将 FX 源代码添加到 JDK 代码库并不在提案范围内。

动机

多年以来,JDK 的完整代码库被拆分到众多的 Mercurial 仓库中。在 JDK 9 中有八个仓库:root、corba、hotspot、jaxp、jaxws、jdk、langtools 和 nashorn。

虽然这种多仓库模型有一些优势,但它也有许多缺点,无法很好地支持各种理想的源代码管理操作。特别是,它无法对相互依赖的变更集跨仓库执行原子提交。例如,如果一个错误修复或 RFE 的代码跨越了 jdk 和 hotspot 两个仓库,那么对这两个仓库的更改无法在托管这两个不同仓库的森林中原子地完成。跨多个仓库的更改是很常见的;在 JDK 仓库森林中,超过 1,100 个 Bug ID 被跨仓库重复使用。这 1,100 多个跨仓库的 Bug 只是逻辑上跨仓库 Bug 数量的一个下限,因为一些工程师会使用不同的 Bug ID 来推送到不同的仓库。

Mercurial 仓库的划分与工程统一性之间的不匹配削弱了现代源代码管理的主要优势之一:跟踪文件集合的变更,而不仅仅是单个文件的变更。相应地,SCM 事务与逻辑事务之间的这种不匹配也使 Mercurial bisect 等工具的使用变得更加复杂。

各个独立的代码仓库并没有与整个 JDK 分开的开发周期;所有代码仓库都随着 JDK 的发布周期同步推进。大量的代码仓库对新开发者造成了比必要门槛更高的障碍,并导致了诸如“获取源码”脚本之类的变通方法。

描述

为了解决这些问题,已经开发了一个合并森林的原型。该原型可在以下位置获取:

http://hg.openjdk.java.net/jdk10/consol-proto/

用于创建原型的一些辅助转换脚本作为 unify.zip 附带。

在原型中,八个代码库已通过自动转换脚本合并为一个代码库,该脚本在每个文件的级别保留了历史记录,并且在用于标记 JDK 升级的标签处同步了整合后的代码库。变更集的注释和创建日期也得以保留。

该原型还有另一层次的代码重组。在整合后的森林中,Java 模块的代码通常会合并到一个顶级的 src 目录下。例如,当前在 JDK 森林中,存在基于模块的目录,比如:

$ROOT/jdk/src/java.base
...
$ROOT/langtools/src/java.compiler
...

在整合后的森林中,此代码反而被组织为

$ROOT/src/java.base
$ROOT/src/java.compiler
...

因此,从存储库的根目录开始,模块中源文件的相对路径在整合和 src 目录合并后会被保留。

一个类似但不那么激进的重组也针对测试目录进行,以实现从...的转变。

$ROOT/jdk/test/Foo.java
$ROOT/langtools/test/Bar.java

$ROOT/test/jdk/Foo.java
$ROOT/test/langtools/Bar.java

由于当前这一工作还属于原型,因此并不是所有部分都已完全完成,并且在某些方面还可以改进适配和完成度。HotSpot C/C++ 源代码已移至共享的 src 目录,与模块化的 Java 代码放在一起。

虽然回归测试将使用原型的当前状态运行,但 jtreg 配置文件的进一步整合是可能的,并且可能会在未来进行。

替代方案

一个替代方案是简单地保留在当前的代码仓库集合中。在迁移到单一代码仓库时,可能已经丢弃了部分或全部代码仓库的历史记录,但这一做法被拒绝了。虽然考虑过整合核心子集的代码仓库,但为了单一代码仓库的简洁性,最终还是选择了拒绝这种方案。

测试

为了验证文件内容,对每个升级标签使用一个脚本来验证在该标签下分离的代码库的内容是否与在该标签下合并的代码库的内容相匹配。对于最近的 JDK 9 标签,比较了在同一标签下的分离代码库和合并代码库的构建结果;只有细微且可解释的差异。

风险与假设

上述测试应该可以减轻文件损坏和构建错误的最严重风险。虽然在原型中已完成整合所需的大部分工作,但在整合投入生产之前,可能无法完成各种较小的支持功能。在 Mercurial 意义上,整合前后的代码库并无关联。对于前向和后向端口,必须使用差异(具有适当调整的路径),而不是导出和导入变更集。