Skip to content

JEP 357: Migrate from Mercurial to Git | 从 Mercurial 迁移到 Git

摘要

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

目标

  • 将所有单仓库 OpenJDK 项目从 Mercurial 迁移到 Git
  • 保留所有版本控制历史,包括标签
  • 根据 Git 最佳实践重新格式化提交信息
  • jcheckwebrevdefpath 工具迁移到 Git
  • 创建一个工具来翻译 Mercurial 和 Git 哈希值

非目标

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

  • 我们不会更改从 JBS 的 bug 系统。

  • 我们不会积极废弃现有的 Mercurial 仓库或采取其他行动过早地使指向仓库的许多 URL(如 JBS 中 bug 的注释中的 URL)失效。现有的主 Mercurial 仓库至少在定义的过渡期内将作为只读存档保留。长期来看,可能会实现一个 Mercurial URL 到 Git URL 的翻译器。

  • 本 JEP 不解决 OpenJDK Git 仓库是否将自托管或由外部提供商托管的问题。该问题是 JEP 369: Migrate to GitHub 的主题。

  • 我们不会提出对当前 JDK 开发过程的更改,尽管本 JEP 确实支持此类更改。

动机

迁移到 Git 主要有三个原因:

  1. 版本控制系统元数据的规模
  2. 可用的工具
  3. 可用的托管

已转换存储库的初步原型表明,版本控制元数据的规模显著减小。例如,根据所使用的 Mercurial 版本,使用 Git 的 jdk/jdk 存储库的 .git 目录大约为 300MB,而使用 Mercurial 的 .hg 目录大约为 1.2GB。元数据规模的减小节省了本地磁盘空间并缩短了克隆时间,因为通过网络传输的比特数更少了。此外,Git 还提供了 浅克隆 功能,该功能仅克隆历史记录的一部分,从而进一步减少了不需要完整历史记录的用户的元数据。

与 Mercurial 相比,与 Git 交互的工具要多得多:

  • 所有的文本编辑器都集成了 Git,无论是本地的还是插件形式的,包括 Emacs (magit 插件),Vim (fugitive.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 命令行工具强烈建议使用标题(单行后跟一个空行)。

  • 使用标题后,可以启用自由格式的正文。

  • Git 生态系统识别 尾随行(trailer),即与正文用新行分隔的行。例如,GitHubGitLab 都识别 Co-authored-by: 尾随行,并会识别出该提交有多个作者。

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

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

作者和提交者字段的内容将采用 Real-name <Email> 的形式,因为并非每个提交作者都是 OpenJDK Author。将使用特殊电子邮件地址来表示作者或提交者也是 OpenJDK Author:<openjdk-username>@openjdk.org

以下是一个 Git 提交消息的示例:

76543210: 启动 JVM 时崩溃

通过使用 Mutex 修复了 JVM 启动时的一个复杂竞态条件。

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。该工具使用由转换工具生成并提交到 Git 仓库的文件 .hgcommits。此文件包含一系列行,每行包含两个十六进制哈希值:第一个是 Mercurial 变更集的哈希值,第二个是转换该 Mercurial 变更集后得到的 Git 提交的哈希值。git-translate 工具只是简单地查询 .hgcommits 文件:

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

替代方案

继续使用 Mercurial。

测试

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

风险和假设

主要风险在于转换过程中可能引入错误。该风险将通过上文所述的严格验证来减轻。

依赖项