[Git] 谷歌的代码管理
copy from : http://www.ruanyifeng.com/blog/2016/07/google-monolithic-source-repository.html
https://github.com/google/styleguide
谷歌和 Facebook 都只有一个代码仓库,全公司的代码都放在这个库里。
我一直很困惑,为什么要这样做,不同语言的项目放在一个库有什么好处?
最新一期的《ACM通信》(59卷第7期)有一篇论文《为什么 Google 要把几十亿行代码放在一个库?》,作者是谷歌基础设施小组的工程师,可以看作官方对这个问题的详细解答。我读后感到收获很大,下面就是摘录。
一、概况
谷歌最早使用 CVS 进行代码管理,1999年改为 Perforce。那时是一台 Perforce 主机,加上各种缓存机。
当时,全公司的代码就在一个仓库里面,后来一直沿用这种做法。由于规模不断增长,Perforce 已经无法满足需求,谷歌就开始使用自己开发的版本管理系统 Piper。
Piper 架设在谷歌自己的分布式数据库系统(以前叫 Bigtable,现在改名 Spanner)之上,分布在全世界10个数据中心,保证世界各地的谷歌员工都有良好的访问速度。
目前,这个代码仓库包含10亿个文件、3500万次提交记录,大小为86TB,用户达到几万人。工作日每秒有50万次请求,高峰时80万次,大部分来自自动构建和测试系统。
谷歌90%以上的代码,放在 Piper 里面。对于那些开源的、需要外部协作的项目,代码放在 Git,主要是 Android 项目和 Chrome 项目。Git 的特点是,所有历史记录都会复制到用户的本地机器,所以不适合大型项目,必须拆分成更小的库。以 Android 为例,该项目一共包含800多个独立的仓库。
二、Piper 的设计
2.1 结构
整个仓库采用树状结构。每个团队有自己的目录。目录路径就是代码的命名空间。每个目录都有负责人(owner),他负责批准该目录的文件变动。
2.2 权限控制
Piper 支持文件级别的权限控制。99% 的代码对所有用户可见,只有少部分重要的配置文件和机密的关键业务,设有访问限制。
如果机密信息不小心放上了 Piper,文件可以被快速清除。并且,所有的读写都有日志,管理员能够查到谁读过这个文件。
2.3 工作流
Piper 的工作流(workflow)如下图。
开发者先创建文件的本地拷贝,这叫做"工作区"(workspace)。完成开发后,工作区的快照共享给其他开发者进行代码评审。只有通过了评审,代码才能合并到中央仓库。
2.4 客户端
大多数开发者通过一个叫做 CitC 的客户端,访问 Piper。
开发者通过 CitC 浏览和同步 Piper 上的文件,但是编辑和修改是在自己工作区,里面只保存有变动的文件(一个工作区一般不超过10个文件)。CitC 带有云储存机制,每个工作区就是云上的一个目录。通过代码评审以后,这些文件才从 Citc 合并进 Piper。
不使用 CitC 也是允许的,所有代码保存在本地,最终用 Git 客户端提交到 Piper。不过,由于 CitC 提供更多的功能,目前使用率达到 80% 。
2.5 主干开发
Google 采用"主干开发"(trunk-based development)。代码一般提交到主干的头部。这样保证了所有用户看到的都是同一份代码的最新版本。
"主干开发"避免了合并分支时的麻烦。谷歌一般不采用分支开发,分支只用来发布。大多数时候,发布分支是主干某个时点的快照。以后的除错和功能增强,都是提交到主干,必要时 cherry-pick 到发布分支。与主干长期并行的开发分支,在谷歌极少见。
由于不采用"分支开发",谷歌引入新功能,一般在代码中使用开关控制。这避免了另起一个分支,也使得通过配置切换功能变得容易,一旦新功能发生故障,很容易切换回旧功能。等到新功能稳定,再彻底删除旧代码。谷歌有类似A/B测试的路由算法,评估代码的表现,由于存在配置开关,这种测试很容易实现。
2.6 代码评审
所有代码合并进仓库之前,都必须进行代码评审。大部分评审对所有人开放,任何谷歌员工都可以对代码提意见或者提交变动。
代码评审的依据是《Google 代码风格指南》。谷歌有一个叫做 Critique 的工具,可以查看每一行代码的历史演变。
2.7 自动测试
评审完成后,会自动运行测试。通过测试以后,代码就合并进了 Piper 仓库,整个过程不需要人工干预。
三、优点
单一代码仓库主要有以下优点。
(1)统一的版本
整个公司的代码,有统一的版本和路径,不存在找不到文件的最新版本这样的问题。
(2)广泛的代码共享和复用
任何人都可以浏览和使用全公司的代码,这大大促进了代码的共享和复用。
(3)简化的依赖管理
如果你是库文件或者 API 的作者,因为所有人的代码都在一个库里面,所以很容易找到依赖你的所有下游代码。
每当代码变动,所有依赖你的代码都会自动构建。如果有大量的构建失败,那么系统会自动撤销这次提交。这样也保证了所有代码依赖的都是最新版本,避免依赖不同的版本所导致的冲突。
另外,由于代码的边界很清楚,所以不会发生循环依赖。而且,API的作者也很容易发现,别人怎么使用他的API。
(4)原子性变动
由于每次代码变动所导致的影响,都在一个仓库里面,所以都属于原子性的变动。因此,很容易撤销,或者预先测试它所造成的影响。
为了防止错误提交,谷歌引入了"预提交"(即在提交之前,先分析一下依赖它的代码是否会构建失败)。
(5)大规模代码析构
单一代码仓库为查找和分析代码,提供了巨大的方便。
Google的静态分析引擎 Tricorder 定时运行,对代码进行分析。比如,C++ 11 标准公布以后,很容易找到所有需要改进的变量声明语句,进行性能优化。该引擎还对许多错误提供"一键修正"的功能,同时产出大量的统计数据。
此外,编译器团队也会对不同语言的所有代码进行分析,找出不合理的代码和过时的API。
四、缺点
单一代码仓库的主要缺点是,所有工具都必须自己写,因为市场上没有能够管理这种规模的代码仓库的软件。
五、总结
单一代码仓库,适合提倡透明开放的大型软件公司,不适合小公司和有大量私密代码的公司。
[Git] 谷歌的代码管理的更多相关文章
- GIT: 分布式开发 代码管理工具使用命令大全
代码管理工具: GIT 什么是GIT? Git是一款免费.开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目 Git是一个开源的分布式版本控制系统,用以有效.高速的处理从很小到非常 ...
- Go语言在线培训哪里好?Git操作和代码管理
在实际的项目开发过程中,多人进行项目开发,需要涉及到代码管理和协同管理.这就需要使用到代码协同管理工具.在过去,大家都熟悉使用的是SVN软件,而现在Git代码仓库管理软件的使用更为广泛.在本系列实战项 ...
- GIt如何进行代码管理
一:Git账号设置(仅第一次需设置): 1.首先打开GIt Bash 界面
- 使用Faric+Git进行分布式代码管理
Fabric是一个Python库,可以通过SSH在多个host上批量执行任务. 可以通过编写任务脚本,然后通过Fabric在本地就可以使用SSH在大量远程服务器上自动运行. 这些功能非常适合应用的自动 ...
- git subtree模块化代码管理
Git Subtree 的原理 首先,你有两个伟大的项目——我们叫他P1项目.P2项目,还有一个牛逼的要被多个项目共用的项目——我们叫他S项目.我们通过简要讲解使用Subtree来同步代码的过程来解释 ...
- 使用Git Bash进行代码管理
前提是已经安装了GitBash,这个稍后再出教程 1.新建一个目录,存放下载下来的项目,我在D盘新建了一个“gitspace”文件夹,用来存放下载下来的项目 2.进入刚刚新建的文件夹,即进入“gits ...
- 软工实践练习一——使用Git进行代码管理心得
在github.com的操作 注册 创建Organization 将指定代码库fork到小组Organization下 在Organization下创建repository 这些操作在学校的机房已经完 ...
- 使用GIT进行源码管理——GIT托管服务
虽然GIT是分布式代码管理,但是仍然需要一个集中存储服务以实现团队协作和代码备份的.对于企业的私有代码来说,大多是自建GIT托管服务.但对于开源项目和个人的私有项目,往往是选择一个GIT托管网站,这样 ...
- 如何修改git上传代码的作者姓名
随着IT行业的不断壮大,开源的东西越来越多,使用git来进行代码管理的人自然也越来越多,而且很多人的git账户都不是自己的本人名字,但是在公司工作的时候为了遇到问题能够定位责任人和便于区分提交人,通常 ...
随机推荐
- odoo 模型与ORM
型号属性 在/模型添加activity.py文件 class ActivityEvent(models.Model): _name = 'activity.event' _inherit = 'eve ...
- JavaScript基础 :学习javascript的原因
JavaScript是世界上最流行的脚本语言,因为你在电脑.手机.平板上浏览的所有的网页,以及无数基于HTML5的手机App,交互逻辑都是由JavaScript驱动的. 简单地说,JavaScript ...
- [BZOJ5293][BJOI2018]求和(倍增)
裸的树上倍增. #include<cstdio> #include<cstring> #include<algorithm> #define rep(i,l,r) ...
- BZOJ.3498.[PA2009]Cakes(三元环 枚举)
题目链接 感觉我可能学的假的(复杂度没问题,但是常数巨大). 一个比较真的说明见这儿:https://czyhe.me/blog/algorithm/3-mem-ring/3-mem-ring/. \ ...
- [UOJ240]aliens
学习了一下凸优化DP,感觉挺有意思的 首先把所有点对称到左下角,然后以每个点为顶点画等腰直角三角形,将被覆盖的点去掉,现在所有点从左上到右下横纵坐标都是递增的,设坐标为$(x_{1\cdots M}, ...
- PHP代码为什么不能直接保存HTML文件——>PHP生成静态页面教程
1.服务器会根据文件的后缀名去进行解析,如果是HTML文件则服务器不会进行语法解析,而是直接输出到浏览器. 2.如果一个页面中全部都是HTML代码而没有需要解析的PHP语法,则没有必要保存为PHP文件 ...
- 鸟哥的私房菜:Linux文件与目录管理
1. 目录与路径 1.1 相对路径与绝对路径 绝对路径:路径的写法『一定由根目录 / 写起』,如:/usr/share/doc 这个目录. 相对路径:路径的写法『不是由 / ...
- hdu 1518 dfs+剪枝
题目大意:几根棒子能否组成一个正方形 Sample Input3 //测试组数4 1 1 1 1 //棒子数目以及每根棒子的长度5 10 20 30 40 508 1 7 2 ...
- java多线程技术之(callable和future)
接着上一篇继续并发包的学习,本篇说明的是Callable和Future,它俩很有意思的,一个产生结果,一个拿到结果. Callable接口类似于Runnable,从名字就可以看出来了,但是Runnab ...
- wikioi 1017 乘积最大
dp[i][j]=max(dp[i][j],dp[t][k-1]*mapn[t+1][i]); dp[i][j]代表从0-i之间有j个乘号,mapn[i][j]表示第i位到第j位的数究竟是多少 #in ...