開發工作流程#
您已經擁有自己 fork 的 NumPy 儲存庫副本,並已設定 Git,並且已如將您的儲存庫連結到上游儲存庫中所述,連結了上游儲存庫。以下描述的是使用 Git 的建議工作流程。
基本工作流程#
簡而言之
這種工作方式有助於保持工作井然有序,並使歷史記錄盡可能清晰。
建立新的功能分支#
首先,從 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
更詳細的說明#
進行一些變更。當您覺得自己完成了一組完整、可運作的相關變更時,請繼續下一步。
選用:使用
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")
選用:使用
git diff
將變更與先前的版本進行比較。這會開啟一個簡單的文字瀏覽器介面,突出顯示您的檔案與先前版本之間的差異。使用
git add modified_file
新增任何相關的已修改或新檔案。這會將檔案放入暫存區,這是將新增到您下一次提交的檔案佇列。僅新增具有相關、完整變更的檔案。將具有未完成變更的檔案留待稍後的提交。要將暫存的檔案提交到您儲存庫的本機副本中,請執行
git commit
。此時,將開啟一個文字編輯器,讓您撰寫提交訊息。請閱讀提交訊息章節,以確保您撰寫格式正確且足夠詳細的提交訊息。儲存訊息並關閉編輯器後,您的提交將被儲存。對於瑣碎的提交,可以使用-m
標誌透過命令列傳遞簡短的提交訊息。例如,git commit -am "ENH: Some message"
。在某些情況下,您會看到此形式的提交命令:
git commit -a
。額外的-a
標誌會自動提交所有已修改的檔案,並移除所有已刪除的檔案。這可以為您節省一些輸入大量git add
命令的時間;但是,如果您不小心,它可能會將不必要的變更新增到提交中。將變更推送到您在 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 merge
和 git 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.
...
並且 6ad92e5
是 main
分支中的最後一個提交。假設我們要進行以下變更
將
13d7934
的提交訊息重寫為更合理的內容。將提交
2dec1ac
、a815645
、eadc391
合併為單個提交。
我們按如下方式執行
# 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
點擊「管理員」按鈕,並將任何其他人作為協作者新增到儲存庫

現在所有這些人都可以執行
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
挑選您想要的提交,然後為包含向下移植的分支提交提取請求。
首先,您需要建立您將要工作的分支。這需要基於舊版本的 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
現在您需要使用
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
您可能會在此處遇到一些挑選衝突。這些衝突的解決方式與合併/變基衝突相同。除了這裡您可以使用
git blame
來查看 main 和向下移植分支之間的差異,以確保沒有任何東西被搞砸。將新分支推送到您的 Github 儲存庫
git push -u origin backport-3324
最後使用 Github 建立提取請求。請確保它是針對維護分支而不是 main,Github 通常會建議您針對 main 建立提取請求。
將變更推送到 main 儲存庫#
需要對 main NumPy 儲存庫具有提交權限。
當您在功能分支中有一組「準備就緒」的變更準備用於 NumPy 的 main
或 maintenance
分支時,您可以按如下方式將它們推送到 upstream
首先,合併或變基到目標分支。
如果只有少數不相關的提交,則最好進行變基
git fetch upstream git rebase upstream/main
請參閱變基於 main。
如果所有提交都相關,則建立合併提交
git fetch upstream git merge --no-ff upstream/main
檢查您要推送的內容看起來是否合理
git log -p upstream/main.. git log --oneline --graph
推送到上游
git push upstream my-feature-branch:main
注意
通常最好使用 -n
標誌來 git push
,以首先檢查您是否要將所需的變更推送到您想要的位置。