開發工作流程#

您已經擁有自己 fork 的 NumPy 儲存庫副本,並已設定 Git,並且已如將您的儲存庫連結到上游儲存庫中所述,連結了上游儲存庫。以下描述的是使用 Git 的建議工作流程。

基本工作流程#

簡而言之

  1. 為您執行的每組編輯工作啟動一個新的功能分支。請參閱下方

  2. 開始修改!請參閱下方

  3. 完成時

    • 貢獻者:將您的功能分支推送到您自己的 Github 儲存庫,並建立提取請求

    • 核心開發人員:如果您想要推送變更而無需進一步審查,請參閱下方的註解。

這種工作方式有助於保持工作井然有序,並使歷史記錄盡可能清晰。

建立新的功能分支#

首先,從 upstream 儲存庫提取新的提交

git fetch upstream

然後,基於上游儲存庫的 main 分支建立一個新分支

git checkout -b my-new-feature upstream/main

編輯工作流程#

概觀#

# hack hack
git status # Optional
git diff # Optional
git add modified_file
git commit
# push the branch to your own Github repo
git push origin my-new-feature

更詳細的說明#

  1. 進行一些變更。當您覺得自己完成了一組完整、可運作的相關變更時,請繼續下一步。

  2. 選用:使用 git status 檢查哪些檔案已變更。您會看到如下的列表

    # On branch my-new-feature
    # Changed but not updated:
    #   (use "git add <file>..." to update what will be committed)
    #   (use "git checkout -- <file>..." to discard changes in working directory)
    #
    #  modified:   README
    #
    # Untracked files:
    #   (use "git add <file>..." to include in what will be committed)
    #
    #  INSTALL
    no changes added to commit (use "git add" and/or "git commit -a")
    
  3. 選用:使用 git diff 將變更與先前的版本進行比較。這會開啟一個簡單的文字瀏覽器介面,突出顯示您的檔案與先前版本之間的差異。

  4. 使用 git add modified_file 新增任何相關的已修改或新檔案。這會將檔案放入暫存區,這是將新增到您下一次提交的檔案佇列。僅新增具有相關、完整變更的檔案。將具有未完成變更的檔案留待稍後的提交。

  5. 要將暫存的檔案提交到您儲存庫的本機副本中,請執行 git commit。此時,將開啟一個文字編輯器,讓您撰寫提交訊息。請閱讀提交訊息章節,以確保您撰寫格式正確且足夠詳細的提交訊息。儲存訊息並關閉編輯器後,您的提交將被儲存。對於瑣碎的提交,可以使用 -m 標誌透過命令列傳遞簡短的提交訊息。例如,git commit -am "ENH: Some message"

    在某些情況下,您會看到此形式的提交命令:git commit -a。額外的 -a 標誌會自動提交所有已修改的檔案,並移除所有已刪除的檔案。這可以為您節省一些輸入大量 git add 命令的時間;但是,如果您不小心,它可能會將不必要的變更新增到提交中。

  6. 將變更推送到您在 GitHub 上的 fork

    git push origin my-new-feature
    

注意

假設您已遵循這些頁面中的指示,git 將建立一個名為 origin 的預設連結到您的 GitHub 儲存庫。您可以使用 --set-upstream 選項確保 origin 的連結永久設定

git push --set-upstream origin my-new-feature

從現在開始,git 將知道 my-new-feature 與您自己 GitHub 儲存庫中的 my-new-feature 分支相關。後續的推送呼叫將簡化為以下形式

git push

您必須為您建立的每個新分支使用 --set-upstream

可能在您編輯時,新的提交已新增到 upstream,這會影響您的工作。在這種情況下,請依照本文檔的變基於 main章節,將這些變更套用到您的分支。

撰寫提交訊息#

提交訊息應清晰並遵循一些基本規則。範例

ENH: add functionality X to numpy.<submodule>.

The first line of the commit message starts with a capitalized acronym
(options listed below) indicating what type of commit this is.  Then a blank
line, then more text if needed.  Lines shouldn't be longer than 72
characters.  If the commit is related to a ticket, indicate that with
"See #3456", "See ticket 3456", "Closes #3456" or similar.

描述變更的動機、錯誤修復的錯誤性質,或增強功能的作用細節,也適合包含在提交訊息中。訊息應該在不查看程式碼變更的情況下也能理解。類似 MAINT: fixed another one 的提交訊息是不應該做的範例;讀者必須到其他地方尋找上下文。

用於開始提交訊息的標準縮寫詞有

API: an (incompatible) API change
BENCH: changes to the benchmark suite
BLD: change related to building numpy
BUG: bug fix
CI: continuous integration
DEP: deprecate something, or remove a deprecated object
DEV: development tool or utility
DOC: documentation
ENH: enhancement
MAINT: maintenance commit (refactoring, typos, etc.)
MNT: alias for MAINT
NEP: NumPy enhancement proposals
REL: related to releasing numpy
REV: revert an earlier commit
STY: style fix (whitespace, PEP8)
TST: addition or modification of tests
TYP: static typing
WIP: work in progress, do not merge
跳過持續整合的命令#

預設情況下,每個 PR 都會執行許多持續整合 (CI) 作業,從在不同的作業系統和硬體平台上執行測試套件,到建置文件。在某些情況下,您已經知道不需要 CI(或並非全部需要),例如,如果您處理 CI 設定檔、README 中的文字,或其他未涉及常規建置、測試或文件序列的檔案。在這種情況下,您可以透過在 PR 的每個提交訊息中包含以下一個或多個片段來明確跳過 CI

  • [skip ci]:跳過所有 CI

    僅當您仍未準備好在您的 PR 上執行檢查時才建議使用(例如,如果這僅是草稿。)

  • [skip actions]:跳過 GitHub Actions 作業

    GitHub Actions 是大多數 CI 檢查運行的位置,包括 linter、基準測試、為大多數架構和 OS 運行基本測試,以及多種編譯器和 CPU 優化設定。請參閱這些檢查的設定檔。

  • [skip azp]:跳過 Azure 作業

    Azure 是運行所有全面測試的位置。這是一項昂貴的運行,如果您僅進行文件變更,則通常可以跳過它。請參閱這些檢查的主要設定檔。

  • [skip circle]:跳過 CircleCI 作業

    CircleCI 是我們建置文件並儲存每個 PR 中產生的預覽工件的位置。此檢查還將運行所有 docstring 範例並驗證其結果。如果您不進行文件變更,但您對函數的 API 進行變更,例如,您可能需要運行這些測試以驗證 doctest 仍然有效。請參閱這些檢查的設定檔。

  • [skip cirrus]:跳過 Cirrus 作業

    CirrusCI 主要觸發 Linux aarch64 和 MacOS Arm64 wheel 上傳。請參閱這些檢查的設定檔。

測試建置 wheel#

Numpy 目前使用 cibuildwheel 以便透過持續整合服務建置 wheel。為了節省資源,預設情況下,cibuildwheel wheel 建置器不會在每個 PR 或提交到 main 時運行。

如果您想測試您的提取請求是否不會破壞 wheel 建置器,您可以將 [wheel build] 附加到您的 PR 中最新提交的提交訊息的第一行來執行此操作。請僅針對與建置相關的 PR 執行此操作,因為運行所有 wheel 建置既緩慢又昂貴。

透過 github actions 建置的 wheel(包括 64 位元 Linux、x86-64 macOS 和 32/64 位元 Windows)將以 zip 檔案形式上傳為工件。您可以從「Wheel builder」action 的摘要頁面存取它們。透過 Cirrus CI 建置的 aarch64 Linux 和 arm64 macOS wheel 不可用作工件。此外,在以下條件下,wheel 將上傳到 https://anaconda.org/scientific-python-nightly-wheels/

  • 透過每週 cron job 或

  • 如果 GitHub Actions 或 Cirrus 建置已手動觸發,這需要適當的權限

如果建置是由以 v 開頭的儲存庫標籤觸發的,則 wheel 將上傳到 https://anaconda.org/multibuild-wheels-staging/

取得郵寄列表的意見#

如果您計劃新的功能或 API 變更,最好先發送電子郵件到 NumPy 郵寄列表 徵求意見。如果您在一週內沒有收到回覆,可以再次 ping 列表。

請求將您的變更合併到 main 儲存庫#

當您覺得您的工作已完成時,您可以建立提取請求 (PR)。如果您的變更涉及 API 的修改或函數的添加/修改,請按照 doc/release/upcoming_changes/README.rst 檔案中的說明和格式,將發行說明添加到 doc/release/upcoming_changes/ 目錄。

取得您的 PR 審查#

我們會盡快審查提取請求,通常在一週內。如果您在兩週內沒有收到審查意見,請隨時透過在您的 PR 上新增評論來請求回饋意見(這將通知維護人員)。

如果您的 PR 很大或很複雜,在 numpy-discussion 郵寄列表上請求輸入也可能很有用。

變基於 main#

這會使用來自上游 NumPy GitHub 儲存庫的變更來更新您的功能分支。如果您絕對不需要執行此操作,請盡量避免執行,除非您已完成。第一步是使用來自上游的新提交來更新遠端儲存庫

git fetch upstream

接下來,您需要更新功能分支

# go to the feature branch
git checkout my-new-feature
# make a backup in case you mess up
git branch tmp my-new-feature
# rebase on upstream main branch
git rebase upstream/main

如果您對上游也已變更的檔案進行了變更,這可能會產生合併衝突,您需要解決這些衝突。請參閱下方以獲得此情況的協助。

最後,在成功變基後,移除備份分支

git branch -D tmp

注意

變基於 main 比將上游合併回您的分支更受歡迎。在功能分支上工作時,不鼓勵使用 git mergegit pull

從混亂中恢復#

有時,您會搞砸合併或變基。幸運的是,在 Git 中,從此類錯誤中恢復相對簡單。

如果您在變基期間搞砸了

git rebase --abort

如果您在變基後注意到您搞砸了

# reset branch back to the saved point
git reset --hard tmp

如果您忘記建立備份分支

# look at the reflog of the branch
git reflog show my-feature-branch

8630830 my-feature-branch@{0}: commit: BUG: io: close file handles immediately
278dd2a my-feature-branch@{1}: rebase finished: refs/heads/my-feature-branch onto 11ee694744f2552d
26aa21a my-feature-branch@{2}: commit: BUG: lib: make seek_gzip_factory not leak gzip obj
...

# reset the branch to where it was before the botched rebase
git reset --hard my-feature-branch@{2}

如果您實際上沒有搞砸,但存在合併衝突,則需要解決這些衝突。

您可能想要執行的其他事項#

重寫提交歷史記錄#

注意

僅針對您自己的功能分支執行此操作。

您所做的提交中存在令人尷尬的錯字嗎?或者,也許您做了一些您不希望後人看到的錯誤開始。

這可以透過互動式變基來完成。

假設提交歷史記錄如下所示

git log --oneline
eadc391 Fix some remaining bugs
a815645 Modify it so that it works
2dec1ac Fix a few bugs + disable
13d7934 First implementation
6ad92e5 * masked is now an instance of a new object, MaskedConstant
29001ed Add pre-nep for a couple of structured_array_extensions.
...

並且 6ad92e5main 分支中的最後一個提交。假設我們要進行以下變更

  • 13d7934 的提交訊息重寫為更合理的內容。

  • 將提交 2dec1aca815645eadc391 合併為單個提交。

我們按如下方式執行

# make a backup of the current state
git branch tmp HEAD
# interactive rebase
git rebase -i 6ad92e5

這將開啟一個編輯器,其中包含以下文字

pick 13d7934 First implementation
pick 2dec1ac Fix a few bugs + disable
pick a815645 Modify it so that it works
pick eadc391 Fix some remaining bugs

# Rebase 6ad92e5..eadc391 onto 6ad92e5
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

為了實現我們想要的目標,我們將對其進行以下變更

r 13d7934 First implementation
pick 2dec1ac Fix a few bugs + disable
f a815645 Modify it so that it works
f eadc391 Fix some remaining bugs

這表示 (i) 我們想要編輯 13d7934 的提交訊息,以及 (ii) 將最後三個提交摺疊為一個。現在我們儲存並退出編輯器。

然後 Git 將立即啟動一個編輯器來編輯提交訊息。修改後,我們得到輸出

[detached HEAD 721fc64] FOO: First implementation
 2 files changed, 199 insertions(+), 66 deletions(-)
[detached HEAD 0f22701] Fix a few bugs + disable
 1 files changed, 79 insertions(+), 61 deletions(-)
Successfully rebased and updated refs/heads/my-feature-branch.

並且歷史記錄現在看起來像這樣

0f22701 Fix a few bugs + disable
721fc64 ENH: Sophisticated feature
6ad92e5 * masked is now an instance of a new object, MaskedConstant

如果出錯,也可以再次按照上方所述進行恢復。

刪除 GitHub 上的分支#

git checkout main
# delete branch locally
git branch -D my-unwanted-branch
# delete branch on github
git push origin --delete my-unwanted-branch

另請參閱:https://stackoverflow.com/questions/2003505/how-do-i-delete-a-git-branch-locally-and-remotely

多人共享單個儲存庫#

如果您想與其他人一起處理某些內容,並且你們都在提交到同一個儲存庫,甚至是同一個分支,那麼只需透過 GitHub 共享即可。

首先,如建立您自己的 scikit-image 副本 (fork)中所述,將 NumPy fork 到您的帳戶中。

然後,轉到您 fork 的儲存庫 github 頁面,例如 https://github.com/your-user-name/numpy

點擊「管理員」按鈕,並將任何其他人作為協作者新增到儲存庫

../_images/pull_button.png

現在所有這些人都可以執行

git clone git@github.com:your-user-name/numpy.git

請記住,以 git@ 開頭的連結使用 ssh 協定並且是讀寫的;以 git:// 開頭的連結是唯讀的。

您的協作者隨後可以使用常用的方式直接提交到該儲存庫

git commit -am 'ENH - much better code'
git push origin my-feature-branch # pushes directly into your repo

從現有的提取請求中檢出變更#

如果您想測試提取請求中的變更或繼續新的提取請求中的工作,則提交將被複製到您 fork 的儲存庫中的本機分支中

首先確保您的上游指向 main 儲存庫,如將您的儲存庫連結到上游儲存庫中所述

然後,提取變更並建立本機分支。假設 $ID 是提取請求編號,而 $BRANCHNAME 是您希望建立的新本機分支的名稱

git fetch upstream pull/$ID/head:$BRANCHNAME

檢出新建立的分支

git checkout $BRANCHNAME

您現在擁有提取請求中的變更。

探索您的儲存庫#

要查看儲存庫分支和提交的圖形表示

gitk --all

要查看此分支的提交線性列表

git log

向下移植#

向下移植是將 NumPy 的 main 分支中提交的新功能/修復複製回穩定發行分支的過程。若要執行此操作,您需要從您要向下移植到的分支建立一個分支,從 numpy/main 挑選您想要的提交,然後為包含向下移植的分支提交提取請求。

  1. 首先,您需要建立您將要工作的分支。這需要基於舊版本的 NumPy(而非 main)

    # Make a new branch based on numpy/maintenance/1.8.x,
    # backport-3324 is our new name for the branch.
    git checkout -b backport-3324 upstream/maintenance/1.8.x
    
  2. 現在您需要使用 git cherry-pick 將 main 中的變更套用到此分支

    # Update remote
    git fetch upstream
    # Check the commit log for commits to cherry pick
    git log upstream/main
    # This pull request included commits aa7a047 to c098283 (inclusive)
    # so you use the .. syntax (for a range of commits), the ^ makes the
    # range inclusive.
    git cherry-pick aa7a047^..c098283
    ...
    # Fix any conflicts, then if needed:
    git cherry-pick --continue
    
  3. 您可能會在此處遇到一些挑選衝突。這些衝突的解決方式與合併/變基衝突相同。除了這裡您可以使用 git blame 來查看 main 和向下移植分支之間的差異,以確保沒有任何東西被搞砸。

  4. 將新分支推送到您的 Github 儲存庫

    git push -u origin backport-3324
    
  5. 最後使用 Github 建立提取請求。請確保它是針對維護分支而不是 main,Github 通常會建議您針對 main 建立提取請求。

將變更推送到 main 儲存庫#

需要對 main NumPy 儲存庫具有提交權限。

當您在功能分支中有一組「準備就緒」的變更準備用於 NumPy 的 mainmaintenance 分支時,您可以按如下方式將它們推送到 upstream

  1. 首先,合併或變基到目標分支。

    1. 如果只有少數不相關的提交,則最好進行變基

      git fetch upstream
      git rebase upstream/main
      

      請參閱變基於 main

    2. 如果所有提交都相關,則建立合併提交

      git fetch upstream
      git merge --no-ff upstream/main
      
  2. 檢查您要推送的內容看起來是否合理

    git log -p upstream/main..
    git log --oneline --graph
    
  3. 推送到上游

    git push upstream my-feature-branch:main
    

注意

通常最好使用 -n 標誌來 git push,以首先檢查您是否要將所需的變更推送到您想要的位置。