开发工作流程#

按照制作您自己的 Matplotlib 副本(fork),您已经拥有自己的Matplotlib存储库的分叉副本。你已经设置了你的叉子。您已经按照配置 git 配置了 git。现在你已经准备好做一些真正的工作了。

工作流程摘要#

在下文中,我们将上游 Matplotlibmain分支称为“主干”。

  • 不要将您的main分支用于任何事情。考虑删除它。

  • 当您开始一组新的更改时,请从主干获取任何更改,并从中启动一个新的功能分支

  • 为每组可分离的更改创建一个新分支——“一个任务,一个分支”(ipython git 工作流)。

  • 为更改目的命名您的分支 - 例如 bugfix-for-issue-14refactor-database-code

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

  • 如果您确实发现自己从主干合并,请考虑在主干上重新定位

  • 如果您遇到困难,请在Matplotlib 邮件列表中询问。

  • 要求代码审查!

这种工作方式有助于保持工作井井有条,具有可读的历史记录。这反过来又使项目维护者(可能是你)更容易看到你做了什么,以及你为什么这样做。

有关一些解释,请参阅linux git 工作流ipython git 工作流

考虑删除你的主分支#

这听起来可能很奇怪,但删除你自己的main分支可以帮助减少你在哪个分支上的混淆。有关详细信息,请参阅在 github 上删除 main

更新主干镜像#

首先确保您已完成将存储库链接到上游存储库

您应该不时从 github 获取上游(主干)更改:

git fetch upstream

这将拉下您没有的任何提交,并将远程分支设置为指向正确的提交。例如,'trunk' 是由 (remote/branchname) 引用的分支upstream/main- 如果自上次检查后有提交,upstream/main则在您执行 fetch 后会更改。

创建一个新的功能分支#

当您准备好对代码进行一些更改时,您应该启动一个新分支。用于相关编辑集合的分支通常称为“功能分支”。

为每组相关更改创建一个新分支将使查看您的分支的人更容易看到您在做什么。

为分支选择一个信息丰富的名称,以提醒您自己和我们其他人分支中的更改是为了什么。例如add-ability-to-fly,或 bugfix-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

通常,您会希望将功能分支保留在Matplotlib的公共github 分支上。为此,您将这个新分支git 推送到您的 github 存储库。通常(如果您按照这些页面中的说明进行操作,并且默认情况下),git 将有一个指向您的 github 存储库的链接,名为. 你在 github 上推送到你自己的仓库:origin

git push origin my-new-feature

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

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

从现在开始,git 将知道这my-new-featuremy-new-featuregithub repo 中的分支有关。

编辑工作流程#

概述#

# 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)。git add new_file_name

  5. 要将所有修改后的文件提交到您的 repo 的本地副本中,请执行 . 注意 的选项 。该标志只是表示您将在命令行上键入一条消息。旗帜——你可以相信——或者看看为什么是 -a 旗帜?——以及在纠结的工作副本问题中有用的用例描述。git commit手册页也可能有用。git commit -am 'A commit message'-amcommitma

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

要求审核或合并您的更改#

当您准备要求某人审查您的代码并考虑合并时:

  1. 转到您的分叉存储库的 URL,例如 https://github.com/your-user-name/matplotlib.

  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

:注意前面的冒号my-unwanted-branch。另请参阅: https ://help.github.com/articles/pushing-to-a-remote/#deleting-a-remote-branch-or-tag

几个人共享一个存储库#

如果你想和其他人一起做一些事情,你都提交到同一个存储库,甚至是同一个分支,那么只需通过 github 共享它。

首先将 Matplotlib 分叉到您的帐户中,如制作您自己的 Matplotlib 副本(分叉)

然后,转到您的分叉存储库 github 页面,例如 https://github.com/your-user-name/matplotlib

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

../../_images/pull_button.png

现在所有这些人都可以做到:

git clone https://github.com/your-user-name/matplotlib.git

请记住,以https或开头的链接git@是可读写的,并且 git@使用 ssh 协议。

然后,您的合作者可以使用通常的方式直接提交到该 repo:

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

探索您的存储库#

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

gitk --all

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

git log

您还可以查看github 存储库的网络图可视化工具。

最后,Fancy 日志输出 lg别名将为您提供一个合理的基于文本的存储库图表。

基于主干#

假设你想到了一些你想做的工作。您 更新主干的镜像并创建一个名为 的新功能分支cool-feature。在这个阶段,主干处于某个提交状态,我们称它为 E。现在您在cool-feature分支上进行了一些新的提交,我们称它们为 A、B、C。也许您的更改需要一段时间,或者您在一段时间后返回它们。与此同时,主干已经从提交 E 进展到提交(比如说)G:

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

在这个阶段,您考虑将主干合并到您的功能分支中,并且您记得此页面严厉建议您不要这样做,因为历史会变得混乱。大多数情况下,您可以只要求进行审查,而不必担心后备箱已经领先了一点。但有时,主干的变化可能会影响你的变化,你需要协调它们。在这种情况下,您可能更喜欢做一个变基。

rebase 接受您的更改(A、B、C)并重播它们,就好像它们已经对trunk. 换句话说,在这种情况下,它采用 A、B、C 表示的更改并在 G 之上重放它们。在 rebase 之后,您的历史记录将如下所示:

              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

在这种情况下,您已经在 branch 上cool-feature,最后一个命令可以更简洁地编写为:

git rebase upstream/main

当一切看起来不错时,您可以删除备份分支:

git branch -D tmp

如果它看起来不太好,您可能需要看看 Recovering from mess-ups

如果您对主干中的文件进行了更改,这可能会产生您需要解决的合并冲突 - 请参阅git rebase手册页以获取“描述”部分末尾的一些说明。在 git 用户手册中有一些关于合并的相关帮助 - 请参阅解决合并

从混乱中恢复#

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

如果你在 rebase 期间搞砸了:

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 [email protected]{0}: commit: BUG: io: close file handles immediately
278dd2a [email protected]{1}: rebase finished: refs/heads/my-feature-branch onto 11ee694744f2552d
26aa21a [email protected]{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 [email protected]{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更明智的内容。

  • 将提交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

如果出错,则可以再次进行恢复,如上所述