文/陈灵

华为无线网络产品线五级软件专家,在大型软件架构设计、性能优化方面有丰富的成功经验,多次荣获公司/产品线优秀软件架构实践表彰。

华为的明星博主,原创软件技术博客超过一百篇,愈十万字,促进了软件领域各种原理、方法、实践应用知识在公司内的普及。

C++ 专家,著有《C++ Programming Guidelines for Embeded System》、《C++ 在嵌入式系统应用的五大问题及解决方案》等大部头。

公司早期 git 与社交编程的实践者和布道者之一,同时开创了公司的技术面试环节依据 github 记录考察能力的先河。

在最近参与的 OSS 优化项目中,我们应用 git 来作为优化代码版本管理、团队协作的工具。

在这个优化项目中,我们:

  • 前后创建了大约 20 个优化分支;

  • 累计完成了超过 350 次提交;

  • 累计完成了 41 次分支合并。

与此相对比的,在很多产品的一个 R 版本开发过程中,甚至不会有开发分支。得益于 git 以及 gitlab 提供的代码托管,上面这些工作(分支建立、分支合并)变得非常简单,极大的提高了整个工作效率。

为什么要使用 git 而不是 SVN?

如果仅仅把 git 当成一个替代 SVN 的工具,我认为不需要从这里找答案,现在有很多 git 教材,都会或多或少的把 git 和传统的集中式的版本管理工具,比如 CVS、SVN 进行一番对比,给出答案。

在基于问题——改进思维模式中,我们可以发现,期望从工具优劣的角度说服使用 git 而不是 SVN 是始终站不住脚的,因为 git 同样存在一堆自己的缺点,比如:太灵活、学习成本远高于 SVN 等。

所以要使用 git,我们必需要看到工具背后极力所倡导的一种团队开发的模式和理念,基于对这种模式和理念的探索,我们再谈 git,才是一件比较顺理成章的事情。

从性能优化这件事情本身来看,通过分析历史版本优化数据,我们可以看到:

  • 我们实际修改优化 100 个优化点,能够确认产生明显收益的,可能不到 50%,也就是说对于优化来说,如何管理好优化点的修改记录,这是最大的挑战。这个述求总结下来就是方便的回溯;

  • 在一个子系统、全系统优化项目中,优化启动、优化实施、优化效果确认整个闭环周期相对较长,通常的模式都是单独走自己的优化分支进行优化的实施和确认,实施完毕之后再进行反合。在这个过程中又在结合问题 1,就会发现,如果只有一个 SVN,多人协作是非常困难的事情。

协作模式

1、基于 SVN 的协作模式

我们先看基于 SVN 的协作模式,基本上如下:


(点击图片,查看大图)

我们现在对分支管理比较严格,要求一个主干。这个要求对于产品的发布版本没有问题, 但作为开发过程或者迭代要求来说,是不适应生产力发展的要求的。在上面这种模式下面,如果多个开发人员之间要共享协作,基本都是采取文件共享这种最低级的方式,采取人工对比合入的方式进行操作(图中步骤 2)。

在很多时候, 步骤 2、3 和 5、6 会成为开发过程中的瓶颈,花上大量时间合入、合入之后解决各种本地构建的问题。 我们通常会低估这些工作的难度,在项目计划上预留很少的时间来做这些事情。

其次,SVN 上分支同步、管理比较麻烦,如果同一项目在自己本地超过 3 个分支,并且要在不同分支之间切换、修改、合并是一件比较困难的事情。

2、基于 git 的协作模式

如果使用 git,协作模式类似如下:

  • Step 1,用户在本地创建新的分支;

  • Step 2,用户将分支 push 到一个公共服务器,以便其他用户获取该分支;

  • Step 3,第二个用户从远程服务器获取分支;

  • Step 4,用户 1、用户 2 分别在各自本地开发,在各自本地分支提交,并将提交 push 到远程服务器;

(注:User 2 实际需要从 remote 上将 User 1 的修改 pull 到自己本地后才能 push,图上简化了这个过程。)

  • Step 5,用户 1 或用户 2 在远程服务器上创建合并请求,合并分支。

可以看到:

  • 所有的人,包括服务器,都拥有完整的版本,包括分支,这样省却了 SVN 那样互相在本地共享版本那样低级的操作;

  • 其次,git 可以自动合并分支,这个过程省却了大量的机械性的人工操作。

项目中的应用

1、分支策略

在优化实施前,通过对优化项目本身的分析,确定三个大的方向,即:

  • 内外置函数优化

  • 解码模块性能优化

  • 自动转换脚本为 C++ 代码

在实施过程中,我们分别为这三块建立不同的分支,通过不同的分支来管理不同类别的优化。

分支合并策略:

三个分支分别进行各自的优化,开展各自的效果确认,最终仅仅将那些确认有效的修改统一合并到一个 test 合并进行集成测试:

(点击图片,查看大图)

git 可以自动完成合并,因此可以在不同的分支上进行开发,不同分支最终的代码合并通过一条简单的 git merge 命令就可以完成,极大的提高效率。

2、分支上的分支:小粒度优化分支

如前所述,性能优化一个特点并不是所有优化修改都会最终合入版本,这中间还有一个效果确认的过程。假如某个优化修改效果不明显不最终合入,那么如何方便的管理修改、回退修改就比较重要。

在传统基于 SVN 的模式中,通常的做法是,所有的优化修改都在一个分支上进行操作,即使效果不明显,这些修改仍然在 SVN 上。到了最终合入的时候,再通过优化前后修改逐一对比,确认是否合入。

在 git 上,我们强调特性分支这个概念,git 可以帮助我们合并分支,也可以帮助我们回退提交,那么可以非常方便帮助我们达成我们预先的期望。

比如,在前面确定的三个优化方向中,内外置函数优化中实际上包括若干项优化,在实施的过程中,我们又进一步对该优化进行了更小粒度的拆分,建立了多个分支:

  • check_imsi_opt

  • lookupgrid_umts_chr_opt

  • splicestr_opt

  • fhx_ext_func_opt

  • getloctime_opt

每个小粒度分支包含一组较小粒度的、完整的修改。

(点击图片,查看大图)

通过这种方式,确认某个优化不需要合入,我们可以:

  • 回退 ext_func_opt 分支提交,重新 merge 需要合入修改的分支;

  • 或者从 ext_func_opt 分支建立新分支,merge 需要合入的分支。

3、分支上的分支:特性开发

DSL 转换为 C++ 这个优化是一个很大的功能特性,我们花了两个多个月才完成这样一个功能特性。这个优化本质上是一个特性开发过程。我们在将 DSL 转换为 C++ 代码时,同样大量应用了特性分支这种模式,以提高协作开发效率。这个功能特性包含这样一些小功能分解:

  • DSL 基本语法转换为 C++ 语法

  • 为转换后的 C++ 方式的 Counter 提供 runtime 接口

  • 适配到多个版本的 Counter 的 DSL 同时转换为 C++

  • 需要支持所有的 Counter 的 DSL 脚本转换为 C++

  • 需要支持动态加载 C++ 方式的 Counter

  • 需要对原 call-table 进行优化以支持 runtime

上述功能特性建立 A 图,如下:

(点击图片,查看大图)

在实际分支建立的时候,我们以特性 1 的分支为主线进行开发。一旦满足新的功能特性的开发条件,我们随即从该主线建立一个新分支开始新的特性开发,一旦特性开发、验证完毕,随即将功能特性合并回主线。

比如,在上面这个简化的分支图中我们可以看到,特性 5 早于特性 3 建立分支,而特性 3 由于工作量小,又早于特性 5 开发完毕合入主线。

通过这样一种模式,几个特性之间互不影响,特性之间也能协作开发而不限于某个特性只有一个人完成。

Benefit

回到最初的两个问题上来:

  • 如何管理好众多的优化点?

将优化归类,为归类建立分支,在分支上再利用特性分支实现更小粒度的修改,利用 git 的 merge 功能实现分支之间的合入。

  • 如何在优化过程中实现协作?

提前识别依赖,规划好特性分支,将涉及多人协作的分支 push 到服务器上。多个员工通过在不同的分支之间切换,在分支上提交,修改验证完毕之后合并回主线。

除此之外,我们能够在效率上感受到明显的收益,包括:

1、分支建立的效率

git 仓库是一个本地库,再不考虑分支规划这些管理上的投入外,分支建立可以看成是一个零成本的动作——任何人都可以在他自己本地建立分支,而在 SVN 上,只能由管理员建立分支,有很多沟通、协调管理上的成本。

比如,在 DSL 转换为 C++ 的过程中,我们发现采用此方案生成的 Counter 的二进制目标文件占用较大的磁盘空间,这时,我们临时决定开展一项针对性的优化:二进制目标体积的优化。我们意识到这个事情是一个独立的、不与其他特性开发产生依赖的、需要大量验证的事情。那么为此建立一个新的开发分支是最合适不过的事情。分支建立这个事情直接在本地进行操作即可。

(点击图片,查看大图)

2、分支切换的效率

如前所述,我们累计建立了超过 20 个分支,这 20 个分支共享一台编译服务器的同一个工作目录。也就是说,在编译器服务器上,一个时刻只有一份分支存在。需要构建某个分支的软件版本,利用 git 的分支切换命令直接切换过去。

git 分支切换效率远比 SVN 的分支检出效率高,很多时候,切换分支不会发生任何文件的检出。这里就不在赘述。

3、分支合并的效率

使用 SVN 的代码,在分支合并时,通常是这么几个步骤:

  • 把两个分支都检出到本地

  • 使用对比工具(比如 beyond compare)对比两个分支

  • 针对对比出来的差异,逐一手动合入

  • 提交上库

对于一些比较大型的产品来说,上述步骤 1、3 非常耗时,也非常痛苦。如果仍然采用这种模式,我们多达 40 次的分支合并简直是给自己挖坑跳。在 git 上,1、2、3 步骤由工具自动完成步骤 4,唯一需要人工参与的工作就是冲突解决。

当然,所有的效率提升,是建立在比较熟练的掌握 git 的基础上,否则缓慢的学习曲线会极大的打击使用 git 的热情。

4、其他收益

除了开发效率的提高之外,利用 gitlab 提供的代码托管功能,我们还可以:

  • 利用 pull-request 模式对提交代码控制合入质量

  • 利用在线检视功能检视代码

  • 利用 Issue 列表记录

这些都是 GitLab 上所提供的功能,已经有很多介绍,在此就不在赘述。

如何更好的用好 git?

1、git tools

git 与 SVN 在操作上有很多不同,虽然同样有提交 (commit) 的概念,但我们经常还需要涉及到分支的操作(建立、合并、删除),提前熟悉好 git 相比我们在过程中不断摸索更好。

熟悉并掌握好 git,包括一个良好的 git 客户端工具应用。我们尝试过 tortoise git、git extensions、eclipse egit、git flow,但从最后的效果来看, 我认为最好的 git 工具还是 git bash 这个命令行工具:

  • 首先,git bash 简单、快速,通过不断的命令使用,能够让我们不断的深入掌握 git,更好的理解 git,这是任何一个提供 GUI 的 git 客户端工具做不到的;

  • 其次,不同的 git GUI 客户端工具对一些操作概念的封装是不同的。比如,tortoise git 上提供了 revert 命令,而 eclipse egit 上则没有 revert 命令,git extensions 也没有 revert 命令。因此,基于某个特定的 git gui 客户端工具来学习和掌握 git 存在一定的局限性,因为客户端工具一旦发生变化,重新学习的成本很高。从这个角度来说,更倾向于直接使用 git bash 通过命令行的方式来使用 git;

  • 再次,git bash 命令行工具也是 linux 下使用 git 的最主要的方式,对于同时拥有 linux 作为开发环境的人员来看,命令行工具是唯一的使用 git 的方式。

2、git command

  • git rebase

我们使用 SVN 多人协作开发过程中,假设 A、B 均基于节点 R1 进行互不耦合的开发,那么 A 先提交,B 后提交,不会存在什么问题。即使 A、B 修改同一个文件,只要修改内容不冲突,B 在提交时更新 A 的修改到本地,SVN 客户端工具都可以自动帮助我们完成合并。

但是在 git 上,A、B 均是首先提交到本地,A 如果先 push 到公共服务器上,B 此后再 push 则必须首先更 A 的 push 更新下来,这样一来,在 A 的本地就会产生一个 merge 的动作,这个 merge 的动作体现版本树上。如果这种操作很多,整个版本树就非常乱。

比如下图体现的提交就比较混乱:

(点击图片,查看大图)

而实际上的提交应该通过 git rebase 命令对本地提交进行重整然后再 push 到服务器上,如下:

(点击图片,查看大图)

因此参与项目等额人员需要熟悉 git,有针对性的培训。

  • git cherrypick

git cherrypick 提供了一种很好的方式用于将 A 分支上的某个修改同步到 B 分支上(不是合并),这对于 git 中多个分支并存开发的情况下显得非常有用。由于之前并不了解这个命令,在分支合并过程中做了一些无用功,比如:

分支反向同步:

(点击图片,查看大图)

建立了额外的分支(比如 master-bug-fix ):

如果熟悉 git cherrypick 命令,那么在过程中能够避免这样一些无用功,提高效率。

  • git commit -- amend

git 的提交首先是提交到本地,这样一来我们并不局限于以往 SVN 的提交方式——即必须要完成本地构建才能提交,相反,我们可以随时提交。

这种方式的好处就是即使保存本地分支的工作进度便于我们在分支中切换。坏处就是从版本树上来看,可能就存在一些非原子的提交或者包含错误的提交,这些提交如果一直在自己本地则没有什么问题,但如果将这些提交版本合并到其他分支,历史树就非常长。

实际上 git 提供了修订提交的命令来修改上一次提交,在项目初期大家对这个命令并不熟悉,历史提交记录看起来非常丑。

3、分支的及时收编

前述,我们为两大优化方向分别建立了两个分支 (decode_opt) 和  (code_translation),两个分支最终会合并到 test 分支上。分支合并后,此时应该及时将两个分支收编,此后:

  • 对于遗留未完成的特性,这些开发我们可以基于合并后的 test 分支重新建立新的 code_translation 分支。这样做,可以避免后续将 code_translation 再次 merge 到 test 时,可能出现的冲突;

  • 对于 test 分支上的 bug,可以直接在这个分支上进行提交,而不需要回到原始的decode_opt 或  code_translation 分支修改然后再 merge 到 test 上两个步骤。

及时收编的好处在于:

  • 减少分支数,查看提交历史时,减少分支历史中同时出现多条分支线,便于查看;

比如下图中,code_translation 并没有及时收编到 test 分支,从历史记录上来看,就会看到两条很长的分支生命周期线,不利于查看历史记录。

(点击图片,查看大图)

  • 避免将来合并再次产生冲突。

4、分支检出

用习惯了 SVN 之后,要检出不同的分支,很多人仍然习惯性的在磁盘上创建不同的目录来检出不同的分支。这种做法实际上比较土、效率比较低的方法。在 git 中,只要在同一个项目(更准确是仓库)中,我们可以使用同一个磁盘目录在不同的目录中进行切换(分支切换效率这个问题就不此讨论了,效率高的出奇)。

一旦掌握了这种方式,在特性开发过程中,在不同的分支中切换、开发、提交,你会发现效率提升非常明显。当然,这是一种习惯的转换,短时间可能思维难以转变过来。

Summary

  • 利用 git 来作为开发阶段的版本管理工具,改变了协作模式,极大的提高了协作效率,促进了生产力的提高;

  • git 学习成本比较高,不能简单的把 SVN 那套操作简单的映射过来,在项目初期必须要有效率可能会降低的心理准备。同时需要引入专门的培训和实战练习,缩短学习周期;

  • 在产品开发中应用中,还需要从集成交付的角度,打通相关环节,特别是 CI 。目前基于 SVN 开发了大量各种工具,这些工具的切换都是成本。在上面本次的优化项目中,没有涉及这块,但正是交付项目需要考虑这些问题。


如何参与?
本次活动共有2种注册方式:
其一,在华为云计算开发者官网(http://developer.huawei.com/ict/cn/site-cloud)注册成为云计算的用户;
其二,在华为云计算开发者官网(http://developer.huawei.com/ict/cn/site-cloud)点击登录,通过CSDN账号授权方式进行注册。
注意,两种注册完成后,均需要在个人中心完善个人资料,尤其电话和邮箱两种联系方式,关系到后期领取奖品和华为开发者生态资讯获取。

如何在项目中利用 git 提高工作效率相关推荐

  1. 我利用 ChatGPT 提高工作效率的 5 种方式

    技术应该是我们的朋友,而不是我们的敌人 ChatGPT 在 11 月的发布改变了世界.学校阻止该计划,程序员对他们工作中新发现的效率赞不绝口,而创意人员则怀疑他们的工作是否受到威胁.每个人都在想同一个 ...

  2. 提高工作效率,改善生活质量

    有朋友跟我说工作一直很忙,而且老板给的工作越来越多,都忙不过来,天天忙得要死.其实这也不是个别情况,很多人有这种抱怨,但抱怨是无济于事的,应该考虑造成这种情况的原因,并设法解决. 首先,工作量是不是很 ...

  3. 如何有效地提高工作效率

    一次面试中被问到如何提高工作效率,呵呵,推荐一本书,卡耐基的<人性的弱点>. 一.保证充足睡眠首当其冲当然是睡眠质量了. 睡眠在我们生活中占据相当重要的地位,至少占了一天1/3的时间,可见 ...

  4. 【效率至上】如何才能有效提高工作效率

    最近感觉自己的工作效率低下,有点颓废,急需重振旗鼓.于是就看看一些提高工作效率的文章来激励.规整自己.程序员当经常反省自己.此时,同行的你如果看到这,那就说明,你也一样有一颗想提高自己的工作效率的心, ...

  5. 项目中使用粘性布局不起作用_项目中的 Git 使用规范

    祖师爷 Linus 在创造了伟大的 Linux 之后,又创造了应用最广泛的代码管理工具 -- Git,极大地提高了程序员的生产力. 现如今大部分项目都在使用 Git 作为代码管理工具,不论是在代码管理 ...

  6. cpu java poi 导出_让 Java 开发更简单,提高工作效率 | Gitee 项目推荐

    1.项目名称:基于 Spring Boot 的权限管理系统 项目简介:Good 权限管理系统是作者学习 springBoot 时基于 springBoot 开发的一套轻量级的权限系统,其目的是形成一套 ...

  7. 如何充分利用开源项目_5个技巧:在开源项目中利用以用户为中心的设计

    如何充分利用开源项目 当我刚开始在开放技术学院 (OTI)工作时,我始终受到以下问题的挑战:"为什么UX设计师为什么要在开源组织工作?" 在我看来,事实是几乎所有设计和可用性工作本 ...

  8. 光环国际PMP:项目经理提高工作效率的方法

    有人会问:为什么我努力善用每分每秒,却永远有做不完的事情?但为什么有的人能够日理万机,却还是精力无限?如何摆脱穷忙又毫无品质的生活? 以下5个聪明工作法,忙碌的项目经理们,请看过来. 01 每天最多做 ...

  9. java聊天室小程序论文_在Java项目中利用continue与break制作一个聊天室小程序

    在Java项目中利用continue与break制作一个聊天室小程序 发布时间:2020-12-08 16:03:27 来源:亿速云 阅读:98 作者:Leah 在Java项目中利用continue与 ...

最新文章

  1. SVD(奇异值分解)小结
  2. iOS 三种类型的Block
  3. 最小乘积生成树和最小乘积最大匹配
  4. 日志文件列表 读书笔记《Linux 系统管理技术手册(第二版)》
  5. Bzoj3924 [Zjoi2015]幻想乡战略游戏
  6. VIM使用系列:转换文本大小写
  7. android 组件化_Android 组件化路由框架设计(仿Arouter)
  8. TIOBE 2014年7月编程语言排行榜:仅发布1月,Swift进Top 20!
  9. 苹果CMSV10橙色自适应25影视网主题模板
  10. Serializable中的serialVersionUID
  11. 51单片机点亮数码管
  12. EJB+JSF开发示例(附源码)
  13. Windows 平台sqlalchemy 连接oracle数据库
  14. Linux上oracle精简版客户端快速部署
  15. 关于SETUP FACTORY %AppFolder%写入注册表问题
  16. 服务器安全防护措施有哪些?
  17. 纯css写一颗跳动的心
  18. 赴美工作常识(Part 5 - 绿卡优先级)
  19. 远程桌面连接遇到的问题及解决方法
  20. 详解StringTokenizer函数

热门文章

  1. java单选框的讲课ppt6_Joho Lewis《Java Software Solutions》第六版课件第十....ppt
  2. calsite原理_Calcite 处理一条SQL - II (Rels Into Planner)
  3. spark streaming 整合kafka 报错 KafkaConsumer is not safe for multi-threaded access
  4. java clh队列_J.U.C|同步队列(CLH)
  5. [电脑问题1]Microsoft Visual Basic运行时错误‘-2147221164’:没有注册类
  6. pandas的数据拼接与合并(concat、join、merge)
  7. 苹果电脑mac os+win双系统在线安装回macos
  8. 【pureftp】解决filezilla连接ftp报错 服务器发回了不可路由的地址 使用服务器地址代替
  9. python怎么读汉字翻译拼音_Python 返回汉字的汉语拼音
  10. iOS 真机测试错误解决An App ID with Identifier ...is not available