Electron 中的 Patches
Electron 建構於兩個主要的上游專案:Chromium 和 Node.js。這些專案各自也有一些自己的依賴項目。我們盡力完全按照現狀使用這些依賴項目,但有時我們必須 patch 這些上游依賴項目才能達成我們的目標,以符合我們的使用案例。
Patch 的理由
Electron 中的每個 patch 都是維護負擔。當上游程式碼變更時,patch 可能會損壞,有時甚至不會出現 patch 衝突或編譯錯誤。保持我們的 patch 集是最新的且有效是一項持續的努力。因此,我們力求將 patch 數量保持在最低限度。為此,每個 patch 的 commit 訊息都必須描述其存在的原因。該原因必須是以下之一
- 此 patch 是暫時性的,旨在(或已經)commit 到上游,或最終移除。如果有的話,請包含指向上游 PR 或程式碼審查的連結,或驗證稍後是否仍需要此 patch 的程序。
- 此 patch 允許程式碼在 Electron 環境中編譯,但由於它是 Electron 特有的(例如,patch 掉對 Chrome 的
Profile
的參考),因此無法上游化。包含關於為什麼無法在沒有 patch 的情況下實作變更(例如,透過子類別化或複製程式碼)的理由。 - 此 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-patches
和 git-export-patches
。git-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。