开发工作流程#
您已经有了 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 上的分叉
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.
在提交消息中描述更改的动机、错误修复的性质或增强功能的详细信息也是不错的。消息应该在不查看代码更改的情况下可理解。像 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 优化设置。参阅这些检查的配置文件。
[skip azp]
:跳过 Azure 作业Azure 是所有综合测试的运行地点。这是一项昂贵的运行,通常如果您只进行文档更改,就可以跳过它。例如,如果您只进行文档更改,就可以跳过它。参阅这些检查的主要配置文件。
[skip circle]
:跳过 CircleCI 作业CircleCI 是我们构建文档并将生成的工件存储以供每个 PR 预览的地方。此检查还将运行所有文档字符串示例并验证其结果。如果您不进行文档更改,但更改了函数 API,例如,您可能需要运行这些测试以验证 doctests 是否仍然有效。参阅这些检查的配置文件。
[skip cirrus]
:跳过 Cirrus 作业CirrusCI 主要触发 Linux aarch64 和 MacOS Arm64 wheel 上传。参阅这些检查的配置文件。
测试构建 wheels#
Numpy 目前使用 cibuildwheel 通过持续集成服务来构建 wheels。为了节省资源,cibuildwheel 的 wheel 构建器默认不会在每个 PR 或提交到 main 时运行。
如果您想测试您的拉取请求是否会破坏 wheel 构建器,可以通过在 PR 中最新提交的第一行提交消息后附加 [wheel build]
来实现。请仅对与构建相关的 PR 执行此操作,因为运行所有 wheel 构建既缓慢又昂贵。
通过 GitHub Actions 构建的 wheels(包括 64 位 Linux、x86-64 macOS 和 32/64 位 Windows)将作为工件上传到 zip 文件中。您可以从“Wheel builder”操作的“摘要”页面访问它们。通过 Cirrus CI 构建的 aarch64 Linux 和 arm64 macOS wheels 不作为工件提供。此外,在以下条件下,这些 wheels 将上传到 https://anaconda.org/scientific-python-nightly-wheels/
通过每周 cron 任务或
如果 GitHub Actions 或 Cirrus 构建已手动触发,这需要相应的权限
如果构建是由以 v
开头的仓库标签触发的,则 wheels 将上传到 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 邮件列表上征求意见也可能有用。
在 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 共享它。
首先将 NumPy 分叉到您的账户中,如创建自己的 scikit-image 副本(分叉)所述。
然后,转到您分叉的仓库 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
从现有拉取请求中检出更改#
如果您想测试拉取请求中的更改或在新拉取请求中继续工作,则需要将提交克隆到您分叉仓库的本地分支中
首先确保您的上游指向主仓库,如将您的仓库链接到上游仓库所述
然后,获取更改并创建本地分支。假设 $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 创建拉取请求。
将更改推送到主仓库#
需要对 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
标志,首先检查您是否即将将所需的更改推送到所需的位置。