跳到主要内容

JEP 357: 从 Mercurial 迁移到 Git

QWen Max 中英对照 JEP 357: Migrate from Mercurial to Git

总结

将 OpenJDK 社区的源代码仓库从 Mercurial (hg) 迁移到 Git。

目标

  • 将所有单一仓库的 OpenJDK 项目从 Mercurial 迁移到 Git
  • 保留所有的版本控制历史记录,包括标签
  • 根据 Git 最佳实践重新格式化提交信息
  • jcheckwebrevdefpath 工具移植到 Git
  • 创建一个工具以在 Mercurial 和 Git 哈希之间进行转换

非目标

  • 我们不会迁移多仓库的 OpenJDK 项目,例如 JDK 8 Updates Project。这些项目可以在它们合并到单一仓库时再迁移到 Git。

  • 我们不会更改现有的错误跟踪系统 JBS

  • 我们不会激进地停用现有的 Mercurial 仓库,也不会采取其他措施过早地使指向这些仓库的众多 URL(如 JBS 中的错误评论中的链接)失效。现有的主 Mercurial 仓库至少会在一个明确的过渡期内保留为只读存档。从长远来看,可能会设置一个 Mercurial URL 到 Git URL 的转换器。

  • 本 JEP 不涉及 OpenJDK Git 仓库是自托管还是由外部提供商托管的问题。该问题在 JEP 369: Migrate to GitHub 中讨论。

  • 我们不会提议对当前的 JDK 开发流程进行更改,不过本 JEP 确实为这样的更改提供了支持。

动机

迁移到 Git 的三个主要原因如下:

  1. 版本控制系统元数据的大小
  2. 可用的工具
  3. 可用的托管服务

转换后的存储库的初始原型显示出版本控制元数据的大小显著减少。例如,使用 Git 时 jdk/jdk 存储库的 .git 目录大约为 300 MB,而使用 Mercurial 时 .hg 目录约为 1.2 GB(具体大小取决于所使用的 Mercurial 版本)。元数据的减少节省了本地磁盘空间,并缩短了克隆时间,因为通过网络传输的数据量减少了。Git 还提供了浅克隆功能,只克隆部分历史记录,从而为那些不需要完整历史记录的用户进一步减少元数据。

与 Mercurial 相比,用于与 Git 交互的工具有很多:

  • 所有文本编辑器都具有 Git 集成,无论是原生集成还是通过插件实现,包括 Emacsmagit 插件)、Vimfugitive.git 插件)、VS Code(内置)和 Atom(内置)。

  • 几乎所有集成开发环境 (IDE) 也都开箱即用地集成了 Git,包括 IntelliJ(内置)、Eclipse(内置)、NetBeans(内置)和 Visual Studio(内置)。

  • 还有多种桌面客户端可用于在本地与 Git 仓库进行交互。

最后,有许多选项可用于托管 Git 仓库,无论是自托管还是作为服务托管。

描述

我们已经制作了一个将 Mercurial 仓库转换为 Git 仓库的程序原型。该程序使用 git-fast-import 协议将 Mercurial 的变更集导入到 Git 中,并调整现有的提交信息以符合 Git 最佳实践。Mercurial 的 jdk/jdk 仓库的提交信息具有以下结构:

JdkHgCommitMessage : BugIdLine+ SummaryLine? ReviewersLine ContributedByLine?

BugIdLine : /[0-9]8/ ": " Text

SummaryLine : "Summary: " Text

ReviewersLine : "Reviewed-by: " Username (", " Username)* "\n"

ContributedByLine : "Contributed-by: " Text

Username : /[a-z]+/

Text : /[^\n]+/ "\n"

Git jdk/jdk 仓库的提交信息将具有略有不同的结构:

JdkGitCommitMessage : BugIdLine+ Body? Trailers

BugIdLine : /[0-9]8/ ": " Text

Body : BlankLine Text*

Trailers : BlankLine Co-authors? Reviewers

Co-authors : (BlankLine Co-author )+

Co-author : "Co-authored-by: " Real-name <Email>

Reviewers : "Reviewed-by: " Username (", " Username)* "\n"

BlankLine = "\n"

Username : /[a-z]+/

Text : /[^\n]+/ "\n"

更改消息结构的原因是:

  • Git CLI 工具强烈鼓励使用标题(一行文本后跟一个空行)。

  • 使用标题后便可编写自由格式的正文。

  • Git 生态系统可识别尾部信息,即与正文之间有一个换行符分隔的行。例如,GitHubGitLab 都能识别 Co-authored-by: 尾部信息,并会识别出该提交有多个作者。

Git 在提交元数据中使用了一个额外的字段来表示提交的提交者,这与作者不同。我们将使用提交者字段来表示赞助:在发生赞助提交的情况下,作者将在提交的 author 字段中命名,而赞助者将在 committer 字段中命名。如果赞助者也是共同作者,那么将添加适当的 Co-authored-by 尾部信息,这是我们无法在现有的 Mercurial 消息结构中捕获的情况。

不同的提交者字段的另一个可能用途是识别从特性发布到更新发布的反向移植提交,这些提交通常由原提交的作者之外的人完成。

作者和提交者字段的内容形式为 真实姓名 <电子邮件>,因为并非每个提交的作者都是 OpenJDK 作者。将使用一个特殊的电子邮件地址来表明某个作者或提交者同时也是 OpenJDK 作者:<openjdk-用户名>@openjdk.org

下面是一个 Git 提交信息的示例:

76543210: Crash when starting the JVM

Fixed a tricky race condition when the JVM is starting up by using a Mutex.

Co-authored-by: Robin Westberg <rwestberg@openjdk.org>
Reviewed-by: darcy

此类提交的作者和提交者字段为:

Author: Erik Duveblad <ehelin@openjdk.org>
Commit: Erik Duveblad <ehelin@openjdk.org>

在转换过程中,当作者列在 Contributed-by: 行中时,该提交将被视为由他人赞助。在这种情况下,Contributed-by: 行中的第一个人将被视为作者,赞助者将被视为提交者,而任何其他贡献者将被视为共同作者。

转换后的存储库示例可在 https://github.com/openjdk/ 查看。

工具

我们已经原型设计了 Mercurial 工具的向后兼容端口,这些工具包括 jcheckwebrevdefpath

我们还为一个新工具制作了原型,git-translate。这个工具使用一个名为 .hgcommits 的文件,该文件由转换工具生成并提交到 Git 仓库中。此文件包含一系列行,每行包含两个十六进制哈希值:第一个是 Mercurial 变更集的哈希值,第二个是由该 Mercurial 变更集转换得到的 Git 提交的哈希值。工具 git-translate 仅查询文件 .hgcommits

$ git translate --to-hg 0f8927e8b5bf88e7e2c7c453b4cd75e01eeccaf4
bd613b97c7c88658801b0f0c603a55345dfef022
$

替代方案

继续使用 Mercurial。

测试

上面描述的 .hgcommits 映射文件可用于验证给定提交的所有元数据是否正确转换,还可用于验证两个提交的源代码树是否相同。

风险与假设

突出的风险是转换过程中可能会引入错误。该风险将通过上述严格的验证来减轻。

依赖