开发工作流程#

你已经有了自己的 NumPy 仓库的 fork 副本,配置了 Git,并将上游仓库链接到 Linking your repository to the upstream repo 中所解释的那样. 下面描述的是使用 Git 的推荐工作流程.

基本工作流程#

简而言之:

  1. 为你做的每组编辑启动一个新的 feature branch.参见 below .

  2. 开始动手吧!参见 below

  3. 完成时:

    • 贡献者:将你的 feature branch 推送到你自己的 Github 仓库,并 create a pull request .

    • 核心开发者:如果你想在没有进一步审查的情况下推送更改,请参见 below 中的说明.

这种工作方式有助于保持工作井井有条,并使历史记录尽可能清晰.

创建一个新的 feature branch#

首先,从 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 . 此时,将打开一个文本编辑器,允许你编写提交消息. 阅读 commit message section ,确保你正在编写格式正确且足够详细的提交消息. 保存你的消息并关闭编辑器后,你的提交将被保存. 对于简单的提交,可以使用 -m 标志通过命令行传递简短的提交消息. 例如, git commit -am "ENH: Some message" .

    在某些情况下,您会看到以下形式的提交命令: git commit -a .额外的 -a 标志会自动提交所有已修改的文件并删除所有已删除的文件. 这样做可以节省您多次输入 git add 命令,但如果不小心,它可能会将不需要的更改添加到提交中.

  6. 将更改推送到 GitHub 上的 fork:

    git push origin my-new-feature
    

备注

假设您已按照这些页面中的说明进行操作,git 将创建一个指向您的 GitHb 仓库的默认链接,称为 origin . 您可以使用 --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上Rebase 部分将这些更改应用到您的分支.

编写提交消息#

提交消息应该清晰并遵循一些基本规则. 例如:

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,基准测试,运行大多数架构和操作系统的基本测试,以及多个编译器和 CPU 优化设置. See the configuration files for these checks.

  • [skip azp] :跳过 Azure 作业

    Azure 是运行所有全面测试的地方. 这是一个昂贵的运行,如果您只进行文档更改,通常可以跳过. See the main configuration file for these checks.

  • [skip circle] :跳过 CircleCI 作业

    CircleCI 是我们构建文档并存储每个 PR 中生成的预览工件的地方. 此检查还将运行所有 docstrings 示例并验证其结果. 例如,如果您不进行文档更改,但对函数的 API 进行更改,则可能需要运行这些测试以验证 doctest 是否仍然有效. See the configuration file for these checks.

  • [skip cirrus] :跳过 Cirrus 作业

    CirrusCI 主要触发 Linux aarch64 和 MacOS Arm64 wheels 上传. See the configuration file for these checks.

测试构建 wheels#

Numpy 目前使用 cibuildwheel 以便通过持续集成服务构建 wheels. 为了节省资源,cibuildwheel wheel 构建器默认情况下不会在每个 PR 或对 main 的提交上运行.

如果您想测试您的pull request是否会破坏wheel构建器,您可以在您的PR中最新commit的commit message的第一行添加 [wheel build] .请仅在与构建相关的PR中使用此方法,因为运行所有wheel构建既缓慢又昂贵.

通过github actions构建的wheels(包括64位Linux,x86-64 macOS和32/64位Windows)将作为zip文件中的artifacts上传.您可以从"Wheel builder"操作的摘要页面访问它们. 通过Cirrus CI构建的aarch64 Linux和arm64 macOS wheels不作为artifacts提供. 此外,wheels将在以下条件下上传到https://anaconda.org/scientific-python-nightly-wheels/:

  • 通过每周的cron job或者

  • 如果GitHub Actions或Cirrus构建已手动触发,这需要适当的权限

如果构建是由以 v 开头的repo标签触发的,那么wheels将上传到https://anaconda.org/multibuild-wheels-staging/.

获取邮件列表的意见#

如果您计划一项新功能或API更改,明智的做法是首先通过电子邮件发送给NumPy mailing list ,征求意见.如果您在一周内没有收到回复,可以再次ping该列表.

请求将您的更改合并到主repo中#

当您觉得您的工作完成时,您可以创建一个pull request(PR).如果您的更改涉及修改API或添加/修改函数,请按照 doc/release/upcoming_changes/README.rst 文件中的说明和格式,在 doc/release/upcoming_changes/ 目录中添加一个release note.

获取PR的审查#

我们会尽快审查pull request,通常在一周内. 如果您在两周内没有收到任何审查意见,请随时在您的PR上添加评论(这将通知维护人员)以请求反馈.

如果您的PR很大或很复杂,那么可以在numpy-discussion邮件列表中请求输入意见.

在main上Rebase#

这将使用上游NumPy GitHub repo中的更改来更新您的feature branch. 如果您不是绝对需要这样做,请尽量避免这样做,除非您已经完成. 第一步是使用来自上游的新提交来更新远程仓库:

git fetch upstream

接下来,您需要更新feature branch:

# 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

如果您对也在上游更改的文件进行了更改,这可能会产生您需要解决的合并冲突. 有关此情况的帮助,请参见 below .

最后,在成功rebase后,删除备份branch:

git branch -D tmp

备注

与将上游合并回您的branch相比,更倾向于在main上rebase.在feature branch上工作时,不鼓励使用 git mergegit pull .

从混乱中恢复#

有时,您会弄乱合并或rebase. 幸运的是,在Git中,从这些错误中恢复相对简单.

如果您在rebase期间弄乱了:

git rebase --abort

如果您在rebase之后注意到自己弄乱了:

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

如果您忘记创建备份branch:

# 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}

如果您实际上没有弄乱,但是存在合并冲突,则需要解决这些冲突.

您可能想要做的其他事情#

重写提交历史#

备注

仅为您自己的feature branch执行此操作.

在您进行的commit中有一个令人尴尬的错字? 或者,也许您做了一些您不希望后人看到的错误的尝试.

这可以通过交互式rebase完成.

假设提交历史记录如下所示:

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 branch中的最后一个commit. 假设我们要进行以下更改:

  • 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

如果出现错误,可以像 above 解释的那样再次恢复.

在 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 共享它.

首先,像从 Making your own copy (fork) of scikit-image 中那样,将 NumPy fork 到你的帐户中.

然后,转到你的 fork 存储库 github 页面,比如 https://github.com/your-user-name/numpy

单击"Admin"按钮,并将任何其他人作为协作者添加到 repo:

../_images/pull_button.png

现在所有这些人都可以:

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

请记住,以 git@ 开头的链接使用 ssh 协议并且是读写;以 git:// 开头的链接是只读的.

然后,你的协作者可以使用通常的::直接提交到该 repo 中.

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

从现有 pull request 中检出更改#

如果要测试 pull request 中的更改或在新的 pull request 中继续工作,则应将提交克隆到 fork 存储库中的本地分支中

首先,确保你的上游指向主存储库,如 Linking your repository to the upstream repo 中所述

然后,获取更改并创建一个本地分支.假设 $ID 是 pull request 编号, $BRANCHNAME 是你希望创建的新本地分支的名称:

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

检出新创建的分支:

git checkout $BRANCHNAME

现在你拥有了 pull request 中的更改.

浏览你的存储库#

要查看存储库分支和提交的图形表示:

gitk --all

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

git log

反向移植#

反向移植是将 NumPy 的 main 分支中提交的新功能/修复复制回稳定发布分支的过程.为此,你需要从要反向移植的分支创建一个分支,从 numpy/main 中 cherry pick 你想要提交的提交,然后为包含反向移植的分支提交一个 pull request.

  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. 你可能会在这里遇到一些 cherry picking 的冲突.这些冲突的解决方式与合并/变基冲突相同.不同的是,你可以在这里使用 git blame 来查看 main 和反向移植分支之间的差异,以确保没有任何东西搞砸.

  4. 将新分支推送到你的 Github 存储库:

    git push -u origin backport-3324
    
  5. 最后使用 Github 创建一个 pull request.确保它是针对维护分支而不是 main,Github 通常会建议你针对 main 创建 pull request.

将更改推送到主 repo#

需要对主 NumPy repo 具有提交权限.

当你在一个特性分支中准备好了一组"就绪"的更改,可以用于 NumPy 的 mainmaintenance 分支时,你可以按如下方式将它们推送到 upstream :

  1. 首先,合并或变基到目标分支.

    1. 如果只有少数几个不相关的提交,那么最好进行变基:

      git fetch upstream
      git rebase upstream/main
      

      请参阅 在main上Rebase .

    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
    

备注

通常,最好使用 git push-n 标志来首先检查你要推送的更改是否是要推送到你想要的地方.