开发工作流程

您已经拥有自己的 NumPy 存储库的分叉副本, 通过以下方式 制作自己的NumPy副本(Fork)以及 设置您的fork,您已经按照Git配置git , 并且已经链接了上游存储库,如将您的存储库链接到上游仓库中所述。

下面介绍的是Git的推荐工作流程。

基本工作流程

简而言之:

  1. 为您执行的每组编辑启动一个新 功能分支 。见下文
  2. 就是干!见下文
  3. 等结束了:
    • 贡献者:将您的功能分支推送到您自己的Github仓库,并 创建一个拉取请求
    • 核心开发者:如果想更改推不进一步审查,看笔记如下

这种工作方式有助于使工作井井有条,并使历史尽可能清晰。

::: tip 另见

有许多在线教程可以帮助您学习git。有关特定git工作流的讨论,请参阅有关linux git工作流ipython git工作流的这些讨论。

:::

创建新的功能分支

首先,从upstream存储库中获取新的提交:

  1. git fetch upstream

然后,基于上游存储库的主分支创建新分支:

  1. git checkout -b my-new-feature upstream/master

编辑工作流程

概述

  1. # hack hack
  2. git status # Optional
  3. git diff # Optional
  4. git add modified_file
  5. git commit
  6. # push the branch to your own Github repo
  7. git push origin my-new-feature

更详细的内容

  1. 做一些更改之后,当您感觉您已经完成了一组完整的相关更改的工作集时,请继续执行下一步。
  2. 可选:检查哪些文件已使用git状态更改(请参阅git状态)。您将看到如下所示的清单:
    1. # On branch my-new-feature
    2. # Changed but not updated:
    3. # (use "git add <file>..." to update what will be committed)
    4. # (use "git checkout -- <file>..." to discard changes in working directory)
    5. #
    6. # modified: README
    7. #
    8. # Untracked files:
    9. # (use "git add <file>..." to include in what will be committed)
    10. #
    11. # INSTALL
    12. no changes added to commit (use "git add" and/or "git commit -a")
  3. 可选:将更改与 git diffgit diff)一起使用的以前版本进行比较。这将显示一个简单的文本浏览器界面,突出显示您的文件与以前版本之间的差异。
  4. 使用 git add modify_file 添加任何相关的已修改或新文件(请参阅 git add)。这会将文件放入暂存区域,该区域是将添加到下一次提交的文件队列。仅添加具有相关完整更改的文件。留有未完成更改的文件供以后提交。
  5. 要将暂存的文件提交到仓库的本地副本中,请执行 git commit。此时,将打开一个文本编辑器,允许您编写提交消息。阅读提交消息部分,确保您正在编写格式正确且足够详细的提交消息。保存消息并关闭编辑器后,您的提交将被保存。对于琐碎的提交,可以使用 -m 标志通过命令行传递简短的提交消息。例如,git commit -am "ENH: Some message"
  6. 在某些情况下,您将看到这种形式的 commit 命令:git commit -a。 额外的 -a 标志自动提交所有已修改的文件并删除所有已删除的文件。 这可以节省一些 git add 命令的输入; 但是,如果您不小心,它可以为提交添加不需要的更改。 有关更多信息,请参阅为什么-a标志?,以及纠结的工作副本问题中有用的用例描述。
  7. 将更改推送到GitHub上的主仓库分支:

    1. git push origin my-new-feature

    有关更多信息,请参见git推送(git push)

::: tip 注意

假设您已按照这些页面中的说明操作,git将创建一个指向您的github repo 的默认链接origin。在git> = 1.7中,您可以使用以下--set-upstream选项确保永久设置到origin的链接:

  1. git push --set-upstream origin my-new-feature

从现在开始,git将知道这my-new-featuremy-new-feature您自己的github仓库中的分支有关。随后的推送调用命令将简化为以下写法:

  1. git push

您必须使用 --set-upstream 创建的每个新分支。

:::

可能的情况是,当您处理编辑时,会添加新的提交,upstream 这会影响您的工作。 在这种情况下,请按照本文档的 Rebasing on master 部分将这些更改应用于您的分支。

编写提交消息

提交消息应该是明确的,并遵循一些基本规则。例:

  1. ENH: add functionality X to numpy.<submodule>.
  2. The first line of the commit message starts with a capitalized acronym
  3. (options listed below) indicating what type of commit this is. Then a blank
  4. line, then more text if needed. Lines shouldn't be longer than 72
  5. characters. If the commit is related to a ticket, indicate that with
  6. "See #3456", "See ticket 3456", "Closes #3456" or similar.

描述变更的动机,bug修复的bug的本质,或者关于增强所做的一些细节,也可以包含在提交消息中。 消息应该是可以理解的,而不需要查看代码更改。像 Maint:Fixed Another one 这样的提交消息就是不应该做的事情的一个例子; 读者必须到别处去寻找上下文。

启动提交消息的标准首字母缩写词是:

  1. API: an (incompatible) API change
  2. BENCH: changes to the benchmark suite
  3. BLD: change related to building numpy
  4. BUG: bug fix
  5. DEP: deprecate something, or remove a deprecated object
  6. DEV: development tool or utility
  7. DOC: documentation
  8. ENH: enhancement
  9. MAINT: maintenance commit (refactoring, typos, etc.)
  10. REV: revert an earlier commit
  11. STY: style fix (whitespace, PEP8)
  12. TST: addition or modification of tests
  13. REL: related to releasing numpy

要求您的更改与主仓库合并

当您觉得您的工作已经完成时,您可以创建拉取请求(PR)。Github有一个很好的帮助页面,概述了提交拉取请求的过程。

如果您的更改涉及API的修改或功能的添加/修改,您应该:

  • 发送电子邮件到NumPy邮件列表,其中包含您PR的链接以及您的更改的描述和动机。这可能会产生变化和反馈。如果您的更改可能存在争议,那么从这一步骤开始可能是谨慎的做法。
  • doc/release/upcoming_changes/按照doc/release/upcoming_changes/README.rst文件中的说明和格式向目录 添加发行说明。

重新拉取主分支

这将通过上游NumPy github存储库的更改来更新您的功能分支。如果你不是绝对需要这样做,尽量避免这样做,除非你完成了。第一步是使用来自上游的新提交更新远程存储库:

  1. git fetch upstream

接下来,您需要更新功能分支:

  1. # go to the feature branch
  2. git checkout my-new-feature
  3. # make a backup in case you mess up
  4. git branch tmp my-new-feature
  5. # rebase on upstream master branch
  6. git rebase upstream/master

如果您对上游已更改的文件进行了更改,则可能会生成需要解决的合并冲突。在这种情况下,请参阅 下面的帮助。

最后,在成功的rebase后删除备份分支:

  1. git branch -D tmp

::: tip 注意

在master上重新绑定比将上游合并到您的分支更受欢迎。在处理功能分支时使用和不鼓励使用。git mergegit pull``

:::

从混乱中恢复

有时候,你搞砸了合并或重组。幸运的是,在Git中,从这些错误中恢复是相对简单的。

如果你在一次变革中陷入困境:

  1. git rebase --abort

如果你注意到在rebase之后搞砸了你:

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

如果您忘记创建备份分支:

  1. # look at the reflog of the branch
  2. git reflog show my-feature-branch
  3. 8630830 my-feature-branch@{0}: commit: BUG: io: close file handles immediately
  4. 278dd2a my-feature-branch@{1}: rebase finished: refs/heads/my-feature-branch onto 11ee694744f2552d
  5. 26aa21a my-feature-branch@{2}: commit: BUG: lib: make seek_gzip_factory not leak gzip obj
  6. ...
  7. # reset the branch to where it was before the botched rebase
  8. git reset --hard my-feature-branch@{2}

如果您实际上并没有陷入困境,但存在合并冲突,则需要解决这些问题。这可能是一个比较棘手的事情。有关如何执行此操作的详细说明,请参阅有关合并冲突的文章

您可能想要做的其他事情

重写提交历史

::: tip 注意

仅对您自己的功能分支执行此操作。

:::

你做出的承诺中有一个令人尴尬的错字?或许你做了几个错误的开始,你希望后人不要看。

这可以通过 交互式变基 来完成。

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

  1. git log --oneline
  2. eadc391 Fix some remaining bugs
  3. a815645 Modify it so that it works
  4. 2dec1ac Fix a few bugs + disable
  5. 13d7934 First implementation
  6. 6ad92e5 * masked is now an instance of a new object, MaskedConstant
  7. 29001ed Add pre-nep for a copule of structured_array_extensions.
  8. ...

并且6ad92e5master分支中的最后一次提交。假设我们要进行以下更改:

  • 重写提交消息以13d7934获得更明智的信息。
  • 合并的提交2dec1aca815645eadc391到一个单一的一个。

我们做如下:

  1. # make a backup of the current state
  2. git branch tmp HEAD
  3. # interactive rebase
  4. git rebase -i 6ad92e5

这将打开一个编辑器,其中包含以下文本:

  1. pick 13d7934 First implementation
  2. pick 2dec1ac Fix a few bugs + disable
  3. pick a815645 Modify it so that it works
  4. pick eadc391 Fix some remaining bugs
  5. # Rebase 6ad92e5..eadc391 onto 6ad92e5
  6. #
  7. # Commands:
  8. # p, pick = use commit
  9. # r, reword = use commit, but edit the commit message
  10. # e, edit = use commit, but stop for amending
  11. # s, squash = use commit, but meld into previous commit
  12. # f, fixup = like "squash", but discard this commit's log message
  13. #
  14. # If you remove a line here THAT COMMIT WILL BE LOST.
  15. # However, if you remove everything, the rebase will be aborted.
  16. #

为了实现我们想要的目标,我们将对其进行以下更改:

  1. r 13d7934 First implementation
  2. pick 2dec1ac Fix a few bugs + disable
  3. f a815645 Modify it so that it works
  4. f eadc391 Fix some remaining bugs

这意味着(i)我们想要编辑提交消息 13d7934,以及(ii)将最后三个提交合并为一个。现在我们保存并退出编辑器。

然后,Git会立即调出一个编辑器来编辑提交消息。修改后,我们得到输出:

  1. [detached HEAD 721fc64] FOO: First implementation
  2. 2 files changed, 199 insertions(+), 66 deletions(-)
  3. [detached HEAD 0f22701] Fix a few bugs + disable
  4. 1 files changed, 79 insertions(+), 61 deletions(-)
  5. Successfully rebased and updated refs/heads/my-feature-branch.

历史现在看起来像这样:

  1. 0f22701 Fix a few bugs + disable
  2. 721fc64 ENH: Sophisticated feature
  3. 6ad92e5 * masked is now an instance of a new object, MaskedConstant

如果出现问题,可以再次进行恢复,如上所述

删除github上的分支

  1. git checkout master
  2. # delete branch locally
  3. git branch -D my-unwanted-branch
  4. # delete branch on github
  5. git push origin :my-unwanted-branch

(请注意:以前的冒号test-branch。另请参阅:https//github.com/guides/remove-a-remote-branch

几个人共享一个存储库

如果你想与其他人一起工作,你们都在同一个存储库,甚至同一个分支中,那么只需通过github共享它。

首先将NumPy分配到您的帐户,例如从NumPy 制作您自己的副本(分叉)

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

点击“管理”按钮,然后将其他任何人作为协作者添加到仓库:

pull_button

现在这些人都能做到:

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

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

然后,您的协作者可以通常使用以下方式直接进入该回购:

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

探索您的存储库

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

  1. gitk --all

要查看此分支的提交历史列表:

  1. git log

您也可以在 网络图形可视化 工具中查看您的 GitHub 仓库。

反向移植

Backporting是将numpy / master中提交的新功能/修复复制 回稳定版本分支的过程。要做到这一点,你要从你正在向后移植的分支上做一个分支,樱桃挑选你想要的提交 numpy/master,然后提交一个包含backport的分支的pull请求。

  1. 首先,您需要创建要处理的分支。这需要基于较旧版本的NumPy(而不是master):
    1. # Make a new branch based on numpy/maintenance/1.8.x,
    2. # backport-3324 is our new name for the branch.
    3. git checkout -b backport-3324 upstream/maintenance/1.8.x
  2. 现在您需要使用git cherry-pick将变更从master应用到这个分支。
    1. # Update remote
    2. git fetch upstream
    3. # Check the commit log for commits to cherry pick
    4. git log upstream/master
    5. # This pull request included commits aa7a047 to c098283 (inclusive)
    6. # so you use the .. syntax (for a range of commits), the ^ makes the
    7. # range inclusive.
    8. git cherry-pick aa7a047^..c098283
    9. ...
    10. # Fix any conflicts, then if needed:
    11. git cherry-pick --continue
  3. 你可能会在这里遇到一些挑战。这些解决方法与 merge/rebase 冲突的解决方式相同。除了这里你可以使用 git blame 来查看 master 和 backported 分支之间的区别,以确保没有再搞砸别的事情了。
  4. 将新分支推送到Github存储库:
    1. git push -u origin backport-3324
  5. 最后使用Github发出拉取请求。确保它是针对维护分支而不是主分支,Github通常会建议你对master进行pull请求。

将更改推送到主分支

仅当您拥有主NumPy仓库的提交权限时,这才有意义。

如果您准备好NumPy mastermaintenance分支的功能分支中有一组 “就绪” 更改,则可以按upstream如下方式将它们推送到:

  1. 首先,在目标分支上合并(merge)或变基(rebase)。
    1. 只有几个不相关的提交会更倾向于 rebase:
      1. git fetch upstream
      2. git rebase upstream/master
      参见 master分支上的rebase.
    2. 如果所有提交都相关,请创建合并提交:
      1. git fetch upstream
      2. git merge --no-ff upstream/master
  2. 检查你要推动的东西看起来是明智的:
    1. git log -p upstream/master..
    2. git log --oneline --graph
  3. 推送到上游:
    1. git push upstream my-feature-branch:master

::: tip 注意

通常最好使用-n标志来检查您是否要将所需的更改推送到所需的位置。git push

:::