章节 ▾ 第二版

6.3 GitHub - 维护项目

维护项目

现在我们已经熟悉了为项目做贡献,让我们来从另一个角度看看:创建、维护和管理自己的项目。

创建新仓库

让我们创建一个新的仓库来分享我们的项目代码。首先,点击仪表盘右侧的“新建仓库”按钮,或者点击顶部工具栏用户名旁边的 + 按钮,正如 “新建仓库”下拉菜单 中所示。

The “Your repositories” area
图 109. “我的仓库”区域
The “New repository” dropdown
图 110. “新建仓库”下拉菜单

这将带您进入“新建仓库”表单

The “new repository” form
图 111. “新建仓库”表单

您在这里只需要提供一个项目名称;其余字段完全是可选的。现在,只需点击“创建仓库”按钮,就完成啦——您在 GitHub 上有了一个新仓库,名为 <user>/<project_name>

由于您还没有代码,GitHub 会显示如何创建全新的 Git 仓库或连接现有 Git 项目的说明。我们在此不多赘述;如果您需要回顾,请查看 Git 基础

现在您的项目托管在 GitHub 上,您可以将 URL 提供给任何您想与之分享项目的人。GitHub 上的每个项目都可以通过 HTTPS 访问,URL 为 https://github.com/<user>/<project_name>,或者通过 SSH 访问,URL 为 git@github.com:<user>/<project_name>。Git 可以从这两个 URL 获取和推送,但它们都受连接用户的凭据控制。

注意

对于公开项目,分享基于 HTTPS 的 URL 通常更可取,因为用户在克隆时不需要 GitHub 账户即可访问。如果提供 SSH URL,用户将需要一个账户并上传 SSH 密钥才能访问您的项目。HTTPS URL 也与用户在浏览器中查看项目时粘贴的 URL 完全相同。

添加协作者

如果您正在与其他希望获得提交权限的人合作,您需要将他们添加为“协作者”。如果 Ben、Jeff 和 Louise 都注册了 GitHub 账户,并且您想给他们推送到您的仓库的权限,您可以将他们添加到您的项目。这样做会赋予他们“推送”权限,这意味着他们对项目和 Git 仓库拥有读写权限。

点击右侧边栏底部的“设置”链接。

The repository settings link
图 112. 仓库设置链接

然后从左侧菜单选择“协作者”。接着,只需在框中输入用户名,然后点击“添加协作者”。您可以根据需要重复此操作,为您喜欢的任何人授予访问权限。如果您需要撤销访问权限,只需点击他们行右侧的“X”。

The repository collaborators box
图 113. 仓库协作者框

管理拉取请求

现在您有了一个包含一些代码,甚至可能还有一些拥有推送权限的协作者的项目,让我们来看看当您收到拉取请求时该怎么做。

拉取请求可能来自您仓库的 fork 中的分支,也可能来自同一仓库中的另一个分支。唯一的区别是,来自 fork 的拉取请求通常来自您无法推送到其分支的人,而他们也无法推送到您的分支;而对于内部拉取请求,双方通常都可以访问分支。

在这些示例中,我们假设您是“tonychacon”,并且您创建了一个名为“fade”的新的 Arduino 代码项目。

电子邮件通知

有人修改了您的代码并向您发送了一个拉取请求。您应该会收到一封通知您新拉取请求的电子邮件,它看起来会像 新拉取请求的电子邮件通知

Email notification of a new Pull Request
图 114. 新拉取请求的电子邮件通知

关于这封邮件有几点需要注意。它会给您一个小的 diffstat——一个已更改文件列表以及更改的多少。它提供了一个指向 GitHub 上拉取请求的链接。它还提供了一些可以从命令行使用的 URL。

如果您注意到“git pull <url> patch-1”这一行,这是在不添加远程仓库的情况下合并远程分支的一种简单方法。我们在 检出远程分支 中快速回顾过这一点。如果您愿意,可以创建一个主题分支并切换到该分支,然后运行此命令来合并拉取请求的更改。

其他有趣的 URL 是 .diff.patch URL,正如您可能猜到的,它们提供统一的 diff 和 patch 格式的拉取请求。您实际上可以像这样合并拉取请求的工作:

$ curl https://github.com/tonychacon/fade/pull/1.patch | git am

协作处理拉取请求

正如我们在 GitHub Flow 中所讲,您现在可以与打开拉取请求的人进行对话。您可以使用 GitHub Flavored Markdown 在任何地方评论特定的代码行、整个提交或整个拉取请求本身。

每次其他人评论拉取请求时,您都会继续收到电子邮件通知,以便您了解正在发生的活动。每封邮件都会有一个指向发生活动的拉取请求的链接,您也可以直接回复电子邮件来评论拉取请求线程。

Responses to emails are included in the thread
图 115. 对电子邮件的回复会包含在讨论串中

一旦代码到了您喜欢并且想要合并它的地方,您就可以将代码拉下来并在本地合并,可以使用我们之前看到的 git pull <url> <branch> 语法,或者将 fork 添加为远程仓库并进行获取和合并。

如果合并很简单,您也可以直接点击 GitHub 网站上的“合并”按钮。这将执行“非快进”合并,即使可以进行快进合并也会创建合并提交。这意味着,无论如何,每次点击合并按钮时,都会创建一个合并提交。正如您在 合并按钮和手动合并拉取请求的说明 中看到的,如果您点击提示链接,GitHub 会为您提供所有这些信息。

Merge button and instructions for merging a Pull Request manually
图 116. 合并按钮和手动合并拉取请求的说明

如果您决定不想合并它,也可以直接关闭拉取请求,打开它的人将会收到通知。

拉取请求引用

如果您处理的拉取请求**非常多**,并且不想每次都添加大量远程仓库或进行一次性拉取,GitHub 提供了一个巧妙的技巧。这有点高级,我们将在 Refspec 中更详细地介绍,但它可能非常有用。

GitHub 实际上将仓库的拉取请求分支作为服务器上的伪分支进行宣传。默认情况下,您在克隆时不会获取它们,但它们以一种隐藏的方式存在,并且您可以很容易地访问它们。

为了演示这一点,我们将使用一个低级命令(通常称为“plumbing”命令,我们将在 Plumbing and Porcelain 中了解更多)称为 ls-remote。这个命令通常不用于日常 Git 操作,但它很有用,可以显示服务器上存在哪些引用。

如果我们针对之前使用的“blink”仓库运行此命令,我们将获得仓库中所有分支、标签和其他引用的列表。

$ git ls-remote https://github.com/schacon/blink
10d539600d86723087810ec636870a504f4fee4d	HEAD
10d539600d86723087810ec636870a504f4fee4d	refs/heads/master
6a83107c62950be9453aac297bb0193fd743cd6e	refs/pull/1/head
afe83c2d1a70674c9505cc1d8b7d380d5e076ed3	refs/pull/1/merge
3c8d735ee16296c242be7a9742ebfbc2665adec1	refs/pull/2/head
15c9f4f80973a2758462ab2066b6ad9fe8dcf03d	refs/pull/2/merge
a5a7751a33b7e86c5e9bb07b26001bb17d775d1a	refs/pull/4/head
31a45fc257e8433c8d8804e3e848cf61c9d3166c	refs/pull/4/merge

当然,如果您在您的仓库中并运行 git ls-remote origin 或您想检查的任何其他远程仓库,它会显示类似的内容。

如果仓库在 GitHub 上并且您有任何已打开的拉取请求,您将获得以 refs/pull/ 为前缀的这些引用。这些基本上是分支,但由于它们不在 refs/heads/ 下,所以您在正常克隆或从服务器获取时不会得到它们——获取过程通常会忽略它们。

每个拉取请求有两个引用——以 /head 结尾的引用指向与拉取请求分支的最后一个提交完全相同的提交。因此,如果有人在我们的仓库中打开了一个拉取请求,并且他们的分支名为 bug-fix,并且指向提交 a5a775,那么在**我们**的仓库中,我们不会有一个 bug-fix 分支(因为它在他们的 fork 中),但我们**会**有一个 pull/<pr#>/head 指向 a5a775。这意味着我们可以一次性轻松地拉取所有拉取请求分支,而无需添加大量远程仓库。

现在,您可以直接获取该引用。

$ git fetch origin refs/pull/958/head
From https://github.com/libgit2/libgit2
 * branch            refs/pull/958/head -> FETCH_HEAD

这告诉 Git:“连接到 origin 远程仓库,并下载名为 refs/pull/958/head 的引用。” Git 会愉快地执行,下载构建该引用所需的所有内容,并将一个指向您想要的提交的指针放在 .git/FETCH_HEAD 下。您可以接着使用 git merge FETCH_HEAD 将其合并到您想测试它的分支中,但那个合并提交的消息看起来有点奇怪。此外,如果您正在审查**大量**拉取请求,这会很繁琐。

还有一种方法可以获取**所有**拉取请求,并在您连接到远程仓库时保持它们的更新。用您喜欢的编辑器打开 .git/config,找到 origin 远程仓库。它应该看起来像这样:

[remote "origin"]
    url = https://github.com/libgit2/libgit2
    fetch = +refs/heads/*:refs/remotes/origin/*

fetch = 开头的哪一行是“refspec”。它是一种将远程仓库上的名称映射到本地 .git 目录中名称的方法。这一行特别告诉 Git:“远程仓库中 refs/heads 下的东西应该放在我的本地仓库的 refs/remotes/origin 下。”您可以修改此部分以添加另一个 refspec:

[remote "origin"]
    url = https://github.com/libgit2/libgit2.git
    fetch = +refs/heads/*:refs/remotes/origin/*
    fetch = +refs/pull/*/head:refs/remotes/origin/pr/*

最后一行告诉 Git:“所有看起来像 refs/pull/123/head 的引用都应该本地存储为 refs/remotes/origin/pr/123。”现在,如果您保存该文件,然后执行 git fetch

$ git fetch
# …
 * [new ref]         refs/pull/1/head -> origin/pr/1
 * [new ref]         refs/pull/2/head -> origin/pr/2
 * [new ref]         refs/pull/4/head -> origin/pr/4
# …

现在所有远程的拉取请求都在本地以类似跟踪分支的方式表示;它们是只读的,并且在您执行 fetch 时会更新。这使得在本地尝试拉取请求中的代码非常容易。

$ git checkout pr/2
Checking out files: 100% (3769/3769), done.
Branch pr/2 set up to track remote branch pr/2 from origin.
Switched to a new branch 'pr/2'

敏锐的读者会注意到 refspec 远程部分末尾的 head。GitHub 端还有一个 refs/pull/#/merge 引用,它代表如果您在网站上点击“合并”按钮所产生的提交。这允许您在点击按钮之前测试合并。

拉取请求的拉取请求

您不仅可以打开针对主分支或 master 分支的拉取请求,实际上还可以打开针对网络中任何分支的拉取请求。事实上,您甚至可以针对另一个拉取请求。

如果您看到一个拉取请求朝着正确的方向发展,并且您有一个基于它的更改想法,或者您不确定这个想法是否好,或者您只是没有目标分支的推送权限,您可以直接向它打开一个拉取请求。

当您打开拉取请求时,页面顶部有一个框,指定您要拉取到哪个分支以及从哪个分支拉取。如果您点击该框右侧的“编辑”按钮,您不仅可以更改分支,还可以更改 fork。

Manually change the Pull Request target fork and branch
图 117. 手动更改拉取请求的目标 fork 和分支

在这里,您可以非常轻松地指定将您的新分支合并到另一个拉取请求或项目的另一个 fork 中。

提及和通知

GitHub 还内置了一个相当不错的通知系统,当您有疑问或需要特定个人或团队的反馈时,它会很有用。

在任何评论中,您可以开始输入 @ 字符,它将开始自动完成项目中协作者或贡献者的姓名和用户名。

Start typing @ to mention someone
图 118. 输入 @ 来提及某人

您也可以提及下拉列表中没有的用户,但自动补全通常可以加快速度。

一旦您发布包含用户提及的评论,该用户就会收到通知。这意味着这是一种将人们引入对话的有效方式,而不是让他们轮询。在 GitHub 的拉取请求中,人们经常会拉入他们团队中或公司中的其他人来审查问题或拉取请求。

如果某人在拉取请求或问题中被提及,他们将被“订阅”该项,并在发生任何活动时继续收到通知。如果您打开了某项,或者您正在关注某个仓库,或者您评论了某项,您也会被订阅。如果您不再希望收到通知,页面上有一个“取消订阅”按钮,您可以点击它来停止接收更新。

Unsubscribe from an Issue or Pull Request
图 119. 取消订阅某个问题或拉取请求

通知页面

当我们在 GitHub 中提到“通知”时,我们指的是 GitHub 在事件发生时与您联系的一种特定方式,并且有几种不同的配置方式。如果您从设置页面转到“通知中心”选项卡,您可以看到一些可用的选项。

Notification center options
图 120. 通知中心选项

您可以选择通过“电子邮件”和“Web”接收通知,对于您积极参与的事项和您正在关注的仓库的活动,您可以选择其中一项、都不选或两者都选。

Web 通知

Web 通知仅存在于 GitHub 上,并且您只能在 GitHub 上查看它们。如果您在首选项中选择了此选项,并且触发了通知,您将在屏幕顶部的通知图标上看到一个小的蓝色圆点,如 通知中心 所示。

Notification center
图 121. 通知中心

如果您点击它,您将看到一个列表,其中包含您被通知到的所有项目,按项目分组。您可以通过单击左侧边栏中的项目名称来过滤特定项目的通知。您还可以通过单击任何通知旁边的复选标记图标来确认通知,或者通过单击组顶部的复选标记来确认一个项目中的**所有**通知。每个复选标记旁边还有一个静音按钮,您可以点击它来停止接收该项目的进一步通知。

所有这些工具对于处理大量通知都非常有用。许多 GitHub 高级用户会完全关闭电子邮件通知,并通过此屏幕管理所有通知。

电子邮件通知

电子邮件通知是您可以通过 GitHub 处理通知的另一种方式。如果您开启此选项,您将收到每条通知的电子邮件。我们在 作为电子邮件通知发送的评论新拉取请求的电子邮件通知 中看到了这方面的示例。电子邮件也会被正确地进行线程化,如果您使用支持线程的电子邮件客户端,这会很好。

GitHub 发送的电子邮件头部还嵌入了相当多的元数据,这对于设置自定义过滤器和规则非常有帮助。

例如,如果我们查看在 新拉取请求的电子邮件通知 中显示的电子邮件发送给 Tony 的实际电子邮件头部,我们会发现以下信息:

To: tonychacon/fade <fade@noreply.github.com>
Message-ID: <tonychacon/fade/pull/1@github.com>
Subject: [fade] Wait longer to see the dimming effect better (#1)
X-GitHub-Recipient: tonychacon
List-ID: tonychacon/fade <fade.tonychacon.github.com>
List-Archive: https://github.com/tonychacon/fade
List-Post: <mailto:reply+i-4XXX@reply.github.com>
List-Unsubscribe: <mailto:unsub+i-XXX@reply.github.com>,...
X-GitHub-Recipient-Address: tchacon@example.com

这里有几件有趣的事情。如果您想突出显示或将电子邮件重新路由到此特定项目甚至拉取请求,Message-ID 中的信息以 <user>/<project>/<type>/<id> 格式提供了所有数据。例如,如果这是一个问题,<type> 字段将是“issues”而不是“pull”。

List-PostList-Unsubscribe 字段意味着,如果您有一个理解这些字段的邮件客户端,您可以轻松地发布到列表或“取消订阅”线程。这基本上与点击 Web 版本通知上的“静音”按钮或在问题或拉取请求页面本身上点击“取消订阅”相同。

还值得注意的是,如果您同时启用了电子邮件和 Web 通知,并且您阅读了通知的电子邮件版本,那么如果您在邮件客户端中允许显示图像,Web 版本也会被标记为已读。

特殊文件

GitHub 会注意到您仓库中的几个特殊文件。

README

第一个是 README 文件,它可以是 GitHub 识别为散文的几乎任何格式。例如,它可以是 READMEREADME.mdREADME.asciidoc 等。如果 GitHub 在您的源代码中看到 README 文件,它将在项目的登陆页面上渲染它。

许多团队使用此文件来存放所有相关的项目信息,供可能刚接触该仓库或项目的新人查阅。这通常包括以下内容:

  • 项目的作用

  • 如何配置和安装它

  • 如何使用它或使其运行的示例

  • 项目提供的许可证

  • 如何为其做出贡献

由于 GitHub 会渲染此文件,您可以在其中嵌入图像或链接以方便理解。

CONTRIBUTING

GitHub 识别的另一个特殊文件是 CONTRIBUTING 文件。如果您有一个名为 CONTRIBUTING 的文件(无论扩展名如何),当任何人开始打开拉取请求时,GitHub 将会显示 存在 CONTRIBUTING 文件时打开拉取请求

Opening a Pull Request when a CONTRIBUTING file exists
图 122. 存在 CONTRIBUTING 文件时打开拉取请求

这样做的目的是您可以指定您希望或不希望在发送到您项目的拉取请求中出现的内容。这样,人们在打开拉取请求之前可能会实际阅读指南。

项目管理

通常,您对单个项目可以进行的管理操作不多,但有几项可能值得关注。

更改默认分支

如果您使用的是“master”以外的分支作为默认分支,并且希望人们在其上打开拉取请求或默认查看该分支,您可以在仓库设置页面的“选项”选项卡下更改它。

Change the default branch for a project
图 123. 更改项目的默认分支

只需在下拉列表中更改默认分支,它将成为之后所有主要操作的默认分支,包括当有人克隆仓库时默认检出的分支。

转移项目

如果您想将项目转移到 GitHub 上的另一个用户或组织,您的仓库设置页面的“选项”选项卡底部有一个“转移所有权”选项,允许您执行此操作。

Transfer a project to another GitHub user or Organization
图 124. 将项目转移到另一个 GitHub 用户或组织

这对于您放弃项目并有人想接管,或者您的项目变得越来越大并想将其移入组织时很有帮助。

这不仅会连同所有关注者和 Star 一起将仓库移动到其他地方,还会从您的 URL 设置一个重定向到新的位置。它还将重定向 Git 的克隆和获取请求,而不仅仅是 Web 请求。