跳转到主内容

Electron 的补丁

Electron是基于两个主要的上游项目:Chromium和Node.js 这些项目都有自己的依赖。 我们尽最大努力完全按照原样使用这些依赖项,但有时如果不修补这些上游依赖项以适应我们的用例,我们就无法实现我们的目标。

打补丁的理由

Electron中的每个补丁都是一个维护负担。 当上游代码更改时,补丁可能会出现错误——有时甚至没有补丁冲突或编译错误。 这是一项不断的努力,以使我们的补丁随时更新和有效。 因此,我们努力将我们的补丁数量保持在最低限度。 为此目的,每个补丁都必须在其Commit信息中说明其存在的理由。 这个原因必须是下列原因之一:

  1. 补丁是临时性的,意在通过上游Commit或以其他方式最终移除。 包含一个链接到上游的 PR 或代码审核(如果可用)。 或核实补丁是否仍然需要的程序。

  2. 补丁允许代码在 Electron 环境中编译,但不能添加到上游,因为它是专门用于 Electron 的(例子:补丁到 Chrome 的 Profile 引用)。 包含为什么这个更改无法在没有补丁的情况下实现的理由(例如通过Subclassing或copying the code)。

  3. 补丁使Electron特定功能的更改从根本上与上游不兼容。

  4. 一般情况下我们与之合作的所有上游项目都是友好的,并且常常乐于接受那些让有关代码同时与 Electron 和上游项目兼容的重构。 (见例见) 在 Chromium 中进行这个更改 ,使我们能够移除一个做同样事情的补丁。 或 Node中的这个补丁 更改对于Node来说没有操作(no-op)但在Electron中修复了一个错误。 我们应该尽可能改变上游,并且避免无限期存在的补丁

补丁系统

如果你发现自己处于不幸的状态,不得不进行更改,且只能通过修补一个上游项目进行更改, 您需要知道如何在 Electron 中管理补丁。

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

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
│   ⋮

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.

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.

用法

添加新补丁

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

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.

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).

编辑现有补丁

$ 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

Note that the ^ symbol can cause trouble on Windows. The workaround is to either quote it "[COMMIT_SHA]^" or avoid it [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

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).

解决冲突

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

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.