使用Git的重要启发性博文 —— GitHub Flow

原文地址http://scottchacon.com/2011/08/31/github-flow.html

git-flow模式存在的问题

我在各地穿梭向人们教授Git而且几乎每次培训我都会被问到关于git-flow的看法。我常常回答它很伟大——它为一个(Git)系统带来了数以百万计的可能的工作流程,并且定义了以一种相当简单的方式的、在大量开发者间可工作的、具有良好测试且灵活的工作流程。它已经成为了一种开发者可以在项目或公司间复用的标准,而且他们已渐渐熟悉了这种标准化的工作流程。

但是,它确实拥有一些缺陷。我听到过太多人抱怨不喜欢新功能分支从develop开始而不是从master开始,以及它处理热更新的方式。但这些都是小问题。

对我而言,其最大的缺陷之一是它的复杂程度超出了我所认为的大部分开发者和开发团队的真实需求。需要开发一个大辅助脚本来协助流程的实施就够复杂的了。它只能通过命令行来实现,尽管这很酷,但问题在于图形界面的Git做不到。因为所有的步骤都要手动完成,所以只有那些真的把这套复杂流程学到家的人,才不会对命令行感到不爽。这是个大问题。

上述的问题只需要通过一个更加简化的处理就可以解决。在GitHub上,我们并不使用git-flow。我们总是使用一个更加简化的Git工作流程。

其简洁性带来了诸多优点。首先是人们易于理解,这也意味着大家可以快速掌握,很少将其搞乱了或不得不撤销做错了的步骤。还有就是我们不需要封装脚本协助实现或依赖之,所以使用图形化的工具也没有问题。

GitHub Flow

所以,为什么我们不在GitHub上使用git-flow呢?嗯,最大的问题就是我们时时刻刻都在部署。git-flow的流程全是围绕“发行版”而设计的。事实上我们并没有所谓的“发行版”,因为我们每天——通常每天数次——都在向生产环境部署。这可以通过聊天室机器人来实现——这也是我们查看持续集成结果的地方。我们尝试让测试和分发越简单越好,从让所有员工在做这些事的时候不受拘束。

让部署常态化是有很多优点的。如果每隔几个小时就部署,通常情况下不可能暴露出来大量严重漏洞。小的问题可能会有,但很快就会被修复并重新部署。通常在正常流程之外你需要做一些“热修复”或其它的东西,但这本来就是我们正常流程的一部分——热更新和小功能特性在GitHub Flow中并无区别。

随时部署的另一优点是快速解决各类问题的能力。我们可以响应引起我们注意的安全问题,也可以迅速地实现小型但有趣的功能请求,同时对于正常规模甚至大型规模的功能开发,我们也可以使用相同的解决方式。过程是相同的,而且都非常简单。

怎么做

所以说,GitHub Flow是什么?

  • master分支上的一切都是可部署的;
  • 要开发新的功能,基于master创建一个名称描述具体的分支(例:new-oauth2-scopes);
  • 提交至本地分支,并持续将工作内容推送到服务端的同名分支;
  • 在需要反馈或帮助时,或你认为当前分支已经可以合并时,开启一个合并请求;
  • 在旁人检查并通过该功能后,你可以将其合并至主分支;
  • 在其合并并推送至主分支后,可以且应当立即部署;

完整的流程就是这样。它简单又有效而且适用于相当大型的团队——GitHub现已有35名员工,其中的15-20人同时在一个项目(github.com)上工作。我认为大多数开发团队——同时在同一逻辑代码上工作的分组会导致冲突——都在这个量级附近甚至更少。特别是那些足够进步开始执行快速持续部署的团队。

我们按顺序来看一下每个步骤吧。

1 - master分支上的一切都是可部署的;

根本上来说,这是本系统唯一的硬性规定。只有一个含义特殊且不变的分支,我们称之为master。对我们来说,这意味着它即将部署或至少在数小时内将被部署。对它进行倒回(将分支移至之前旧的提交点以撤销更改)是极不寻常的——如果有问题,应当撤回提交或通过新的提交修复问题,其分支本身几乎从不会回滚。

master分支是稳定的,而且基于它构建或从它开始创建新分支必须永远永远是安全的。如果未经测试或会导致构建失败的代码提交到了主分支,就会破坏整个开发团队的社会共识,这通常让人感到非常不爽。我们推送的每一个分支都应该执行测试,而且测试报告会发送到聊天室里。也就是说如果你没有在本地执行测试,那么只要将其推送到服务端的一个话题分支(甚至该分支只有单次提交)上,就可以等待Jenkins来告诉你测试有没有通过了。

你可以做一个仅在每次部署之后更新的deployed分支,但我们并没有这么做。我们只是简单地将本次构建的SHA通过web应用本身暴露出来,然后在需要做比较时curl它。

2 - 基于主分支创建具有描述性名称的分支

不论要着手开始任何工作,你都应该基于稳定的master分支创建一个具有描述性名称的分支。如GitHub代码库中现有的一些示例:user-content-cache-keysubmodules-init-taskredis2-transition。这样做有若干好处:第一,在拉取变更时,你可以看到所有大家正在做的事情;第二,当你暂时切出现有分支干别的之后又要切回来时,可以很容易记住刚刚的分支是哪个。

这样做很不错,因为当我们访问GitHub的分支列表页面时,可以轻松看到当下哪些分支正在工作中以及在这些分支上已经完成了多少工作内容。
GitHub 分支列表
这和带有粗略当前状态的新功能列表很像。如果你没有用过这个页面的话,就不知道这个页面有多棒。它只会显示相对于你当前选择的分支各自独有的工作,而且还会按最新完成的工作在前的方式进行排序。如果感兴趣,我可以点击“Compare”按钮查看具体该分支和当前分支的提交和不同之处列表。

在我正在写作这会儿,我们的仓库里正有44个携带着尚未合并的工作的分支,但同样我也看到本周内只有其中的9或10个推送过。

3 - 持续推送至命名分支

另一个和git-flow的大的不同点是我们会持续推送至服务器端的命名分支。从此,从开发者的角度,真正需要我们关心的就只有master了——向服务器推送不会搞乱任何东西亦不会造成困惑——除master以外的一切分支不过是做工作用的而已。

它同样确保了我们的工作总是得到了备份,预防了笔记本电脑丢失或硬盘损坏的问题。更重要的是,它使大家处于持续的交流中。简单的git fetch命令可以展示一个基础的待办列表给你,其包含了所有当前正在进行的工作。

$ git fetch
remote: Counting objects: 3032, done.
remote: Compressing objects: 100% (947/947), done.
remote: Total 2672 (delta 1993), reused 2328 (delta 1689)
Receiving objects: 100% (2672/2672), 16.45 MiB | 1.04 MiB/s, done.
Resolving deltas: 100% (1993/1993), completed with 213 local objects.
From github.com:github/github
 * [new branch]      charlock-linguist -> origin/charlock-linguist
 * [new branch]      enterprise-non-config -> origin/enterprise-non-config
 * [new branch]      fi-signup  -> origin/fi-signup
   2647a42..4d6d2c2  git-http-server -> origin/git-http-server
 * [new branch]      knyle-style-commits -> origin/knyle-style-commits
   157d2b0..d33e00d  master     -> origin/master
 * [new branch]      menu-behavior-act-i -> origin/menu-behavior-act-i
   ea1c5e2..dfd315a  no-inline-js-config -> origin/no-inline-js-config
 * [new branch]      svg-tests  -> origin/svg-tests
   87bb870..9da23f3  view-modes -> origin/view-modes
 * [new branch]      wild-renaming -> origin/wild-renaming

通过访问GitHub 分支列表页面,还可以让大家看到其他所有人正在工作的内容。如果有谁需要帮助或其它什么东西,可以直接审阅这些工作内容。

4 - 总是要开启合并请求

GitHub有一个叫做Pull Request(按字面翻译应该是拉取请求,意味申请让主服务端拉取更新当前申请分支的变动,但不符合中文理解,一般人会理解为本分支拉取合并主分支的更改,故使用更容易理解的“合并请求”来翻译)的很棒的代码审阅系统,但恐怕并不是所有人都知道。一些用户用它做开源工作——派生一个项目,更新项目,再向维护者发送合并请求。然而,同样可以很简单地将它当作内部代码审核系统使用,我们就是这么做的。

实际上,我们更多地把它当作一个分支交流界面来使用,而不是当作合并请求。在GitHub上,你可以发送当前分支到同一项目(不论公开还是私有)的其它分支上的合并请求,所以除了发送“请将其合并”之外,你也可以发送“我需要谁来帮忙看看”。
合并请求界面
上图可以看到Josh “@” 了 Brian 帮忙审阅代码,Brian之后针对某行代码留下了建议。再往后我们可以看到Josh认可了Brian的启发并推送了新的代码以解决这些问题。
合并请求界面的交流
最后,你可以看到我们依然处于试阅阶段——当下它还不是一个可部署的分支。早在确实希望将其合并至master并部署之前,我们就已经通过合并请求来审阅代码了。

如果在分支上或功能开发上卡壳了需要帮助或建议,或者你是一个开发者需要设计师检查工作(反之亦然),甚至是只有极少或没有代码只是截屏对比或通用的点子,你都可以开启一个合并请求。你可以使用“@用户名”的方式 “at” GitHub系统的用户,所以当你需要指定用户检查或反馈时,只要在合并请求的消息中 “at” 他们一下就好了(如上面Josh那样)。

这很酷,因为合并请求功能使人可以对不同点的某一行、一次提交点或合并请求本身进行评论,而且将所有的内容列成了独立的交流视图。同时它也允许你继续向分支推送代码,于是如果别人指出了你的代码中存在bug或遗漏了什么东西,你可以修复之并再次推送分支,GitHub会在交流视图显示新的提交。该方式可以如此持续反复。

如果该分支已经开启了太长时间,你感觉它已经失去了和主分支的同步,则可以将主分支合并至当前话题分支并继续工作。你可以在合并请求讨论或提交列表中轻松看到该分支跟上主分支进度的时间。
合并主分支提交记录
当你认为该分支上的一切都确确实实搞定,已经可以部署了,就可以进入下一步了。

5 - 只有审核合并请求后才能合并

我们不会直接在master上工作,也不会在我们认为可以了之后直接将话题分支合并至主分支——我们需要尝试获得公司其他人的共识。通常,获得共识是点“+1”、颜文字表情或者“:shipit:”的文本评论,手段不限,但一定要让别人看到并审核。
合并分支意见
当做完这些且持续集成通过了该分支后,我们可以将其合并到主分支以部署。当推送之后,该合并请求就会自动关闭。

6 - 审核后立即部署

终于,工作已经完成并合并到了master分支。这意味着就算眼下还没有部署,人们也会基于现在的主分支开始新的工作,而下一次部署(也许数小时内就会发生)也会将其推出。所以鉴于大家都不希望因为自己编写的代码导致别人的推送搞砸,所以大家总是倾向于确保自己的东西在合并后确实是稳定的而且倾向于只推送自身的改动。

我们的篝火机器人,hubot,会为所有人执行部署,例如:

hubot deploy github to production

会部署代码并零停机时间重启所有的必要步骤。你可以看到在GitHub这是多么地频繁:

hubot构建记录
你可以看到6位不同的用户(包括1位维护小哥和1位设计师)在1天内部署了大概24次。

我只需要给分支一个只包含一行更改的提交就可以做到。处理流程简单、直接、可扩展且强大。你当然可以借助功能分支的50个提交在2周内完成该操作,不过亦可以通过耗时10分钟的1次提交做到。过程简单又顺畅,不过不要因为仅仅只需要1次提交就可以实现而困惑,因为这意味着处理过程一般不会被跳过或避开,除非变更极小或无关紧要从而不值一提。

整个过程难以置信地简单且强大。我想大多数人应该都认同GitHub是一个非常稳定的平台。如果有人提出了缺陷,很快就会被修复。而且新功能的添加十分迅速。之所以在质量和稳定性方面没有任何妥协,就是因为我们可以处理得更快,或者简化、精简处理过程。

结尾

Git本身理解起来是相当复杂的,这也使得工作流程的复杂度要比简单地添加大家每天的精神负担的复杂度要高。我总是主张使用适用于团队的最简单的系统直至其不再可行,之后再添加必要的复杂度。

对于需要使用较长时间周期(每次发版间隔数周甚至数月)发行正式版本的,而且需要热更新分支、维护分支及其他分发过程中不常见的东西的团队来说,git-flow更可行,我会高度主张其使用。

而对于建立起了分发文化的团队,这些团队每天都会向生产环境推送,而且持续测试和部署代码,我会主张他们使用像GitHub Flow这样更加简化的流程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值