开发工作流程#
您已经有了 NumPy 仓库的自己的 fork 副本,配置了 Git,并且已经按照 Linking your repository to the upstream repo 中的说明链接了上游仓库.下面描述的是推荐的 Git 工作流程.
基本工作流程#
简而言之:
为您所做的每组编辑启动一个新的特性分支.参见 below .
开始修改!参见 below
完成时:
贡献者:将您的特性分支推送到您自己的 Github 仓库,并且 create a pull request .
核心开发者:如果您想在没有进一步审查的情况下推送更改,请参见 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
更详细地#
进行一些更改.当您觉得您已经完成了一组完整的,相关的工作更改时,请继续执行下一步.
可选:使用
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.此时,将打开一个文本编辑器,允许您编写提交消息.阅读 commit message section ,以确保您正在编写格式正确且足够详细的提交消息.保存您的消息并关闭编辑器后,您的提交将被保存.对于琐碎的提交,可以通过命令行使用-m标志传递一条简短的提交消息.例如,git commit -am "ENH: Some message".在某些情况下,您将看到这种形式的提交命令:
git commit -a.额外的-a标志会自动提交所有已修改的文件并删除所有已删除的文件.这可以为您节省一些输入大量的git add命令;但是,如果您不小心,它可能会将不需要的更改添加到提交中.将更改推送到 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 分支变基 章节,将这些更改应用到你的分支.
编写提交信息#
提交信息应该清晰并遵循一些基本规则.例如:
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.
描述更改的动机,bug修复的本质或增强功能的细节,这些都应该包含在提交信息中.提交信息应该在不查看代码更改的情况下也能理解.像 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),例如,如果您处理 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 生成的工件以供预览的地方.此检查还将运行所有 docstring 示例并验证其结果.如果您不进行文档更改,但更改了函数的 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 构建器,您可以通过将 [wheel build] 附加到您的 PR 中最新提交的提交消息的第一行来做到这一点. 请仅对与构建相关的 PR 执行此操作,因为运行所有 wheel 构建既缓慢又昂贵.
通过 github actions 构建的 wheels(包括 64 位 Linux,x86-64 macOS 和 32/64 位 Windows)将作为 zip 文件中的 artifacts 上传.您可以从 “Wheel builder” action 的 Summary 页面访问它们.通过 Cirrus CI 构建的 aarch64 Linux 和 arm64 macOS wheels 不会作为 artifacts 提供.此外,wheels 将在以下条件下上传到 https://anaconda.org/scientific-python-nightly-wheels/:
通过每周的 cron 任务,或者
如果 GitHub Actions 或 Cirrus 构建已手动触发,这需要适当的权限.
如果构建是由以 v 开头的 repo 标签触发的,则 wheels 将上传到 https://anaconda.org/multibuild-wheels-staging/.
获取邮件列表的意见#
如果您计划新的特性或 API 变更,最好首先通过电子邮件发送到 NumPy mailing list 请求评论.如果您在一周内没有收到回复,可以再次 ping 该列表.
请求将您的更改合并到主仓库中#
当您觉得您的工作完成时,您可以创建一个 pull request (PR).如果您的更改涉及 API 的修改或函数的添加/修改,请按照 doc/release/upcoming_changes/README.rst 文件中的说明和格式,向 doc/release/upcoming_changes/ 目录添加一个 release note.
获取您的 PR 审查#
我们会尽快审查 pull requests,通常在一周内.如果您在两周内没有收到任何审查意见,请随时通过在您的 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
如果您对已在上游更改的文件进行了更改,这可能会产生您需要解决的合并冲突.有关这方面的帮助,请参见 below .
最后,在成功变基后,删除备份分支:
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
如果出现错误,仍然可以按照 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”按钮,并将其他任何人作为协作者添加到存储库中:
现在,所有这些人都可以执行以下操作:
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 的存储库中的本地分支中
首先,确保您的上游指向主存储库,如 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 中 cherry pick 您想要的提交,然后为包含反向移植的分支提交一个拉取请求.
首先,您需要创建将要工作的分支.这需要基于 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 创建拉取请求.
推送更改到主仓库#
需要对主 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
备注
通常,最好使用 git push 的 -n 标志来首先检查您是否要将更改推送到您想要的位置.