Skip to main content

Electron 中的补丁

¥Patches in Electron

Electron 建立在两个主要的上游项目之上:Chromium 和 Node.js。这些项目中的每一个也都有一些自己的依赖。我们尽力按原样使用这些依赖,但有时如果不修补这些上游依赖以适应我们的用例,我们就无法实现我们的目标。

¥Electron is built on two major upstream projects: Chromium and Node.js. Each of these projects has several of their own dependencies, too. We try our best to use these dependencies exactly as they are but sometimes we can't achieve our goals without patching those upstream dependencies to fit our use cases.

补丁理由

¥Patch justification

Electron 中的每个补丁都是维护负担。当上游代码发生变化时,补丁可能会损坏 - 有时甚至没有补丁冲突或编译错误。我们需要不断努力,使我们的补丁设置保持最新且有效。因此,我们努力将补丁数量保持在最低限度。为此,每个补丁都必须在其提交消息中描述其存在的原因。该原因必须是以下之一:

¥Every patch in Electron is a maintenance burden. When upstream code changes, patches can break—sometimes without even a patch conflict or a compilation error. It's an ongoing effort to keep our patch set up-to-date and effective. So we strive to keep our patch count at a minimum. To that end, every patch must describe its reason for existence in its commit message. That reason must be one of the following:

  1. 该补丁是临时的,旨在(或已经)提交到上游或最终删除。包括指向上游 PR 或代码审查(如果有)的链接,或者用于验证稍后是否仍需要该补丁的程序。

    ¥The patch is temporary, and is intended to be (or has been) committed upstream or otherwise eventually removed. Include a link to an upstream PR or code review if available, or a procedure for verifying whether the patch is still needed at a later date.

  2. 该补丁允许代码在 Electron 环境中编译,但无法上游,因为它是 Electron 特定的(例如修补对 Chrome 的 Profile 的引用)。包括关于为什么没有补丁就无法实现更改的推断(例如,通过子类化或复制代码)。

    ¥The patch allows the code to compile in the Electron environment, but cannot be upstreamed because it's Electron-specific (e.g. patching out references to Chrome's Profile). Include reasoning about why the change cannot be implemented without a patch (e.g. by subclassing or copying the code).

  3. 该补丁对 Electron 的功能进行了特定的更改,这些更改从根本上与上游不兼容。

    ¥The patch makes Electron-specific changes in functionality which are fundamentally incompatible with upstream.

一般来说,我们合作的所有上游项目都是友好的人,并且通常很乐意接受重构,使有问题的代码与 Electron 和上游项目兼容。(例如,参见 Chromium 中的 this 更改,它允许我们删除执行相同操作的补丁,或者 Node 中的 this 更改,这对 Node 来说是无操作的,但修复了 Electron 中的错误。)我们应该尽可能地向上游进行更改,并避免无限期的补丁。

¥In general, all the upstream projects we work with are friendly folks and are often happy to accept refactorings that allow the code in question to be compatible with both Electron and the upstream project. (See e.g. this change in Chromium, which allowed us to remove a patch that did the same thing, or this change in Node, which was a no-op for Node but fixed a bug in Electron.) We should aim to upstream changes whenever we can, and avoid indefinite-lifetime patches.

补丁系统

¥Patch system

如果你发现自己处于不幸的境地,必须进行只能通过修补上游项目才能进行的更改,那么你需要知道如何在 Electron 中管理补丁。

¥If you find yourself in the unfortunate position of having to make a change which can only be made through patching an upstream project, you'll need to know how to manage patches in Electron.

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

¥All patches to upstream projects in Electron are contained in the patches/ directory. Each subdirectory of patches/ contains several patch files, along with a .patches file which lists the order in which the patches should be applied. Think of these files as making up a series of git commits that are applied on top of the upstream project after we check it out.

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 文件中。

¥To help manage these patch sets, we provide two tools: git-import-patches and git-export-patches. git-import-patches imports a set of patch files into a git repository by applying each patch in the correct order and creating a commit for each one. git-export-patches does the reverse; it exports a series of git commits in a repository into a set of files in a directory and an accompanying .patches file.

边注:我们使用 .patches 文件来维护应用补丁的顺序,而不是在每个文件前面添加像 001- 这样的数字,是因为它减少了与补丁顺序相关的冲突。它可以防止两个 PR 在系列末尾都添加具有相同数字的补丁并最终合并导致重复标识符的情况,并且还可以减少在中间添加或删除补丁时的流失。 系列。

¥Side note: the reason we use a .patches file to maintain the order of applied patches, rather than prepending a number like 001- to each file, is because it reduces conflicts related to patch ordering. It prevents the situation where two PRs both add a patch at the end of the series with the same numbering and end up both getting merged resulting in a duplicate identifier, and it also reduces churn when a patch is added or deleted in the middle of the series.

用法

¥Usage

添加新补丁

¥Adding a new patch

$ 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 会忽略任何未提交的文件,因此如果你希望导出更改,则必须创建提交。提交消息的主题行将用于派生补丁文件名,提交消息的正文应包括补丁存在的原因。

¥NOTE: git-export-patches ignores any uncommitted files, so you must create a commit if you want your changes to be exported. The subject line of the commit message will be used to derive the patch file name, and the body of the commit message should include the reason for the patch's existence.

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

¥Re-exporting patches will sometimes cause shasums in unrelated patches to change. This is generally harmless and can be ignored (but go ahead and add those changes to your PR, it'll stop them from showing up for other people).

编辑现有补丁

¥Editing an existing patch

$ 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

删除补丁

¥Removing a patch

$ 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 之前的提交)。

¥Note that git-import-patches will mark the commit that was HEAD when it was run as refs/patches/upstream-head. This lets you keep track of which commits are from Electron patches (those that come after refs/patches/upstream-head) and which commits are in upstream (those before refs/patches/upstream-head).

解决冲突

¥Resolving conflicts

更新上游依赖时,补丁可能无法完全应用。通常,冲突可以通过 git 通过三向合并自动解决。你可以通过传递 -3 参数来指示 git-import-patches 使用 3 路合并算法:

¥When updating an upstream dependency, patches may fail to apply cleanly. Often, the conflict can be resolved automatically by git with a 3-way merge. You can instruct git-import-patches to use the 3-way merge algorithm by passing the -3 argument:

$ 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 继续应用其余补丁。

¥If git-import-patches -3 encounters a merge conflict that it can't resolve automatically, it will pause and allow you to resolve the conflict manually. Once you have resolved the conflict, git add the resolved files and continue to apply the rest of the patches by running git am --continue.