记我的第一次GitHub Pull Request(上篇)提交与分支

2020-03-06

介绍

Github

GitHub是一家汇集了全世界的开源项目和开发者的网站,在上面呢你可以找到很多有趣的同时也是有用的项目,你也可以通过Pull Request的方式给你感兴趣的项目做贡献,今天我分享我的第一次Pull Request是怎样的.

Git

Git是一款开源的版本控制系统,尤其是它还是分布式的,可以理解为来自不同国家的人们通过Git可以轻松地在同一个项目上进行协作,有关它的资料你可以在这个链接找到,简单地说啊,这个版本管理中的『版本』,你可以理解为书籍出版的版本,一本书可以有第一版,第二版,第三版甚至第n版,所谓版本呢你可以理解为它描述的是一个人造物被改动的次数,现代软件开发由于节奏快,而且对开发效率要求高,还要求项目的开发方向要能灵活地适应环境变化,所以,看了Git的文档之后,你想象一下如果不用Git,直接在C盘,D盘,或者什么盘上建几个文件夹之类的来管理项目,团队协作就通过互相打包发文件来实现,效率低不说,也非常繁琐.

Hub有集成、集中的意思,GitHub就是说GitHub这个地方汇集的都是用Git这个版本管理系统管理的项目.

Git的基本概念

两个概念很重要,也很好理解,分别是:

提交

额,提交(Commit)嘛,你可以这么理解,每一次提交就相当于给项目拍一张照片,或者说把项目当时的状态记录下来,供以后检出查看,提交也类似于版本,不过在Git中也会有频繁的提交(Git的提交实际上是通过记录项目的变动实现的,而不是每次的记录项目的全部内容),重要的一点是每一次提交都在上一次提交的基础上进行的,比如说有提交,我们分别叫它们,就按提交的时间顺序排列,叫c1c2c3c4,好了,现在假设离现在最近一次提交是c4,那么你不可以在c1c2中间提交,也不可以在c2c3或者c3c4之间提交,你只能提交成c5,然后Git通过记录c5c4之间的差别,来记录你的这个c5提交.你想象一下,书籍的出版可能会有第1版,第2版,或者更多版本,假设现在那本书已经出版到了第3版,会有作者下一次更新那本书还把它叫做2.5版吗?不会的,下一次更新就叫做第4版.

一句话就是,每一次新的提交,只能建立在最近一次提交的基础之上!

分支

可是我们知道现代软件开发,要求灵活,敏捷,快速和高效,像这样每一次提交只能建立在最近一次的基础上,那如果很多人共事一个项目,还要排着队等着轮到自己的时候再提交吗?再假设我们的产品,在市场上发布着的产品对应着提交c3,而我们还在开发新功能,开发到了c5这个提交(但还不稳定,还不能公开发布),而这时如果突然发现c3有一个紧急的漏洞必须尽快解决,按照刚才我们所说的,为了修复这个漏洞,就要把现在的c5,连带着c3之后的c4一同抛弃掉,重新在c3的基础上开发以修复漏洞呢?

情况如图

肯定不能是这样的,多亏有了分支(Branch),我们能实现不抛弃当前已经开发了的c4c5,而回到c3去修复漏洞,这怎么做到的呢?

假设我们决定不抛弃c4c5,但c3的漏洞还是要修复,首先我们是可以检出每一次提交的,因为每一次提交都保存着当次提交和上次提交的差异(这也就是为什么提交必须保持的时间顺序,只能在最近的提交的基础上提交),我们可以检出c1,这没问题,然后是c2c3,可以检出来,也就是说我们可以查看c1c2或者c3时的状态(想象一下时光机,回到过去),这是可以实现的,我再重复一次,因为每一次提交都保存着变更,看这个变更是什么把它逆回去就可以了,分别检出来,然后把c1c2c3都复制到另外一个文件夹下,原先的我们叫项目a,也就是文件夹a,后来的叫做文件夹b,那么这时,文件夹b只有c1c2c3,现在我们可以修改c3的漏洞,在文件夹b做提交,我们把它叫做c4‘,这样漏洞就修复了,新功能的开发也没有被拖累.画几个示意图出来给你们看:

文件夹a,即原来的文件夹,还在继续开发新功能没有修复漏洞的那个文件夹

情况如图

可以看到文件夹a的开发新功能的进程c4c5是没有被c3的漏洞所牵连的.下面是文件夹b

<code>文件夹b</code>

文件夹b多了个c4’,就是修复漏洞的那个c4’(当然和c4没有任何关系,只是用了这个名字加了个’)

细心的朋友可能已经注意到了,在文件夹a文件夹bc1c2c3保存的信息都是一样的,却多重复了一份,有什么办法可以改进呢?假如说我们的磁盘空间非常珍贵,容不下c1c2c3这三个重复?

我们还注意到,文件夹a文件夹b虽然有相同的c1c2,和c3,但c3后面的部分,却是不一样的,这时可能你已经注意到了,不就是两条链吗?它们共同的部分只保存一份,而不同的部分就分开保存,从而把文件夹a文件夹b合并放到一起,假设叫做文件夹c,省去了冗余的c1c2c3,由于我们保存了c3之后的差异,所以就保存着c4c5来自原来的文件夹a的证据,同样也保存着c4'来自原来的文件夹b的证据,这样,由于c5记录着的是c5c4的差异,而c4记录着的是c4c3的差异,c4'记录着c4'和c3的差异,c4’,c4,和c5分开保存,并不互相干扰,以后我们说到c4’,只要把c4'和c5区分开来就行了,比如说,『来自文件夹bc4’』,『来自文件夹ac4』,『来自文件夹ac5』,这种描述方式,蕴含的正是『分支』的思想——求同存异!

合并后的『<code>文件夹c</code>』

以后,为了描述更加清晰、方便,我们就不说『来自文件夹bc4'了』,换成分支bc4’,分支ac4c5,这样,分支的概念是不是就形象了?它们原本是相同的,但是为了在不破坏版本系统一致性的前提下保存它们后来的变异,引入了新的描述子,这个新的描述子,就叫做分支.

那么上一小节,我们关于『提交』的总结就变为:在·不·引·入·额·外·信·息·的·前·提·下,如·果·每·个·提·交·都·只·保·存·自·身·和·上·次·提·交·的·变·异,那·么·为·了·维·持·版·本·管·理·系·统·数·据·的·一·致·性,每·一·次·提·交·只·能·在·最·近·一·次·提·交·的·基·础·上·进·行!

很好理解,拿刚才的例子来说,c4'显然是在c5之后产生的,那么如果不用额外的信息表示c4'是『来自文件夹b』,而『c4c5是来自文件夹a』,那么c4‘只能是c5之后的提交,因为:1)c4'的提交时间比c5要晚,而c4'只保存和上一次提交的差异,那么系统如果要检出c4’,就会按照提交时间找到c5c5加上c4'保存的差异信息,得到c4'时文件夹的状态,所以c4'是相对c5的提交而不可能是相对c3的提交;2)如果不保持时间……,那就乱套了,每次提交都只保存和上一次的差异,还不保持提交时间(或者提交次序)?那相当于丢失了全部数据!

试一试(实验题)

请你参阅Git的文档,在电脑上安装Git软件,安装后依次进行下列操作:

  1. 创建一个文件夹,命名为文件夹a,进入文件夹a,运行git init,创建文件hello.txt,随意输入一些内容,保存更改
  2. 然后运行git add hello.txtgit commit -a -m "commit1"
  3. 运行git checkout -b a
  4. 后分别在hello.txt后面添加2345并且每一次添加保存修改后都运行git add hello.txtgit commit -a -m "commit1"
  5. git log命令查看提交记录,找到第三次提交(主要观察自己的提交评论),commit xxxx字样,复制commit右边的十六进制数,我们叫他提交编号.
  6. 输入git checkout ,然后粘贴第三次提交的提交编号,应该类似git checkout xxxx
  7. 运行git switch -c b,打开此时目录下的hello.txt文件,观察看它相对你最近一次提交有何变化?
  8. 运行git checkout a,再打开hello.txt,观察它和刚才有什么变化?

小结

在本篇文章中,为了说清楚Github中的Pull Request这个事情,我们依次介绍了Git版本控制系统中『提交』和『分支』的概念,我们举了生动详实的例子,我们给出了精心准备的实验题,希望大家在有时间能多多练习,争取使自己获得更快的进步!我们会在下一篇文章讲解剩下的两个基本概念,之后我们就可以开始讲Pull Request了.

参考文献

[1] Git SCM

概念普及githubgit

记我的第一次GitHub Pull Request(中篇)合并与冲突处理

移除Hugo自动生成sitemap.xml中的无关链接