0. 快速上手与理解
- 若是你的团队来了一个新队员,有一台全新的机器,大家是否有一个文档,只要设置了相应的权限,她就能够根据文档,从头开始搭建环境,并成功地把最新、最稳定版本的软件编译出来,并运行必要的单元测试?(在这过程当中,不须要和老队员作任何交流)
其实咱们很是想说能够,可是最后在仔细考虑后发现确实是不能够的。咱们的文档注重的方面更多地在理解用户需求与后端的设计上,可是关于配置环境,运行单元测试这方面的文档,虽而后端工程师在启程时写过一篇,以下:

可是后期并无对它进行必要的完善与维护,而且没有将它push到github上,因此咱们即便想说是,可是确实是不能够的。咱们没有重视对于环境与运行方面的文档。前端
1. 你的团队的源代码控制在哪里?用的是什么系统?如何处理文件的锁定问题?
场景: 程序员果冻正在对几个文件进行修改,实现一个大的功能, 这时候,程序员小飞也要改其中一个文件,快速修复一个问题。怎么办?git
一个代码文件被签出 (check out) 以后,另外一个团队成员能够签出这个文件,并修改,而后签入么?程序员
有几种设计,各有什么优缺点?github
例如,签出文件后,此文件就加锁,别人没法签出; 或者, 全部人均可以自由签出文件数据库
答:咱们团队的源代码控制在Github上,使用的Git系统与Github自己集成的一些其余功能。
因为Git的特色,在处理文件的合并这方面有着易懂且优秀的合并技巧。
如下是场景分析:
程序员果冻如今正在对几个文件进行修改,程序员小飞要修改其中一个文件,修复一个大bug。果冻由于尚未修改完,尚未push。可是很快,小飞修改完成了,commit,push成功!小飞乐滋滋地想着本身即将到来的奖金,去吃饭了。办公室就剩下果冻一我的在紧张赶工….也是轻松且愉悦地commit,push。
啊?被拒绝了!
Pushing to git@github.com:buaase/Phylab-Web.git
To git@github.com:buaase/Phylab-Web.git
! [rejected] master -> master (non-fast-forward)
果冻内心非常郁闷,难道就由于我长得没小飞帅,就要拒绝个人提交吗?
嘿嘿,其实不是的,其实这是由于果冻在进行push以前,小飞已经推送了内容到远程数据库,果冻的push就被拒绝。由于直接push会覆盖小飞所修改的内容。
因此做为项目经理的我,在跟咱们团队的队员强调Git的使用时反复强调一点,在全部的push以前必定要进行pull,将服务器端他人推送的内容先合并到本地。
好比咱们在项目中演示以下:

关于文件的锁定这一点上,git自己的合并机制支持了多我的同时开发不一样的feature,不管是经过同一个分支,或者是不一样的分支。若是在一样的时间内,一个文件只能被一我的修改的话,虽然是不会产生冲突,可是在某些项目里,这样类串行化的做业方式效率较低。固然在实际使用git的过程当中应该尽可能避免冲突,可以自动merge就自动合并。
2. 如何看到这个文件和以前版本的差别? 如何看到代码修改和工做项 (work item),缺陷修复 (bug fix) 的关系。
场景: 程序员果冻看到某个文件被修改了,他怎么看到这个文件在最近的修改究竟改了哪些地方? 后端
场景: 程序员果冻看到某个文件在最新版本被改动了100 多行, 那么和这100多行对应的其余修改在什么文件中呢? 这个修改是为了解决哪些问题而做的呢? 那些问题有工做项 (work item,issue),或者bug 来跟踪么?服务器
答: 在git管理中, 使用git diff便可看到文件和以前版本的差别。
-
git diff:是查看working tree(工做目录)与index file(暂存区)的差异的。
-
git diff --cached:是查看index file(暂存区)与commit(本地仓库)的差异的。
-
git diff HEAD:是查看working tree(工做目录)和commit(本地仓库)的差异的。
在git里,这三个概念是很重要的,其中 git add的一个功能是将修改从工做目录添加到index file,commit的工能就是从index file的修改添加到 commit。
好比下面这是一个截图:(使用git diff --cached)

当咱们把a.txt文件提交并做出修改后,可使用git diff来查看差别:

在Github中,也能够经过可视化的界面来看到每次修改的代码(包括增长,删除)文件与修改的具体位置,修改的具体内容。
好比下面这样的界面:
网络
能够看到每次修改的文件路径、文件的内容、红色表明删除掉的内容,绿色表明添加的内容app
修改成了解决的问题要经过commit日志的提交信息来实现,可是很遗憾,在咱们的团队项目中,关闭Issue和commit日志信息都作得不太好。你们的commit日志除了黄雨萌和个人相对规范一些,队员们不少都用来当打油诗了…
一次commit能够和Issue相关联,以代表这个Issue是由本次commit修复的,只须要在git commit的时候使用时加入以下commit日志信息便可:
-
fix #xxx
-
fixes #xxx
-
fixed #xxx
-
close #xxx
-
closes #xxx
-
closed #xxx
好比我使用了以下语句:框架

如今能够在github看到

能够看到最后那里,一次commit和issue的关闭是绑定的。
3. 若是某个文件在你签出以后已经被别人修改,而且签入了,那么你在签入你的修改的时候, 如何合并不一样的修改(merge)? 你用了什么工具来帮助你?
答: 咱们使用Git来帮助咱们完成了这件事。
在通常状况下,git pull后git会自动合并Git修改的部分,自动的Merge。可是,也存在没法自动合并的状况。就像果冻和小飞这样,远程数据库和本地数据库的同一个地方都发生了修改的状况下,由于Git没法自动判断要选用哪个修改,因此就会发生冲突。可是,Git会在发生冲突的地方打个标记!好比这样式的:
<<<<<<< HEAD
test in Local
=======
test in Remote
>>>>>>> 17c805…(Commit的Hash值)
这时候咱们须要经过一双慧眼来识别哪些均可以保留,哪些保留远程数据库的内容,哪些保留本地数据库的内容。在将文件冲突的内容合并后,删除掉<<<<< 和=====,>>>>>这样的东西,从新add,commit,push,即完成了一次手工合并。
不过由于你们都是新手入门,不太会合理地人工合并冲突,因此项目经理自己在分配任务时,遵循了一个原则:尽可能不让两我的的任务在同一个文件上产生重叠。
每一个人修改的文件范围或者其余都是固定的,通常不会存在两我的同时修改一样的文件。固然,前端和后端在修改时大部分时候都会产生冲突,这时候咱们就使用了另外一套机制来帮咱们实现这一点:
新建分支与分支合并。
Beta阶段,咱们要用到一个论坛的框架与现有的一些逻辑,可是又要同时兼容以前的网站主页的风格与设计,为了实现这一点,咱们的前端负责修改页面样式,后端负责对接后台逻辑与数据库的同步问题。那么问题来了,若是两我的在同一个分支下进行工做,那么每次都要有合并与修改记录,而且若是一我的修改的部分由于某些bug不可用的时候,另外一部分也没法确认其所修改的部分是否正确。因此咱们创建了两个分支(Back-end和Front-end),Front-end上只有一个wecenter的模版供前端进行样式的修改,然后端使用默认的wecenter的模版进行数据库的对接与其余工做,两份工做由此而开始独立进行,互不干扰。
咱们团队项目里的Front-end分支和Back-end分支的状况以下:

等到前端作到可行的程度后,先后端修改的部分开始合并,合并两个分支来将前端修改的部分合并到Back-end分支上,这样合并的工做只在一天进行,且因为冲突的部分较少,大部分都是自动合并,效率很高。
4. 你有20个文件都是关于同一个功能的修改,你要如何保证这些文件都同时签入成功(修改的原子性),或者同时签入不成功?
场景: 程序员果冻要签入 20 个文件,他一个一个地签入, 在签入完5 个 .h 文件以后, 他发现一些 .cpp 文件和最新的版本有冲突,他正在花时间琢磨如何合并... 这时候, 程序员小飞从客户端同步了全部最新代码, 开始编译, 可是编译不成功 - 由于有不一样步的 .h 文件和 .cpp 文件! 这时候, 别的程序员也来抱怨一样的问题,果冻应该怎么办?
答:果冻目前面临的问题偏偏能够由咱们第三点所述的branch的好处解决。
Branch的出现,可让任何一位开发者基于其余人的代码或环境都完整可用(即stable版)的环境下进行本身的部分的独立开发 。
最后的合并工做能够放在一天以内,将全部的Branch上的feature合并到一个dev分支上来。可是这样面临的风险也是有的,多个分支同时合并时若是出现了比较大的冲突,合并起来必须当心翼翼。
同时,在解决一个Issue的时候,也能够新建一个Issue分支,好比像以下所示:

在解决了Issue后,可使用分支合并的技术将两个或多个分支合并。
5. 你的PC 上有关于三个功能的修改,可是都没有完成,有不少文件处于半完工的状态,这时你要紧急修改一个新的 bug,如何把本地修改放一边,保证在干净的环境中修改这个 bug, 并成功地签入你的修改 --- changelist management。
答:在Git里,不能完整地保证commit后整个环境处于可编译或可运行状态下的commit是很差的提交。
因此在文件半完工的状态下,咱们不可使用commit来将文件修改的内容留下来。
Git为咱们提供了一种相似于操做系统里的保存现场的指令,那就是stash。 它能够把当前工做现场"储藏"起来,等之后恢复现场后继续工做,使用方法相似下面:
$ git stash
Saved working directory and index state WIP on master: 5655bdc Merge branch 'mas
ter' of https://github.com/buaase/Phylab-Web
HEAD is now at 5655bdc Merge branch 'master' of https://github.com/buaase/Phylab
-Web
这时候就会发现,add了之后的东西都被"雪藏"起来,如今的工做区很是干净,咱们这时候能够在一个干净的环境中修复紧急的bug并提交,签入,在push后,再使用
git stash apply 或者 git stash pop
来将保存起来的内容取出来继续开开心心地开发啦。
好比下面咱们来实际操做演示一下

能够看到咱们对a.txt进行了修改,下面咱们使用stash指令来让它”保存现场“

能够看到实际上 git stash后,咱们对于a.txt的修改不见了?!
再使用 git stash pop,再来一观:

能够看到 git stash pop 后,对a.txt的修改又回来了。
6. 如何给你的源代码创建分支?
场景:大家须要作一个演示,因此在演示版本的分支中对各处的代码作了一个临时的修改,同时,主要的分支还保持原来的计划开发。大家怎么作到的?在演示以后,演示版本的有些修改应该合并到主分支中,有些则不用,大家是怎么作到的?
场景:大家的软件发布了,有不少用户,一天,一个用户报告了一个问题,可是他们是用某个老版本,并且没有条件更新到最新版本。这时候,你如何在本地构建一个老版本的软件,并试图重现那个问题?
给源代码创建分支的过程咱们下面使用一个gif图来演示一下:

上面这个gif图演示了咱们使用cherry pick的一个完整流程(第一次录制gif见谅)
主要流程是咱们创建了两个分支 dev1和devtest分支,并使用cherry-pick将dev1上的commit(日志信息为"test")合并到devtest分支上来,而且最后形成devtest分支也有该commit提交。
而且在这过程当中经过命令行创建了远程分支。
当用户没有条件更新到新版本的时候,咱们将新建一个分支,而后使用git reset hashcode(commit日志的惟一hash码,能够倒退回过去),而后进行测试以重现问题。
全过程以下所示:

咱们能够看到,咱们从fixed #189的HEAD 回退到了 b5320c所表明的commit记录处。
7. 一个源文件,如何知道它的每一行都是何时签入的,为了什么目的签入的 (解决了哪一个任务,或者哪一个bug)?
场景:一个重要的软件突然出现崩溃的状况, 程序员果冻通过各类debug手段,发现问题是在某一个文件中有一行代码彷佛显然出了问题,可是这个模块被不少其余模块调用,这行代码是何时,为了什么目的,通过谁签入的呢?若是贸然修改,会不会致使其余问题呢?怎么办?
答:针对一个源文件的每一行是在何时签入,为了什么签入,在github里有很是好的支持,以下图:

在上图中咱们能够看到,Handle10611.tex在两次提交中被修改了,分别是在65b4fe1和9a9913d两次commit中被修改过,而且两次都带有比较清晰的commit日志,知道它是为什么被签入,修改又是为了什么。以及全部跟它有关的全部commit提交信息。
一个良好的团队应当维护一个良好的commit日志,而且有所规范,可是咱们组在这一点上还很是欠缺...
8. 如何给一个系统的全部源文件都打上标签,这样别人能够同步全部有这个标签的文件版本?
代码天天都在变,有时质量变好,有时变差,咱们须要一个 Last Known Good (最后稳定的好版本) 版本,这样新员工就能够同步这个版本,咱们若是须要发布,也是从这个版本开始。那么如何标记这个 Last Known Good 版本呢?
使用git来打tag这件事,在Github中是能够很方便来作这件事:

每次发布到必定成果后,就须要发布一个realease版本,可是这样的话,是对commit自己打标签。在git里,标签分为两种类型:轻量标签和附注标签。轻量标签是指向提交对象的引用,附注标签则是仓库中的一个独立对象。
$ git tag v1.0.0
想查看tag的话,可使用git tag来查看,以下:

若是想回到某个标签时某个文件的状态,那么只要使用git checkout tag(标签名) 便可,以下面这个gif所示:

能够看到咱们的项目在发布时一共发布了1.1.0,1.1.1,1.0.0三版。
9. 你的项目的源代码和测试这些代码的单元测试,以及其余测试脚本都是放在一块儿的么? 修改源代码会确保相应的测试也更新么?你的团队是否能部署自动构建的任务?
在签入以前,程序员可否自动在本身的机器上运行自动测试,以保证本地修改不会影响整个软件的质量?
在程序员提交签入以后,服务器上是否有自动测试程序,完成编译,测试,若是成功,就签入,不然,就取消签入?
团队是否配置了服务器,它自动同步全部文件,自动构建,自动运行相关的单元测试,碰到错误能自动发邮件给团队
答:配置了服务器,一开始使用的是Travis-CI来自动集成测试,可是因为网络因素,Travis-CI登陆很慢,因此最后决意采用了drone.io来进行自动化的单元测试,每次测试都会自动按照预约的脚本运行单元测试,单元测试经过之后能够在Github的ReadMe里体现出来。
是这样的标志:

点开build passing的示例,咱们能够看到在drone.io中咱们部署的自动化测试:

每一次commit都会触发自动化测试,在部署成功后(只针对master分支),已经test了38次。

在Setting中也能够看到,咱们在build出错时,会自动通知个人邮箱(qianlxc@126.com)
