开发工作流程#

你已经拥有了自己的 NumPy 仓库的分支副本,配置了 Git,并且按照 Linking your repository to the upstream repo 中的说明将上游仓库链接起来.下面描述的是一个推荐的 Git 工作流程.

基本工作流程#

简而言之:

  1. 每次编辑时都从新的 功能分支 开始.请参见 下方.

  2. 继续破解!请参见 下方

  3. 完成时:

    • 贡献者: 将你的特性分支推送到你自己的 Github 仓库,并 创建一个拉取请求.

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

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

创建一个新的功能分支#

首先,从 upstream 仓库获取新的提交:

git fetch upstream

然后,基于上游仓库的主分支创建一个新分支:

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: 一些消息”``.

    在某些情况下,你会看到这种形式的提交命令:git commit -a.额外的 -a 标志会自动提交所有修改的文件并删除所有已删除的文件.这可以节省你输入大量 git add 命令的时间;然而,如果你不小心,它可能会在提交中添加不需要的更改.

  6. 将更改推送到 GitHub 上的你的分支:

    git push origin my-new-feature
    

备注

假设你已经按照这些页面中的指示操作,git 将会创建一个默认链接到你的 GitHub 仓库,称为 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 中,这些提交会影响你的工作.在这种情况下,请按照本文档的 在主分支上变基 部分将这些更改应用到你的分支.

编写提交信息#

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

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: 修复了另一个 这样的提交消息是一个不应该做的例子;读者必须到别处寻找上下文.

开始提交消息的标准缩写是:

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 检查运行的地方,包括代码检查器、基准测试、为大多数架构和操作系统运行基本测试,以及多个编译器和 CPU 优化设置.`查看这些检查的配置文件. <numpy/numpy>`__

  • [skip azp]: 跳过 Azure 作业

    Azure 是所有综合测试运行的地方.这是一个昂贵的运行,如果你只做文档更改,例如,你通常可以跳过它.`查看这些检查的主配置文件. <numpy/numpy>`__

  • [skip circle]: 跳过 CircleCI 任务

    CircleCI 是我们构建文档并存储生成的工件以在每个PR中预览的地方.此检查还将运行所有docstring示例并验证其结果.如果你没有进行文档更改,但更改了函数的API,例如,你可能需要运行这些测试以验证doctests是否仍然有效.`查看这些检查的配置文件. <numpy/numpy>`__

  • [skip cirrus]: 跳过 Cirrus 任务

    CirrusCI 主要触发 Linux aarch64 和 MacOS Arm64 轮子上传.`查看这些检查的配置文件. <numpy/numpy>`__

测试构建轮子#

Numpy 目前使用 cibuildwheel 通过持续集成服务来构建轮子.为了节省资源,cibuildwheel 轮子构建器默认不会在每个 PR 或提交到主分支时运行.

如果你想测试你的拉取请求不会破坏轮子构建器,你可以通过在PR中最新的提交信息的第一个行添加 [wheel build] 来实现.请仅对与构建相关的PR这样做,因为运行所有的轮子构建是缓慢且昂贵的.

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

  • 通过每周的 cron 作业

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

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

获取邮件列表的意见#

如果你计划一个新功能或API更改,最好先给NumPy的 邮件列表 发邮件征求意见.如果你一周内没有收到回复,可以再次联系列表.

请求将您的更改合并到主仓库#

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

获取你的 PR 审查#

我们尽快审查拉取请求,通常在一周内完成.如果在两周内没有收到审查意见,欢迎通过在你的PR上添加评论来请求反馈(这会通知维护者).

如果你的PR很大或很复杂,在numpy-discussion邮件列表上寻求意见也可能是有用的.

在主分支上变基#

这将使用上游 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

备注

在主分支上变基比将上游合并回你的分支更受欢迎.在功能分支上工作时,不鼓励使用 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 的提交信息重写为更合理的内容.

  • 将提交 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分享它.

首先将 NumPy 分叉到您的账户中,如 Making your own copy (fork) of scikit-image 所述.

然后,转到你 forked 的仓库 github 页面,例如 https://github.com/your-user-name/numpy

点击 ‘Admin’ 按钮,并将其他人添加为仓库的协作者:

../_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

从现有的拉取请求中检出更改#

如果你想在一个拉取请求中测试更改或在新的拉取请求中继续工作,需要将提交克隆到你分叉仓库的本地分支中

首先确保你的上游指向主仓库,如从 Linking your repository to the upstream repo

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

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

查看新创建的分支:

git checkout $BRANCHNAME

你现在有了拉取请求中的更改.

探索你的仓库#

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

gitk --all

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

git log

回移植#

回溯移植是将 NumPy 的 main 分支中提交的新功能/修复复制回稳定发布分支的过程.为此,您从要回溯移植到的分支创建一个分支,从 numpy/main 中挑选您想要的提交,然后为包含回溯移植的分支提交拉取请求.

  1. 首先,你需要创建你要工作的分支.这需要基于NumPy的旧版本(不是主分支):

    # 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 将主分支的更改应用到这个分支:

    # 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 来查看主分支和回退分支之间的差异,以确保不会出现问题.

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

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

推送更改到主仓库#

需要对主NumPy仓库的提交权限.

当你在一个功能分支中有一组”准备就绪”的更改,准备提交到 NumPy 的 mainmaintenance 分支时,你可以将它们推送到 upstream ,如下所示:

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

    1. 只有少数几个不相关的提交,然后更喜欢变基:

      git fetch upstream
      git rebase upstream/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 是一个好主意,首先检查你是否即将推送你想要的更改到你想要的地方.