章节 ▾ 第二版

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(例如https://github.com/<user>/<project_name>)和 SSH(例如git@github.com:<user>/<project_name>)访问。Git 可以从这两个 URL 拉取(fetch)和推送(push),但它们会根据连接用户的凭据进行访问控制。

注意

对于公共项目,通常更推荐分享基于 HTTPS 的 URL,因为用户无需拥有 GitHub 账户即可克隆访问。如果你向他们提供 SSH URL,用户则必须拥有账户并上传 SSH 密钥才能访问你的项目。HTTPS 地址也正是他们会粘贴到浏览器中查看项目的 URL。

添加协作者

如果你与想要授予提交(commit)权限的其他人一起工作,你需要将他们添加为“协作者”。如果 Ben、Jeff 和 Louise 都在 GitHub 上注册了账户,并且你希望授予他们对你的仓库的推送(push)权限,你可以将他们添加到你的项目。这样做将赋予他们“推送”权限,这意味着他们对项目和 Git 仓库同时拥有读写访问权。

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

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

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

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

管理拉取请求

既然你拥有一个包含一些代码的项目,甚至可能还有一些拥有推送权限的协作者,那么让我们回顾一下当你自己收到拉取请求(Pull Request)时该怎么做。

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

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

邮件通知

有人对你的代码进行了更改并向你发送了拉取请求。你应该会收到一封关于新拉取请求的通知邮件,它应该看起来像新拉取请求的邮件通知

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

这封邮件有几点值得注意。它会给你一个简短的 diffstat——一个列出在拉取请求中更改了哪些文件以及更改了多少的列表。它还提供了指向 GitHub 上该拉取请求的链接。此外,它还提供了几个可以在命令行使用的 URL。

如果你注意到那行写着git pull <url> patch-1的命令,这是一种无需添加远程仓库即可合并远程分支的简单方法。我们之前在检出远程分支中简要介绍过这一点。如果你愿意,可以创建一个主题分支并切换到该分支,然后运行此命令来合并拉取请求的更改。

其他有趣的 URL 是.diff.patch URL,顾名思义,它们提供了拉取请求的统一差异(unified diff)和补丁(patch)版本。理论上,你可以用类似这样的方式合并拉取请求的工作:

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

在拉取请求上协作

正如我们在GitHub 流程中所介绍的,你现在可以与打开拉取请求的人进行对话。你可以评论特定的代码行、评论整个提交,或者评论整个拉取请求本身,并且处处使用 GitHub 风味 Markdown。

每次有人评论拉取请求时,你都会继续收到邮件通知,以便你了解正在进行的活动。每封邮件都将包含指向活动发生位置的拉取请求链接,你也可以直接回复邮件以评论拉取请求的讨论串。

Responses to emails are included in the thread
图 115. 邮件回复将包含在讨论串中

一旦代码达到你喜欢的状态并希望将其合并,你可以通过我们之前看到的git pull <url> <branch>语法在本地拉取代码并合并,或者通过将派生仓库添加为远程仓库然后拉取(fetch)并合并。

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

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

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

拉取请求引用

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

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

为了演示这一点,我们将使用一个低级命令(通常被称为“底层命令”,我们将在底层命令与日常命令中阅读更多相关内容),名为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/下,所以当你从服务器克隆或拉取(fetch)时通常不会获取它们——拉取过程通常会忽略它们。

每个拉取请求有两个引用——其中以/head结尾的引用指向的提交与拉取请求分支中的最新提交完全相同。因此,如果有人在我们的仓库中打开一个拉取请求,他们的分支名为bug-fix并指向提交a5a775,那么在我们的仓库中,我们将不会有一个bug-fix分支(因为那在他们的派生仓库中),但我们有一个指向a5a775pull/<pr#>/head引用。这意味着我们可以很容易地一次性拉取所有拉取请求分支,而无需添加一堆远程仓库。

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

$ 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下。” 你可以修改此部分以添加另一个引用规范:

[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'

眼尖的你可能会注意到引用规范的远程部分末尾的head。在 GitHub 端还有一个refs/pull/#/merge引用,它代表了如果你在网站上点击“合并”按钮后将产生的提交。这可以让你在点击按钮之前就测试合并。

基于拉取请求的拉取请求

你不仅可以打开以 main 或master分支为目标的拉取请求,实际上你还可以打开以网络中任何分支为目标的拉取请求。事实上,你甚至可以以另一个拉取请求为目标。

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

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

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

在这里,你可以相当容易地指定将你的新分支合并到另一个拉取请求或项目的另一个派生仓库中。

提及和通知

GitHub 还内置了一个非常好的通知系统,当你需要向特定个人或团队提问或征求反馈时,它会派上用场。

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

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

你也可以提及不在该下拉列表中的用户,但通常自动补全功能会更快。

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

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

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

通知页面

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

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

两种选择是通过“电子邮件”和“网页”接收通知,你可以选择两者之一、两者皆无或两者兼有,用于你积极参与的活动以及你关注的仓库的活动。

网页通知

网页通知只存在于 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字段意味着如果你有一个支持这些字段的邮件客户端,你可以轻松地向列表发帖或从讨论串中“取消订阅”。这与点击网页版通知上的“静音”按钮或议题或拉取请求页面上的“取消订阅”本质上是相同的。

还需要注意的是,如果你同时启用了电子邮件和网页通知,并且你阅读了邮件版本的通知,那么如果你的邮件客户端允许显示图片,网页版本也将被标记为已读。

特殊文件

如果你的仓库中存在一些特殊文件,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 用户或组织

如果你放弃了一个项目并且有人想接管它,或者如果你的项目变得越来越大并希望将其移到一个组织中,这将很有帮助。

这不仅会将仓库及其所有关注者和星标移动到另一个位置,还会设置从你的 URL 到新位置的重定向。它还会重定向 Git 的克隆(clones)和拉取(fetches),而不仅仅是网页请求。

scroll-to-top