Git正解 脱水版 【6. GitHub】

目前GitHub是规模最大的Git仓库的托管主机,它的中心服务器已容纳了数百万的开发者和项目,相当多的Git仓库都托管在GitHub,许多开源项目都在使用它,实现Git仓库,问题跟踪,代码浏览等功能,虽然GitHub不属于Git项目,但作为一个开发者,你迟早会遇见GitHub。

以下将介绍GitHub的一些细节,比如用户注册,账号挂你,创建和使用Git仓库,项目贡献的常用工作流,贡献接纳,以及GitHub编程接口和一些小技巧。

注意,由于时间的关系,GitHub的Web UI可能会发生变化,如果发生变化,请参考GitHub提供的最新指南。

6.1 账号注册和配置

首先需要注册一个免费账号,打开https://github.com页面,选择一个用户名,以及邮箱地址和密码,点击Sign up for GitHub按钮,
在这里插入图片描述
之后用户将看见一个账号升级的价格页面,当然这可获得一个更私密的环境,但目前并不需要,同时GitHub会向用户邮箱,发送一份验证邮件,以确认用户邮箱的有效性。注意,GitHub向免费用户开放了所有功能,但是免费用户只能创建公开项目,即所有人都可查看,如果升级成付费账号,则可创建私有项目。点击页面左上角的章鱼猫(Octocat,GitHub吉祥物),即可进入用户界面

ssh访问

此时用户已可使用http协议,连接Git仓库,并可使用用户名和密码,通过页面验证,如果只克隆一个公开项目,无需申请GitHub账号,有了GitHub账号之后,用户可以创建一个公开项目的副本,用于贡献代码。

如果需要ssh远程登录,则需配置一个公钥,点击页面右上角的账户设置链接,
在这里插入图片描述
选中左侧面板的SSH keys项,
在这里插入图片描述
点击Add an SSH key按钮,在Title文本框中设定公钥的名字,将用户的公钥文件(~/.ssh/id_rsa.pub)内容,复制到Key文本框中,再点击Add key按钮,则完成公钥生成,注意,在设定ssh公钥名称时,应设定一个有意义的名字,比如My Laptop或Work Account,方便将来取消公钥时,能直接获知公钥的用途。

变更用户信息

选中左侧面板的Profile项,再点击右侧的Upload new picture,可更改用户头像和信息。
在这里插入图片描述
GitHub基于邮件,发送贡献者的项目提交,如果用户需要使用多个邮箱地址,可告知GitHub,项目提交应发送到哪个邮箱,选中左侧面板的Emails项,配置不同用途的邮箱地址,
在这里插入图片描述
在Add email addresses标题栏中,输入邮箱地址,点击Add,可完成邮箱地址的添加,上图已添加了三个邮箱地址,首个邮箱已通过验证,并设定为主邮箱,这意味着所有的通知和邮件,都将发送到给邮箱,第二个邮箱已通过验证,如果需要设定为主邮箱,需点击右侧按钮,第三个邮箱未通过验证,还无法正常使用,如果GitHub在任意仓库的提交信息中,发现上述三个邮箱名,将会生成一个链接,直接指向用户的主页。

为了获得更好的安全性,用户还需配置双次验证(也是支付宝和微信的付款模式),如果用户密码不幸被盗,双次验证机制可减弱用户账号的未知风险,因此双次验证机制越来越流行,选中左侧面板的Security项,GitHub将询问用户,选择哪两种不同的验证方法,如果其中一种失效,黑客也无法访问用户账号,
在这里插入图片描述
点击Set up two-factor authentication按钮,将跳转到一个配置页面,用户可选择,使用手机app生成一个二级密码(带时限的一次性密码),或者在每次用户登录时,由GitHub使用短信,向用户发送一个登录密码。

6.2 项目贡献

完成用户账号的配置后,用户则可开始计划,为已有项目贡献代码。

项目副本

如果用户不拥有原始项目的推送权限,只能创建一个原始项目的副本,以方便贡献代码,而GitHub可为用户,创建一个原始项目的副本,并放置在用户空间,因此用户有权向该副本,推送数据。注意,在GitHub应用中,fork是指创建原始项目的副本,这与其他IT领域的含义稍有差别,在副本模式下,原始项目的维护者则无需烦恼,用户管理的诸多问题,普通用户可创建一个原始项目的副本,并推送自己的工作成果,再请求原始项目的维护者,接纳这些成果。

为了创建原始项目的副本,可点击页面右上角的Fork按钮
在这里插入图片描述
几秒之后,用户将跳转到原始项目的副本主页,

GitHub工作流

GitHub设计了一套特别的协作机制,重点在于,贡献者的请求接纳,这套机制不关心项目的规模,只是基于特性分支的运用,比如以下的工作流程,

  1. 贡献者创建原始项目的副本
  2. 贡献者基于master分支,创建一个特性分支
  3. 贡献者向特性分支,提交一些项目改进
  4. 贡献者将特性分支推送到GitHub
  5. 在GitHub上,贡献者向原始项目的维护者,发送一个接纳请求
  6. 贡献者发起后续改进的讨论
  7. 原始项目的维护者接纳或拒绝贡献者的提交
  8. 贡献者将原始项目的最新数据,同步到自己的副本

上述工作流类似于集中管理工作流,只是维护者与贡献者之间的通讯,未使用邮件。

创建接纳请求

Tony正在寻找,可运行在Arduino微控制器的代码,这时他在GitHub上,发现了一个类似的项目,https://github.com/schacon/blink,
在这里插入图片描述
但是该项目存在一个问题,LED闪烁的速度太快,需将延时从3秒改为1秒,因此Tony准备修改该项目,首先创建原始项目的副本,Tony的用户名为tonychacon,所以项目副本的地址为https://github.com/tonychacon/blink,之后将原始项目克隆到本地,再创建一个特性分支,完成代码修改,并推送到GitHub的项目副本,

$ git clone https://github.com/tonychacon/blink  // #1
Cloning into 'blink'...

$ cd blink
$ git checkout -b slow-blink  // #2
Switched to a new branch 'slow-blink'

$ sed -i '' 's/1000/3000/' blink.ino (macOS) // #3
# If you're on a Linux system, do this instead:
# $ sed -i 's/1000/3000/' blink.ino // #3

$ git diff --word-diff // #4
diff --git a/blink.ino b/blink.ino
index 15b9911..a6cc5a5 100644
--- a/blink.ino
+++ b/blink.ino
@@ -18,7 +18,7 @@ void setup() {
// the loop routine runs over and over again forever:
void loop() {
    digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
    [-delay(1000);-]{+delay(3000);+} // wait for a second
    digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
    [-delay(1000);-]{+delay(3000);+} // wait for a second
}

$ git commit -a -m 'three seconds is better' // #5
[slow-blink 5ca509d] three seconds is better
 1 file changed, 2 insertions(+), 2 deletions(-)

$ git push origin slow-blink // #6
Username for 'https://github.com': tonychacon
Password for 'https://[email protected]':
Counting objects: 5, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 340 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
To https://github.com/tonychacon/blink
 * [new branch] slow-blink -> slow-blink
  1. 将原始项目克隆到本地
  2. 创建特性分支
  3. 修改代码
  4. 测试代码
  5. 将修改提交到特性分支
  6. 将特性分支推送到GitHub的项目副本

这时在GitHub的项目副本中,多了一条新分支slow-blink,同时出现了一个绿色的矩形按钮Compare & pull request,点击它,可向原始项目,发出接纳请求,
在这里插入图片描述
或者进入Branches页面(https://github.com/<用户名>/<项目名>/branches),点击Create pull request按钮,可生成一次接纳请求,
在这里插入图片描述
点击上述两个按钮后,将出现一个对话框,请求用户提供,接纳请求的标题和描述,简洁明了的标题和描述,有利于原始项目的维护者理解贡献者的意图,并快速给出响应,当贡献者点击按钮后,原始项目的维护者将收到一个建议修改的通知,并附带了贡献者的页面链接,值得注意,虽然公开项目通常需要使用接纳请求,但在私有项目的初始阶段,也经常使用接纳请求,因为用户可在接纳请求发送之后,再推送特性分支,那么接纳请求的提前发送,有利于团队之间的项目迭代,而不是等到开发即将结束时,才发送接纳请求。

接纳请求的迭代

当原始项目的维护者看到修改建议后,可选择三种处理方式,合并,否决或讨论,讨论可选择邮件沟通,或者基于GitHub,实现在线沟通,因此维护者可点击差异代码的任意行,留下相关评论,当维护者给出评论后,发送接纳请求的贡献者,也将收到一个通知,
在这里插入图片描述
如果双方使用邮件沟通,Tony发出的邮件,如下,
在这里插入图片描述
同时在接纳请求的讨论页面中,任何人都可以留下评论,以下是接纳请求的讨论页面,
在这里插入图片描述
经过讨论,贡献者可了解,还需要哪些修改,提交才可被接纳,当然双方也可使用邮件,达到这一目的,但在GitHub中,处理更加简单,贡献者可再次推送修改后的特性分支,这时接纳请求页面会自动更新,同时之前的代码评论将折叠,另外在原有的接纳请求中,添加提交,并不会通知维护者,因此贡献者推送玩新提交之后,应当留下一个评论,以便通知维护者。

如果点击接纳请求页面的Files Changed栏,将得到特性分支与master分支的所有差异,这等同于git diff master…<特性分支名>命令的输出结果。

另外GitHub将会检查接纳请求,能否被干净地合并,如果维护者拥有当前项目的写入权限,并且合并已通过检查,这时才会显示一个合并按钮,如果维护者点击合并按钮,GitHub将执行一次合并,值得注意,即使是一次快进合并(只移动分支指针),也将创建一个合并提交,如果维护者喜欢将分支同步到本地,并进行本地合并,比如将特性分支合并到master分支,再推送到GitHub,这时接纳请求将自动关闭。
在这里插入图片描述
上述细节是大多数GitHub项目的基本工作流,应当注意,用户还可为同一仓库的分支合并,发送接纳请求,在两人协作开发中,两人都拥有项目的写入权限,其中一人将自己的特性分支,推送到仓库,并开启一个接纳请求,请求将特性分支合并到master分支,等同于开启代码浏览和评论页面,这时并不需要创建项目副本,当然这类操作更利于项目的讨论环节。

接纳请求的高级技巧
补丁属性

绝大多数GitHub项目并未把接纳请求,视为补丁队列或是基于邮件的提交补丁,而是将它视为,变更的迭代评审环节,只有变更在各方都满意的情况下,才进行合并,这是一个重大的改进,之前只能在变更完成之后,才进行讨论,而现在可利用接纳请求页面,先讨论出一个变更方案,同时也不再需要补丁文件。回到之前的附图中,贡献者无需衍合提交,只需发起另一个接纳请求,这使得每个变更都集中了所有人的智慧,因此冗余更小。

保留上游分支

如果接纳请求由于过期等原因,无法实现干净地合并,则必须修正冲突,以使项目维护者能够顺利合并,之前提到,GitHub会测试每个接纳请求,能否被顺利合并,
在这里插入图片描述
当贡献者看到上图,则表示特性分支存在合并冲突,必须修正冲突,以使上图变绿,此时维护者只能等待贡献者解决冲突,而贡献者有两个选择,将特性分支衍合或合并到目标分支(通常是项目副本的master分支),以修正冲突,大多数GitHub开发者会选择后者,因为衍合未必能得到一个干净的提交历史,同时还会带来更多的复杂性和更大的出错风险。

回到之前的tonychacon示例,贡献者的接纳请求中,存在一个冲突,以下给出了一个解决方法,

$ git remote add upstream https://github.com/schacon/blink // #1

$ git fetch upstream // #2
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (3/3), done.
Unpacking objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
From https://github.com/schacon/blink
* [new branch] master -> upstream/master

$ git merge upstream/master // #3
Auto-merging blink.ino
CONFLICT (content): Merge conflict in blink.ino
Automatic merge failed; fix conflicts and then commit the result.

$ vim blink.ino // #4
$ git add blink.ino
$ git commit
[slow-blink 3c8d735] Merge remote-tracking branch 'upstream/master' \
    into slower-blink
    
$ git push origin slow-blink // #5
Counting objects: 6, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 682 bytes | 0 bytes/s, done.
Total 6 (delta 2), reused 0 (delta 0)
To https://github.com/tonychacon/blink
    ef4725c..3c8d735 slower-blink -> slow-blink
  1. 贡献者将原始项目仓库,添加为远程仓库,并命名为upstream
  2. 同步该远程仓库的数据
  3. 将特性分支合并到远程仓库的本地副本
  4. 修正冲突
  5. 将特性分支重新推送到GitHub的接纳请求

之后接纳请求将自动更新,并重新检测,如下,
在这里插入图片描述
即使在长期项目中,也可使用上述方式,实现目标分支的连续合并,或是用于处理合并冲突,这将使开发过程更易于管理,注意,如果贡献者非要使用衍合,应当注意处理方式,不要使用衍合的特性分支强行覆盖,之前(已开启的接纳请求所包含)的特性分支,因为其他协作者有可能,已获取了之前的特性分支,所以应将衍合分支作为一条新分支,推送到GitHub,开启新的接纳请求,并创建一个引用标记,指向之前的接纳请求,再关闭之前的接纳请求。

引用标记

引用在GitHub中无处不在,在项目中,所有的接纳请求和问题点,都将获得一个唯一编号,比如接纳请求#3和问题点#3,如果需要接纳请求或问题点之间的交叉引用,可在评论或描述中,使用#<唯一编号>格式,当然也可引用项目副本的接纳请求或问题点,即<用户名>#<唯一编号>,甚至可以引用其他仓库,<用户名>/<仓库名>#<唯一编号>。

举例说明,回到之前的衍合分支,为其开启了新的接纳请求,并引用了之前的接纳请求,同时还引用了项目副本的一个问题点,以及其他项目的一个问题点,如下,
在这里插入图片描述
创建衍合分支的接纳请求,
在这里插入图片描述
如果关闭之前的接纳请求,将会看见新的接纳请求,因为GitHub可基于开启时间,自动排序所有接纳请求,这意味着任何人都可查看所有接纳请求,如下,
在这里插入图片描述
除此之外,用户还可基于SHA-1校验码,引用一个特定提交,但必须给出完整(40个字符)的SHA-1校验码,如果GitHub找到与之匹配的提交,将会直接生成一个链接,指向特定提交,同样也可以引用项目副本或其他项目的特定提交。

Markdown扩展

使用Markdown语法,可为文本,添加不同的web显示风格,比如之前的交叉引用,请看以下示例,
在这里插入图片描述
当然GitHub扩展了基础的Markdown语法,如下,

任务列表

首先是用于接纳请求的任务列表,它是一个复选框列表,可选中多个任务项,以下是文本内容和页面效果,
在这里插入图片描述
在这里插入图片描述
常用于显示接纳请求在合并之前,所需完成的任务,因此用户只需点击选项,就能更新评论,而无需了解Markdown语法,同时GitHub会查询问题点和接纳请求包含的所有任务列表,并汇总到一个页面下,比如以下的接纳请求列表,可方便查看接纳请求包含的任务,以及跟踪分支的进度,因此尽早地开启接纳请求,有利于开发进度的跟踪。
在这里插入图片描述

代码片段

用户可在评论中,添加代码片段,这对于编程思路的展示,更加直接,如下,当然GitHub支持不同编程语言的语法高亮,
```java
for(int i=0 ; i < 5 ; i++)
{
System.out.println("i is : " + i);
}
```
在这里插入图片描述

摘录

如果用户只回应大段评论的一小部分,可复制原有评论,并添加>前缀,实现原有评论的摘录效果,同时可使用快捷键,选中原有评论的文本,点击r键,被选文本将出现在评论文本框中,如下,

> Whether 'tis Nobler in the mind to suffer
> The Slings and Arrows of outrageous Fortune,
How big are these slings and in particular, these arrows?

在这里插入图片描述

表情图标

在GitHub的问题点和接纳请求的讨论中,经常会看到表情图标,在评论框中,输入:符号,就可显示表情图标,如下,
在这里插入图片描述
或者使用::格式,直接添加表情图标,如下,在https://www.webfx.com/tools/emoji-cheat-sheet/页面下,可查看emoji表情图标的对应文本,

I :eyes: that :bug: and I :cold_sweat:.
:trophy: for :microscope: it.
:+1: and :sparkles: on this :ship:, it's :fire::poop:!
:clap::tada::panda_face:

在这里插入图片描述

贴图

使用Markdown语法在评论框中贴图,相当复杂,因此GitHub简化了相关步骤,允许用户将图片拖入评论框,直接嵌入到评论中。
在这里插入图片描述

同步原始仓库

一旦用户完成公开仓库的复制,那么仓库副本(或项目副本)可独立存在,如果原始仓库出现了新提交,GitHub将使用消息,通知用户,

This branch is 5 commits behind progit:master.

但是GitHub并不会自动同步仓库副本,这需要用户手动同步原始仓库,方法如下,假定原始仓库的地址为https://github.com/progit/progit2.git,分支为master,

$ git checkout master // #1
$ git pull https://github.com/progit/progit2.git // #2
$ git push origin master // #3
  1. 贡献者切换到原始仓库本地副本的master分支
  2. 同步原始仓库
  3. 将本地master分支,推送到原始仓库的GitHub副本

6.3 项目维护

作为一个项目维护者,应当如何创建,维护和管理项目。

新建仓库

点击用户面板右侧的New repository按钮,或者点击顶层工具栏的+按钮,在下拉菜单中,选择New repository,如下,
在这里插入图片描述
在这里插入图片描述
之后将进入new repository表单,
在这里插入图片描述
只需提供项目名称,其他选项可以忽略,点击Create Repository按钮,这时GitHub仓库创建成功,仓库名为<用户名>/<项目名>,由于用户未提供放入仓库的代码,GitHub会显示相应的操作指南,引导用户创建一个全新的Git仓库,或是连接到一个已存在的Git项目。

当开发项目已加入到GitHub仓库,就可使用URL地址进行分享,所有GitHub项目都支持HTTPS和SSH访问,地址为https://github.com/<用户名>/<项目名>和[email protected]:<用户名>/<项目名>,使用上述两个地址,都可实现Git的数据获取和推送,而访问控制则基于登录用户的权限,对于公开项目来说,无需GitHub账号,也可基于HTTPS,实现项目克隆,如果用户已申请GitHub账号,同时上传的SSH密钥也被项目维护者接纳,这时可使用SSH访问项目,当然HTTPS是最简单的访问模式。

添加项目协作者

如果开发项目需要其他的协作者,将需要使用GitHub的协作者属性,比如Ben,Jeff,Louise已申请GitHub账号,同时项目维护者需将仓库的读写权限,授予此三人,点击右侧面板的Settings链接,
在这里插入图片描述
选中左侧面板的Collaborators项,在表单底部的文本框中,输入协作者的用户名,点击Add collaborator按钮,并可重复添加协作者,如果需要删除协作者,可点击用户名右侧的X符号。
在这里插入图片描述

管理接纳请求

接纳请求可能来自于仓库副本的分支,或者来自于原始仓库的另一条分支,假定项目维护者tonychacon,创建了一个新项目fade,

邮件通知

当贡献者完成代码修改后,可开启一次接纳请求,并使用邮件,通知项目维护者,如下,
在这里插入图片描述
邮件将会给出接纳请求的变更统计,以及接纳请求的链接,运行git pull patch-1,维护者可从贡献者的GitHub仓库副本中,获取修改提交,因此维护者可新建一个特性分支,运行该命令,合并贡献者的提交,以下的.diff和.patch URL,则是接纳请求中,所包含的差异文件和补丁,如果维护者需要直接合并贡献者的提交,可运行,

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

当接纳请求中出现评论时,维护者将会收到一个邮件通知,点击邮件中包含的评论链接,可直接跳转到评论页面,同时维护者也可直接回复邮件,邮件的内容也将公布在接纳请求的评论区,
在这里插入图片描述
当维护者准备合并贡献者的提交时,既可以直接从URL获取,也可以添加贡献者的GitHub仓库副本进行获取,之后完成合并,如果只是一次简单合并,维护者也可直接点击,接纳请求页面的Merge按钮,这时将生成一个合并提交,并完成合并。
在这里插入图片描述
如果维护者暂时不希望合并,也可以关闭接纳请求,开启接纳请求的贡献者,也将获得通知。

引用标记

如果项目维护者需要处理大量的接纳请求,同时也不希望添加过多的远程仓库,GitHub允许维护者使用一个高级技巧,来处理这类问题。

GitHub提供的接纳请求,实际等同于伪分支的排序,在默认情况下,克隆无法使得用户获得这些伪分支,但它们只是被隐藏起来,用户依然可以访问它们,这时可使用一个底层命令ls-remote,当然这不是一个常用命令,但可以显示服务器上出现的所有引用,如果命令附带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分支(因为它保存在贡献者的副本仓库),这时维护者可使用pull/<接纳请求的编号>/head指针,获取到提交a5a775,这意味着项目维护者无需添加远程仓库,就可获取接纳请求所包含的分支,运行以下命令,

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

上述命令可连接origin远程仓库,并下载refs/pull/958/head引用,所指向的分支,之后该分支将放入本地仓库的.git/FETCH_HEAD,使用git merge FETCH_HEAD,合并到本地特性分支,进行评估,虽然上述合并有些奇怪,但的确能提交效率。

基于上述原理,可以一次性获取所有的接纳请求,打开本地仓库的.git/config配置文件,找到[remote “origin”]配置项,如下,

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

fetch =可将远程仓库的目录,映射到本地仓库的目录,等同于远程仓库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/*

添加的目录映射,等同于将远程仓库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
# ...

从上述输出信息可知,远程仓库的所有接纳请求,都同步到本地,应当注意,这些本地目录都具有只读属性,

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

GitHub仓库中,除了head引用之外,还有merge引用,如果维护者点击了页面的Merge按钮,相关接纳请求将保存在该引用中。

接纳请求的迭代

从本质上说,接纳请求类似于开启一个论坛话题,它既可以针对特性分支,也可以针对另一个接纳请求,比如在原有接纳请求的基础上,其他贡献者突然想到一个更好的方案,但他并不确定,该方案是不是足够好到,放弃之前所有人的努力,这时他可再开启一个接纳请求,指向原有的接纳请求,而作为项目维护者则可以选择新的接纳请求。
在这里插入图片描述

呼叫和通告

GitHub提供一个优秀的通告系统,团队或普通贡献者发出任何问题或反馈,都将第一时间通知项目维护者,同时在评论文本框中,使用@前缀,会出现一个名称列表,其中包含了项目的所有协作者和贡献者,
在这里插入图片描述
当然也可使用@呼叫一个陌生用户,之后该陌生用户也将会添加到名称列表中,如果在评论中,呼叫了某一用户,该用户将收到一个通告,这意味着,在沟通过程中,可以指定目标用户,而避免对其他用户造成干扰,同时项目成员也可呼叫自己的朋友,或公司同事,使其加入到项目中。

当用户开启一个接纳请求或问题点时,可使用订阅功能,之后该接纳请求或问题点的任何变动和评论,用户都将获得通告,当然用户还可订阅其他的内容,如果用户不想继续订阅,可点击对应页面的Unsubscribe按钮,
在这里插入图片描述

通告页面

在用户设置页面中,选中Notification center栏,可配置通告的事件和类型,用户可选择Email或Web通知,或者同时选中,
在这里插入图片描述

web通告

在个人主页的顶部工具栏,就可看到蓝色的通告图标,如下,
在这里插入图片描述
点击图标,可显示一个通告列表,并基于开发项目进行分组,如果需要查看特定项目的通告,可点击左侧面板的项目名,

点击通告右侧的打勾图标,表示用户已查看,点击项目名右侧的打勾图标,表示该项目的所有通告都已查看,打勾图标之前,还有一个静音图标,点击它,表示用户不想再接收后续通告。

上述功能适用于大量通告的处理,许多资深的GitHub用户都会关闭Email通告,而使用web页面进行通告管理。

Email通告

如果在设置页面中,开启Email通告功能,当出现新的接纳请求或评论时,GitHub将会向用户邮箱,发送一封通告邮件,如下,

To: tonychacon/fade <[email protected]>
Message-ID: <tonychacon/fade/pull/[email protected]>
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:[email protected]>
List-Unsubscribe: <mailto:[email protected]>,...
X-GitHub-Recipient-Address: [email protected]

Message-ID包含了开发项目和接纳请求的信息,List-Post和List-Unsubscribe等同于web通告的静音和取消订阅功能,只需将当前邮件转发到两个邮箱,即可实现静音和取消订阅功能。

如果用户同时开启了web通告和Email通告,当用户读取Email通告之后,对应的web通告将标记为已读。

特殊文件

如果开发项目中包含了这些特殊文件,GitHub将会放入web页面中。

README

GitHub可接受任意格式的README文件,比如README, README.md, README.asciidoc等,如果GitHub在项目源码中,发现README文件,将会显示在项目的起始页面中。大多数团队都会使用该文件,保存项目的相关信息,比如项目或仓库的发起人,该文件通常会包含,项目梗概,配置和安装方法,运行示例,应用许可,如何贡献代码,由于GitHub会渲染该文件,因此文件内可嵌入图片或链接。

CONTRIBUTING

如果存在一个CONTRIBUTING文件(扩展名不计),当任何人开启一个接纳请求时,GitHub都将显示以下页面,在CONTRIBUTING文件中,可预定义接纳请求的处理方式,以及操作指南。
在这里插入图片描述

项目管理

通常情况下,GitHub并无太多的项目管理,需要用户分心,以下列举了一些常用的配置,

默认分支的变更

如果仓库的主分支不是master,同时维护者又希望贡献者或接纳请求,将当前主分支视为默认分支,可在仓库设置页面的Options中,点击Default branch,在下拉列表中,选择默认分支。
在这里插入图片描述

项目移交

如果项目维护者希望将项目,移交给GitHub的其他用户,可在仓库设置页面的Options栏中,找到Transfer ownership项,
在这里插入图片描述
当维护者准备放弃项目,同时有其他用户愿意接受,或者项目越来越大,希望移交给一个团队,都可以使用移交功能,移交之后,仓库以及与仓库关联的信息,都将移动到新位置,同时会在原有仓库的页面上,放置一个链接,指向仓库的新位置,使用原有仓库的URL,依然可克隆和同步,因为原URL能重定向到新URL。

6.4 团队管理

在GitHub中,除了申请个人账号,还可申请团队账号,两种账号存在一些差异,团队账号可包含多个成员,并能共享项目的控制权,同时GitHub也提供了一些工具,用于管理团队成员,当然团队账号可以是开源团队(比如perl,rails),或者公司团队(比如google,twitter)。

基础

点击页面右上角的+图标,选择New organization,即可新建团队,
在这里插入图片描述
首先需要为团队取名,并提供一个邮箱,用于整个团队的对外联络,团队创建者可邀请其他用户,成为团队的维护者,之后团队才算正式建立,与个人用户一样,团队账号也是免费使用,但所有项目必须开源。

作为团队维护者,当创建仓库部分时,可选择将其,放入团队空间中,当创建新仓库时,同样既可以放入个人空间,也可放入团队空间,同时团队维护者还可自动查看,其他团队账号所创建的新仓库。

也可为团队,配置一个头像,同时团队账号也有一个起始页面,可列出团队的所有项目仓库。

开发组

团队可建立开发组,每个开发组可分配一些用户和仓库,同时配置开发组用户的仓库访问权限,比如现有三个仓库frontend,backend,deployscripts,这时HTML/CSS/JavaScript开发者需要访问frontend和backend仓库,运维开发者需要访问backend和deployscripts仓库,建立开发组之后,就无需仓库的协作问题。

团队首页中,将列出团队包含的所有仓库,开发组和用户,
在这里插入图片描述
在团队页面右侧的开发组面板中,点击开发组名,可进入开发组页面,其中可添加组成员,添加仓库,设定开发组的访问权限,每个开发组可拥有仓库的只读,读写,管理员三种权限,点击Setting按钮,可修改开发组的访问权限,
在这里插入图片描述
团队维护者可发送邮件,邀请用户,加入开发组,使用@,可呼叫开发组的所有成员,比如@acmecorp/frontend,用户可加入多个开发组,因此可依据用户个人的喜好,加入不同类型的开发组。

审查日志

团队维护者可查看整个团队所发生的变化,点击Audit Log栏,其中可显示团队发生的所有时间,所有成员的登录位置和地理位置,当然也可设置不同的过滤器,以方便查看。
在这里插入图片描述

6.5 脚本系统

在大型开发组或项目中,需要定制一些扩展服务,这时需要使用GitHub提供的hook系统和api。

服务与hook系统

使用服务和hook,可方便仓库管理者实现,与外部系统的交互,在GitHub仓库的Settings页面,可找到Webhooks and Services项,
在这里插入图片描述
目前有很多外部服务可供选择,同时也集成到了其他的商用和开源系统中,这些服务可实现持续整合,bug和问题跟踪,聊天室,文档化系统,从页面的Add Service下拉列表中,选择email,可进入配置页面,
在这里插入图片描述
如果点击Add service按钮,一旦仓库出现新的推送,用户邮箱都将收到一份通知邮件,同时服务可监听不同类型的事件,通常用于监听仓库推送事件。如果外部的开发系统需要集成到GitHub,应当检查外部系统是否支持集成,比如需要使用Jenkins,对代码库进行测试,则必须使能Jenkins内建的服务集成功能,以便在仓库的每次推送后,运行相关的测试。

如果用户需要的服务,并未包含在配置页面中,也可使用更通用的hook系统,在GitHub仓库中添加hook也十分简单,只需指定一个URL,当对应事件出现时,GitHub会向指定URL,发送一个http包,而通常情况下,用户需要配置一个小型的web服务,用于监听GitHub hook的定向投递,以及处理http数据,为了使能hook,点击Settings页面的Add webhook按钮,之后将进入web hook配置表单,
在这里插入图片描述
通常情况下,只需输入一个URL,一个密钥,再点击Add webhook按钮,就可完成配置,剩余选项用于指定GitHub需响应的事件,默认状态下,只获取push事件,即仓库出现新推送。

以下是一个web服务的示例,用于处理web hook发出的http数据,这里使用Ruby的web框架Sinatra,如果项目仓库中分支的某个文件被修改后,将向用户发送一封邮件,

require 'sinatra'
require 'json'
require 'mail'

post '/payload' do
    push = JSON.parse(request.body.read) # parse the JSON
    
    # gather the data we're looking for
    pusher = push["pusher"]["name"]
    branch = push["ref"]
    
    # get a list of all the files touched
    files = push["commits"].map do |commit|
        commit['added'] + commit['modified'] + commit['removed']
    end
    files = files.flatten.uniq
    
    # check for our criteria
    if pusher == 'schacon' &&
        branch == 'ref/heads/special-branch' &&
        files.include?('special-file.txt')
        
        Mail.deliver do
            from '[email protected]'
            to '[email protected]'
            subject 'Scott Changed the File'
            body "ALARM"
        end
    end
end

GitHub投递的数据采用了JSON格式,其中包含了,完成仓库推送的用户,推送的分支名,推送提交中修改了哪些文件,之后将检查约定条件,如果匹配,则向用户发送邮件。

为了实现上述开发,用户必须有一个优秀的开发平台,基于上例可知,web hook并未提供更多的数据,如果每个hook能够容纳GitHub包含的所有数据,可使hook的调试更加方便,另一个特别的功能,用户可以重复投递http数据,用于web服务的测试。至于编写webhook和事件类型的信息,可查找https://developer.github.com/webhooks/

GitHub API

服务和hook可基于仓库事件,预定义处理操作,如果用户需要在事件中,添加更多的信息,或是需要一些自动化操作,比如添加协作者,标记问题点,这时就可基于GitHub创建大量的API,熟练掌握这些API,基本可满足用户的所有需求。

基本用法

最简单的应用,生成一个无需验证的GET请求,可用于获取开源项目的用户信息或只读信息,比如需要了解schacon用户的以下信息,

$ curl https://api.github.com/users/schacon
{
  "login": "schacon",
  "id": 70,
  "avatar_url": "https://avatars.githubusercontent.com/u/70",
  # ...
  "name": "Scott Chacon",
  "company": "GitHub",
  "following": 19,
  "created_at": "2008-01-27T17:19:28Z",
  "updated_at": "2014-06-10T02:37:23Z"
}

当然也可以获取团队,项目,问题,提交的信息,只要是GitHub的公开信息,都可以获取,另外用户还可以使用API,渲染Markdown格式的文本,或是查找.gitignore模板,

$ curl https://api.github.com/gitignore/templates/Java
{
  "name": "Java",
  "source": "*.class
  
  # Mobile Tools for Java (J2ME)
  .mtj.tmp/
  # Package Files #
  *.jar
  *.war
  *.ear
  
  # virtual machine crash logs, see https://www.java.com/en/download/help/error_hotspot.xml
  hs_err_pid*
  "
}
问题点的评论

如果用户需要评论问题点或接纳请求,以及查看或交流需私有信息(包含验证),这时将遇到验证的问题,当然存在不同的解决方法,最简单的方法,使用用户名和用户密码,选中Settings页面的Applications项,
在这里插入图片描述
首先选定通讯令牌和描述,适用的页面范围,当用户的脚本或应用关闭时,一个好的描述,可让用户放心移除通讯令牌,同时GitHub每次只会提供一个通讯令牌,应当将其复制保存,这时用户在脚本中,可使用该令牌完成验证,而不是使用用户名和用户密码,因为令牌的访问范围可进行限制,同时令牌也可以撤销,另外用户的访问速率也将产生变化,在无验证的状态下,用户每小时只能发出60个http请求,一旦完成验证,用户每小时可发出5000个http请求。

以下示例将在问题点中,生成一个评论,假定问题点的编号为#6,用户可向repos/<user>/<repo>/issues/<num>/comments,发出一个http post,而用户令牌将放入验证头,

$ curl -H "Content-Type: application/json" \
       -H "Authorization: token TOKEN" \
       --data '{"body":"A new comment, :+1:"}' \
       https://api.github.com/repos/schacon/blink/issues/6/comments
{
  "id": 58322100,
  "html_url": "https://github.com/schacon/blink/issues/6#issuecomment-58322100",
  ...
  "user": {
    "login": "tonychacon",
    "id": 7874698,
    "avatar_url": "https://avatars.githubusercontent.com/u/7874698?v=2",
    "type": "User",
  },
  "created_at": "2014-10-08T07:48:19Z",
  "updated_at": "2014-10-08T07:48:19Z",
  "body": "A new comment, :+1:"
}

执行上述命令后,在问题点的评论区,将看到一条新评论,
在这里插入图片描述
使用API,用户还可完成很多web操作,比如创建和设置milestone,分配问题点和接纳请求的用户权限,创建和修改标签,访问提交数据,创建新的提交和分支,开启/关闭/合并接纳请求,创建和编辑开发组,生成接纳请求的评论,网页检索等等功能。

接纳请求的状态修改

在接纳请求中,每个提交都有一个或多个状态,使用API可添加和查询这些状态,

大多数的持续集成和测试服务,可使用API,基于已推送代码的测试结果,来确定已推送代码的处理方法,之后,如果推送提交通过所有测试,将返回一个报告,另外也可使用API进行一些检查,比如提交描述的格式,贡献指南文档中是否包含了撰稿人的信息,提交是否包含有效的签名。

以下示例用于检查提交描述中,是否包含Signed-off-by字符串,

require 'httparty'
require 'sinatra'
require 'json'

post '/payload' do
  push = JSON.parse(request.body.read) # parse the JSON
  repo_name = push['repository']['full_name']
  
  # look through each commit message
  push["commits"].each do |commit|
  
    # look for a Signed-off-by string
    if /Signed-off-by/.match commit['message']
      state = 'success'
      description = 'Successfully signed off!'
    else
      state = 'failure'
      description = 'No signoff found.'
    end
    
    # post status to GitHub
    sha = commit["id"]
    status_url = "https://api.github.com/repos/#{repo_name}/statuses/#{sha}"
    status = {
      "state"       => state,
      "description" => description,
      "target_url"  => "http://example.com/how-to-signoff",
      "context"     => "validate/signoff"
    }
    HTTParty.post(status_url,
      :body => status.to_json,
      :headers => {
        'Content-Type'  => 'application/json',
        'User-Agent'    => 'tonychacon/signoff',
        'Authorization' => "token #{ENV['TOKEN']}" }
    )
  end
end

以上的web hook处理程序,将检查推送包含的每个提交,如果提交描述中存在Signed-off-by字符串,将向/repos/<user>/<repo>/statuses/<commit_sha>发送一个http post,其中则包含了状态信息。

如果发送了一个状态信息,比如成功/失败/错误,那么目标URL将得到更多的信息,同时单个提交也存在多个状态,比如测试服务可提供一个状态信息,而有效性服务也可提供一个状态信息,而这两个信息其实存在差异。

如果此时开启了一个接纳请求,同时上述hook已完成配置,用户将看到以下结果,
在这里插入图片描述
如果在最后一行看见一段绿色文本,则表示提交描述中,存在Signed-off-by字符串,而现在是一段红色文本,很显然提交者忘记署名,同时接纳请求中,分支的最后提交也显示了失效图标。

Octokit

上述示例均采用了curl和http请求,在一些开源库中,使用了更规范的方法,来构建上述API,并能在多种编程语言上使用,比如Go, Objective-C, Ruby, .NET, 查看https://github.com/octokit页面,可获得更多的信息,同时这些API可帮助用户,定制和修改GitHub,以适应不同的工作流,类似信息可查看https://developer.github.com。

在这里插入图片描述

发布了80 篇原创文章 · 获赞 10 · 访问量 19万+

猜你喜欢

转载自blog.csdn.net/osoon/article/details/103991708
今日推荐