Electron의 패치
Electron은 두 개의 주요 상위 프로젝트인 Chromium과 Node.js를 기반으로 구축되었다. 이 프로젝트들은 각각 여러 종속성을 가지고 있다. 우리는 이러한 종속성을 그대로 사용하려고 최선을 다하지만, 때로는 우리의 사용 사례에 맞게 상위 프로젝트의 종속성을 패치하지 않고는 목표를 달성할 수 없는 경우가 있다.
패치 적용 근거
Electron의 모든 패치는 유지보수 부담을 초래한다. 업스트림 코드가 변경되면 패치가 깨질 수 있으며, 때로는 패치 충돌이나 컴파일 오류 없이도 발생한다. 패치 세트를 최신 상태로 유지하고 효과적으로 만드는 것은 지속적인 노력이 필요하다. 따라서 우리는 패치 수를 최소한으로 유지하려고 노력한다. 이를 위해 모든 패치는 커밋 메시지에 존재 이유를 명시해야 한다. 그 이유는 다음 중 하나여야 한다:
-
패치가 임시적이며, 업스트림에 커밋되거나 결국 제거될 예정이다. 가능한 경우 업스트림 PR이나 코드 리뷰 링크를 포함하거나, 나중에 패치가 여전히 필요한지 확인하는 절차를 명시한다.
-
패치가 Electron 환경에서 코드를 컴파일할 수 있게 하지만, Electron에 특화된 변경사항이므로 업스트림에 적용할 수 없다 (예: Chrome의
Profile
참조를 패치로 제거하는 경우). 왜 이 변경사항을 패치 없이 구현할 수 없는지 (예: 서브클래싱이나 코드 복사를 통해) 이유를 설명한다. -
패치가 Electron에 특화된 기능 변경을 수행하며, 이는 업스트림과 근본적으로 호환되지 않는다.
일반적으로 우리가 협력하는 모든 업스트림 프로젝트는 친절한 사람들이며, Electron과 업스트림 프로젝트 모두와 호환되도록 코드를 리팩토링하는 것을 기꺼이 받아들인다. (예: 이 Chromium 변경사항은 동일한 작업을 수행하던 패치를 제거할 수 있게 했고, 이 Node 변경사항은 Node에는 영향이 없었지만 Electron의 버그를 수정했다.) 가능한 한 변경사항을 업스트림에 적용하고, 무기한으로 유지되는 패치를 피해야 한다.
패치 시스템 관리
상위 프로젝트에 패치를 적용해야만 변경할 수 있는 상황에 처했다면, Electron에서 패치를 관리하는 방법을 알아야 한다.
Electron에서 상위 프로젝트에 적용하는 모든 패치는 patches/
디렉토리에 포함되어 있다. patches/
의 각 하위 디렉토리에는 여러 패치 파일과 함께 .patches
파일이 있다. .patches
파일은 패치를 적용해야 하는 순서를 나열한다. 이 파일들은 상위 프로젝트를 체크아웃한 후 적용되는 일련의 git 커밋으로 생각할 수 있다.
patches
├── config.json <-- 이 파일은 어떤 패치셋 디렉토리가 어떤 프로젝트에 적용되는지 설명
├── 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-patches
와 git-export-patches
두 가지 도구를 제공한다. git-import-patches
는 패치 파일 세트를 git 저장소로 가져와 각 패치를 올바른 순서로 적용하고 각각에 대해 커밋을 생성한다. git-export-patches
는 반대로 동작하며, 저장소의 일련의 git 커밋을 디렉토리의 파일 세트와 .patches
파일로 내보낸다.
참고: 각 파일 앞에
001-
과 같은 번호를 붙이는 대신.patches
파일을 사용해 패치 적용 순서를 유지하는 이유는 패치 순서와 관련된 충돌을 줄이기 위해서다. 두 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
는 커밋되지 않은 파일을 무시하므로, 변경 사항을 내보내려면 반드시 커밋을 생성해야 한다. 커밋 메시지의 제목은 패치 파일 이름을 생성하는 데 사용되며, 메시지 본문에는 패치가 필요한 이유를 포함해야 한다.
패치를 다시 내보내면 때로는 관련 없는 패치의 shasums가 변경될 수 있다. 이는 일반적으로 무해하며 무시해도 되지만, PR에 해당 변경 사항을 추가하면 다른 사람에게 동일한 문제가 발생하지 않게 할 수 있다.
기존 패치 수정하기
$ cd src/v8
$ vim some/code/file.cc
$ git log
# 수정하려는 패치의 커밋 SHA를 찾는다.
$ git commit --fixup [COMMIT_SHA]
$ git rebase --autosquash -i [COMMIT_SHA]^
$ ../electron/script/git-export-patches -o ../electron/patches/v8
^
기호는 윈도우에서 문제를 일으킬 수 있다. 이를 해결하려면 "[COMMIT_SHA]^"
와 같이 따옴표로 감싸거나 [COMMIT_SHA]~1
로 대체한다.
패치 제거하기
$ vim src/electron/patches/node/.patches
# 제거하려는 패치 이름이 적힌 줄을 삭제한다
$ 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-way 병합을 통해 충돌을 자동으로 해결할 수 있다. git-import-patches
에 -3
인자를 전달해 3-way 병합 알고리즘을 사용하도록 지시할 수 있다:
$ cd src/third_party/electron_node
# 패치 적용이 중간에 실패했다면, 다음과 같이 초기화할 수 있다:
$ git am --abort
# 그리고 3-way 병합으로 다시 시도한다:
$ ../../electron/script/git-import-patches -3 ../../electron/patches/node
git-import-patches -3
이 자동으로 해결할 수 없는 병합 충돌을 만나면 일시 중지하고 수동으로 충돌을 해결할 수 있게 한다. 충돌을 해결한 후, 해결된 파일을 git add
로 추가하고 git am --continue
를 실행해 나머지 패치를 적용한다.