开发工作流#

通过遵循 制作你自己的 scikit-image 副本(分支),你已经拥有自己的 scikit-image 仓库的分支副本了。你已 设置好你的分支。你按照 配置 git 的说明配置好了 git。现在你可以开始真正的工作了。

工作流摘要#

在下文中,我们将把上游 scikit-image 的 main 分支称为“主干”。

  • 不要将你的 main 分支用于任何操作。考虑将其删除。

  • 当你开始一组新变更时,从主干提取任何变更,然后从那里启动一个新的功能分支

  • 为每组可分离变更制作一个新分支 — “一项任务,一个分支”(ipython git 工作流)。

  • 为你的分支指定一个变更目的的名称 - 例如 bugfix-for-issue-14refactor-database-code

  • 如果你有可能避免,在工作时请避免将主干或任何其他分支合并到你的功能分支中。

  • 如果你发现自己要合并主干,可以考虑在主干上进行重定基

  • 如果你遇到困难,可以到scikit-image 开发者论坛寻求帮助。

  • 索取代码审核!

这样做可以有效地组织工作,并保留可读的历史记录。这反过来让项目维护者(也许就是你)更容易地了解你做了什么,以及为什么要这么做。

请查看linux git 工作流ipython git 工作流来了解相关说明。

考虑删除你的 main 分支#

听起来可能很奇怪,但删除你自己的main分支可以帮助减少有关你所在分支的困惑。详细内容请参见在 github 中删除 master(将master替换为main)。

更新主干镜像#

首先请确保你已经完成将你的代码库链接到上游代码库

你要时不时从 github 获取上游(主干)更改

git fetch upstream

这样做会拉取你没有的任何提交记录,并设置远程分支指向正确的提交记录。例如,‘trunk’ 是由(远程/分支名)upstream/main引用的分支 - 如果你上次检查后已经有了提交记录,upstream/main在你执行了获取操作后将发生更改。

创建一个新的功能分支#

你准备对代码进行一些更改时,你应该开始一个新分支。用于收集相关编辑的分支通常被称为‘功能分支’。

针对每组相关更改创建一个新分支将让审查你分支的人员更容易了解你正在进行的操作。

为你的分支选择一个有帮助的名称,用来提醒自己和其他人该分支中的更改是为了什么。例如add-ability-to-flybuxfix-for-issue-42

# Update the mirror of trunk
git fetch upstream
# Make new feature branch starting at current trunk
git branch my-new-feature upstream/main
git checkout my-new-feature

一般来说,您会希望在 githubscikit-image 公共分叉上保留您的特性分支。为此,您可以 git push 将此新分支推送到您的 github 存储库。通常情况下(如果您按照本指南中的说明操作,并且在默认情况下),git 会将 origin 称为指向您 github 存储库的链接。您可以使用以下命令将内容推送到 github 上的自己的存储库:

git push origin my-new-feature

在 git >= 1.7 中,您可以使用 --set-upstream 选项确保正确设置链接

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

从现在开始,git 将知道 my-new-feature 与 github 存储库中的 my-new-feature 分支相关。

编辑工作流#

概述#

# hack hack
git add my_new_file
git commit -am 'NF - some message'
git push

更多详细信息#

  1. 进行一些更改

  2. 使用 git status 查看已更改的文件(请参阅 git status)。您会看到类似以下的列表

    # On branch ny-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 查看实际更改(git diff)。

  4. 将任何新文件添加到版本控制中 git add new_file_name(请参阅 git add)。

  5. 要将所有修改后的文件提交到存储库的本地副本中,请执行 git commit -am 'A commit message'。请注意提交时的 -am 选项。m 标记只是表示您将在命令行中输入一条消息。a 标记 — 您只需凭直觉理解即可 — 或参阅 为什么会有 -a 标记? — 以及 纠缠的工作副本问题 中有用的用例描述。可能 git commit 手册页也可能会有用。

  6. 要将更改推送到您的 github 分叉存储库,请执行 git push(请参阅 git push)。

请请求审阅或合并您的更改#

当您准备请他人审阅代码并考虑合并时

  1. 转到您的已分叉仓库的 URL,例如 https://github.com/your-user-name/scikit-image

  2. 使用页面左上角附近的“切换分支”下拉菜单以选择包含您更改的分支

    ../_images/branch_dropdown.png
  3. 单击“创建请求”按钮

    ../_images/pull_button.png

    为一组更改输入标题,并简要说明您已完成的操作。声明您希望特别关注的任何内容 - 例如复杂的更改或您不喜欢的某些代码。

    如果您认为您的请求尚未准备好合并,只需在您的请求信息中说明即可。这仍然是获得一些初步代码审阅的好方法。

您可能还想做的一些其他事情#

在 Github 上删除分支#

git checkout main
# delete branch locally
git branch -D my-unwanted-branch
# delete branch on github
git push origin :my-unwanted-branch

(注意 :test-branch 之前。另请参见:https://help.github.com/en/github/using-git/managing-remote-repositories

几个人共享一个仓库#

如果您想与其他人共同处理一些事情,其中你们都提交到同一仓库,甚至同一分支,那么只需通过 Github 共享即可。

首先将 scikit-image 分叉到您的帐户中,如从 创建您自己的 scikit-image 副本(分叉)

然后,转到您的分叉仓库 Github 页面,例如 https://github.com/your-user-name/scikit-image

单击“管理”按钮,并将其他任何人作为协作者添加到仓库中

../_images/pull_button.png

现在所有这些人都可以执行以下操作

git clone git@githhub.com:your-user-name/scikit-image.git

请记住,以 git@ 开头的链接使用 ssh 协议。

您的合作者随后可以使用通常的

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

探索您的仓库#

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

gitk --all

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

git log

您还可以查看 Github 仓库的 网络图可视化程序

最后,美观的日志输出 lg 别名将为您提供一个合理的文本型仓库图。

在干线上进行变基#

假设你想做些自己喜欢的工作。你可以 更新主干的镜像 然后 创建一个新的特性分支 称为 酷特性。在此阶段,主干处于某个提交状态,我们称之为 E。现在你在你的 酷特性 分支上做出了一些新提交,我们称之为 A、B、C。或许你的更改会花费一些时间,或者你过一段时间后又回到它们。同时,主干已经从提交 E 进展为提交(假设)G

      A---B---C cool-feature
     /
D---E---F---G trunk

在此阶段,你认为将主干合并到你的特性分支,并且你记得此页面严厉警告你不能这么做,因为这样会造成历史混乱。大多数时候你只需申请审查,而不用担心主干是否已经有一点领先。但是,有时候,主干中的更改可能会影响你的更改,你需要调和它们。在此情况下,你可能更愿意进行一次变基。

变基会采用你的更改(A、B、C),并将它们重复执行,就好像它们已经应用到了 主干 的当前状态。换句话说,在此情况下,它采用由 A、B、C 表示的更改,并将其重复应用到 G 的上方。在变基之后,你的历史将看起来像这样

              A'--B'--C' cool-feature
             /
D---E---F---G trunk

请参阅 浅谈变基 了解更详细的信息。

在主干上进行变基

# Update the mirror of trunk
git fetch upstream
# go to the feature branch
git checkout cool-feature
# make a backup in case you mess up
git branch tmp cool-feature
# rebase cool-feature onto trunk
git rebase --onto upstream/main upstream/main cool-feature

在此情况下,当你已经处于 酷特性 分支时,最后一个命令可以用更简洁的方式编写为

git rebase upstream/main

当一切看起来都不错时,你可以删除你的备份分支

git branch -D tmp

如果看起来不不错,你可能需要查看 从混乱中恢复

如果你对主干中也已经更改的文件进行了更改,这可能会生成需要你解决的合并冲突 - 请参阅 git 变基 手册页,“说明”部分末尾的某些说明。git 用户手册中有一些有关合并的相关帮助 - 请参阅 解决合并

从混乱中恢复#

有时,你会搞乱合并或变基。幸运的是,在 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 cool-feature

8630830 cool-feature@{0}: commit: BUG: io: close file handles immediately
278dd2a cool-feature@{1}: rebase finished: refs/heads/my-feature-branch onto 11ee694744f2552d
26aa21a cool-feature@{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 cool-feature@{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 copule of structured_array_extensions.
...

6ad92e5cool-feature 分支中的最后一个提交。假设我们想要进行以下更改

  • 13d7934 的提交消息重写为更有意义的内容。

  • 2dec1aca815645eadc391 合并为一个提交。

我们执行以下操作

# 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

如果出错,则仍有可能恢复,如上方所述。