跳到主要內容

Electron 中的 Patches

Electron 建構於兩個主要的上游專案:Chromium 和 Node.js。這些專案各自也有一些自己的依賴項目。我們盡力完全按照現狀使用這些依賴項目,但有時我們必須 patch 這些上游依賴項目才能達成我們的目標,以符合我們的使用案例。

Patch 的理由

Electron 中的每個 patch 都是維護負擔。當上游程式碼變更時,patch 可能會損壞,有時甚至不會出現 patch 衝突或編譯錯誤。保持我們的 patch 集是最新的且有效是一項持續的努力。因此,我們力求將 patch 數量保持在最低限度。為此,每個 patch 的 commit 訊息都必須描述其存在的原因。該原因必須是以下之一

  1. 此 patch 是暫時性的,旨在(或已經)commit 到上游,或最終移除。如果有的話,請包含指向上游 PR 或程式碼審查的連結,或驗證稍後是否仍需要此 patch 的程序。
  2. 此 patch 允許程式碼在 Electron 環境中編譯,但由於它是 Electron 特有的(例如,patch 掉對 Chrome 的 Profile 的參考),因此無法上游化。包含關於為什麼無法在沒有 patch 的情況下實作變更(例如,透過子類別化或複製程式碼)的理由。
  3. 此 patch 對功能進行了 Electron 特有的變更,而這些變更與上游從根本上不相容。

一般來說,我們合作的所有上游專案都是友善的團隊,並且通常很樂意接受重構,使相關程式碼與 Electron 和上游專案相容。(例如,請參閱 Chromium 中的變更,它允許我們移除一個執行相同操作的 patch,或 Node 中的變更,它對於 Node 來說是 no-op,但修復了 Electron 中的一個錯誤。)我們應該盡可能將變更上游化,並避免無限期存在的 patch

Patch 系統

如果您發現自己處於不得不進行變更的不幸位置,而該變更只能透過 patch 上游專案來完成,那麼您需要了解如何在 Electron 中管理 patch。

Electron 中對上游專案的所有 patch 都包含在 patches/ 目錄中。patches/ 的每個子目錄都包含多個 patch 檔案,以及一個 .patches 檔案,其中列出了應套用 patch 的順序。將這些檔案視為構成一系列 git commit,這些 commit 在我們 check 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
│   ⋮

為了幫助管理這些 patch 集,我們提供了兩個工具:git-import-patchesgit-export-patchesgit-import-patches 透過以正確的順序套用每個 patch 並為每個 patch 建立 commit,將一組 patch 檔案匯入到 git 儲存庫中。git-export-patches 執行相反的操作;它將儲存庫中的一系列 git commit 匯出到目錄中的一組檔案和一個隨附的 .patches 檔案中。

附註:我們使用 .patches 檔案來維護已套用 patch 的順序,而不是像 001- 那樣在每個檔案前面加上數字的原因是,因為它可以減少與 patch 順序相關的衝突。它可以防止以下情況:兩個 PR 都會在系列結尾新增一個 patch,並使用相同的編號,最終導致兩者都被合併,從而產生重複的識別碼,並且它還可以減少在系列中間新增或刪除 patch 時的變動。

用法

新增新的 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 會忽略任何未 commit 的檔案,因此如果您希望匯出變更,則必須建立 commit。Commit 訊息的主旨行將用於派生 patch 檔案名稱,並且 commit 訊息的內文應包含 patch 存在的原因。

重新匯出 patch 有時會導致不相關的 patch 中的 shasum 變更。這通常是無害的,可以忽略(但繼續將這些變更新增到您的 PR 中,它會阻止它們為其他人顯示出來)。

編輯現有的 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

請注意,^ 符號 可能會在 Windows 上造成問題。解決方法是引用它 "[COMMIT_SHA]^" 或避免它 [COMMIT_SHA]~1

移除 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 commit 標記為 refs/patches/upstream-head。這可讓您追蹤哪些 commit 來自 Electron patch(那些在 refs/patches/upstream-head 之後的 commit),以及哪些 commit 在上游(那些在 refs/patches/upstream-head 之前的 commit)。

解決衝突

當更新上游依賴項目時,patch 可能無法乾淨地套用。通常,衝突可以透過 git 使用 3-way merge 自動解決。您可以指示 git-import-patches 使用 3-way merge 演算法,方法是傳遞 -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 遇到無法自動解決的 merge 衝突,它將暫停並讓您手動解決衝突。解決衝突後,git add 已解決的檔案,然後執行 git am --continue 以繼續套用其餘 patch。