跳到主要内容

Electron 中的补丁

Electron 构建于两个主要的上游项目之上:Chromium 和 Node.js。 这些项目中的每一个也有若干个自己的依赖项。 我们尽力完全按原样使用这些依赖项,但有时我们无法在不修补这些上游依赖项以适应我们的用例的情况下实现我们的目标。

补丁理由

Electron 中的每个补丁都是维护负担。 当上游代码更改时,补丁可能会中断——有时甚至没有补丁冲突或编译错误。 让我们的补丁集保持最新和有效是一项持续的努力。 因此,我们力求将补丁数量保持在最低限度。 为此,每个补丁都必须在其提交消息中描述其存在的原因。 该原因必须是以下之一

  1. 该补丁是临时的,旨在(或已经)提交到上游或最终以其他方式删除。 如果可用,请包含指向上游 PR 或代码审查的链接,或用于验证稍后是否仍需要该补丁的程序。
  2. 该补丁允许代码在 Electron 环境中编译,但无法上游,因为它特定于 Electron(例如,修补掉对 Chrome 的 Profile 的引用)。 包括关于为什么不能在没有补丁的情况下实现更改(例如,通过子类化或复制代码)的理由。
  3. 该补丁对 Electron 特定的功能进行更改,这些功能从根本上与上游不兼容。

一般来说,我们合作的所有上游项目都是友好的,并且通常很乐意接受重构,从而使有问题的代码与 Electron 和上游项目兼容。 (例如,请参阅 Chromium 中的此项 更改,它使我们能够删除执行相同操作的补丁,或 Node 中的此项 更改,这对 Node 来说是空操作,但修复了 Electron 中的一个错误。) 我们应该尽可能地将更改提交到上游,并避免无限期寿命的补丁

补丁系统

如果您发现自己处于不得不进行更改的不幸境地,而这种更改只能通过修补上游项目来完成,那么您需要了解如何在 Electron 中管理补丁。

Electron 中对上游项目的所有补丁都包含在 patches/ 目录中。 patches/ 的每个子目录都包含若干个补丁文件,以及一个 .patches 文件,其中列出了应应用补丁的顺序。 将这些文件视为构成一系列 git 提交,这些提交在我们检出上游项目后应用于其之上。

patches
├── config.json <-- this describes which patchset directory is applied to what project
├── chromium
│   ├── .patches
│   ├── accelerator.patch
│   ├── add_contentgpuclient_precreatemessageloop_callback.patch
│ ⋮
├── node
│   ├── .patches
│   ├── add_openssl_is_boringssl_guard_to_oaep_hash_check.patch
│   ├── build_add_gn_build_files.patch
│   ⋮

为了帮助管理这些补丁集,我们提供了两个工具:git-import-patchesgit-export-patchesgit-import-patches 通过按正确的顺序应用每个补丁并为每个补丁创建一个提交,将一组补丁文件导入到 git 存储库中。 git-export-patches 执行相反的操作;它将存储库中的一系列 git 提交导出到目录中的一组文件和一个随附的 .patches 文件中。

旁注:我们使用 .patches 文件来维护应用补丁的顺序,而不是像 001- 那样在每个文件前加上数字的原因是,因为它减少了与补丁顺序相关的冲突。 它避免了两个 PR 都在系列末尾添加具有相同编号的补丁,并且最终都被合并导致重复标识符的情况,并且还减少了在系列中间添加或删除补丁时的变动。

用法

添加新补丁

$ cd src/third_party/electron_node
$ vim some/code/file.cc
$ git commit
$ ../../electron/script/git-export-patches -o ../../electron/patches/node

注意git-export-patches 忽略任何未提交的文件,因此如果您希望导出更改,则必须创建一个提交。 提交消息的主题行将用于派生补丁文件名,提交消息的正文应包括补丁存在的原因。

重新导出补丁有时会导致不相关的补丁中的 shasum 发生更改。 这通常是无害的,可以忽略(但继续并将这些更改添加到您的 PR 中,这将阻止它们为其他人显示)。

编辑现有补丁

$ cd src/v8
$ vim some/code/file.cc
$ git log
# Find the commit sha of the patch you want to edit.
$ git commit --fixup [COMMIT_SHA]
$ git rebase --autosquash -i [COMMIT_SHA]^
$ ../electron/script/git-export-patches -o ../electron/patches/v8

请注意,^ 符号 可能会在 Windows 上引起问题。 解决方法是引用它 "[COMMIT_SHA]^" 或避免它 [COMMIT_SHA]~1

删除补丁

$ vim src/electron/patches/node/.patches
# Delete the line with the name of the patch you want to remove
$ cd src/third_party/electron_node
$ git reset --hard refs/patches/upstream-head
$ ../../electron/script/git-import-patches ../../electron/patches/node
$ ../../electron/script/git-export-patches -o ../../electron/patches/node

请注意,git-import-patches 会将运行时的 HEAD 提交标记为 refs/patches/upstream-head。 这使您可以跟踪哪些提交来自 Electron 补丁(那些在 refs/patches/upstream-head 之后出现的提交)以及哪些提交在上游(那些在 refs/patches/upstream-head 之前出现的提交)。

解决冲突

当更新上游依赖项时,补丁可能无法干净地应用。 通常,冲突可以通过 git 使用 3 向合并自动解决。 您可以指示 git-import-patches 通过传递 -3 参数来使用 3 向合并算法

$ cd src/third_party/electron_node
# If the patch application failed midway through, you can reset it with:
$ git am --abort
# And then retry with 3-way merge:
$ ../../electron/script/git-import-patches -3 ../../electron/patches/node

如果 git-import-patches -3 遇到无法自动解决的合并冲突,它将暂停并允许您手动解决冲突。 解决冲突后,git add 已解决的文件,并通过运行 git am --continue 继续应用其余补丁。