漫谈版本控制系统
背景
我想大家都给文件起过这些名称:
HelloWorld.java
HelloWorld_2018_04_05.java
HelloWorld_2018_04_06.java
当我们单独使用这些文件时,按照上述方式可以很好的管理文件,但是,如果现在有两个人同时修改这份文件,那么,其中一人对文件修改的内容会被另一人的内容所覆盖,这是我们不希望看到的。譬如下面代码中,不能简简单单地用李四写的HelloWorld覆盖张三写的HelloWorld。
// 张三写的HelloWorld
public class HelloWorld{
public void methodA(int arg){
System.out.print("hi");
System.out.print(arg);
}
}
// 李四写的HelloWorld
public class HelloWorld{
public void methodA(int arg){
System.out.print("hi " + arg);
}
public void methodB(){
int a = 1;
int b = 2;
System.out.print(a+b);
}
}
v1.0--悲观锁
基于此,版本控制系统(Version Control System,VCS)就应用而生了,此时的VCS(v1.0)通过悲观锁将并发执行转换成顺序执行,它具有如下功能:首先,应该把文件放在一个服务器上,方便使用者上传或下载文件;其次,任何人想对文件修改时,需要先把这个文件加锁,通过checkout
指令,使得其他人无法修改;最后,当修改完成之后,需要释放锁,通过checkin
指令,形成一个新的版本,存放到服务器端。
使用v1.0之后,张三和李四需要争夺锁,假设张三抢到锁,张三首先将HelloWorld.java上传到服务器端,形成一个新的版本并释放锁,接着,李四获得锁,上传代码到服务器端进行比较合并,最后上传,最终形成如下代码:
public class HelloWorld{
public void methodA(int arg){
System.out.print("hi " + arg);
}
public void methodB(){
int a = 1;
int b = 2;
System.out.print(a+b);
}
}
v2.0--乐观锁
基于悲观锁的VCS也存在一些问题,譬如:王五只想学习下HelloWorld,并不会对该文件进行修改,当王五向VCS服务器拉取最新代码也需要进行锁操作;张三在提交完最新代码之后,忘记了释放锁,导致其他想修改代码的人无法修改。针对这些问题,我们将乐观锁替换成悲观锁,VCS演进到v2.0版本。乐观锁通常的做法是在每个表中增加一个version版本字段,事务修改数据之前先读数据,当然版本也顺势读取出来,然后把这个读取出来的版本号加入到更新语句的条件中,比如,读取出来的版本号是1,我们修改数据的语句可以这样写,update table set column = xx where id = 1 and version =1 ,那如果更新失败了,说明以后其他事务已经修改过数据了,那系统需要抛出异常给客户端,让客户端自行处理,客户端可以选择重试。 还是以HelloWorld为例,张三修改了HelloWorld.java,并且成功提交到VCS服务器中。与此同时,李四也修改了HelloWorld.java,提交的时候,系统就会提示"版本已更新,请重新下载最新版本!"。这时的李四需要重服务器拉取最新代码,然后把本地代码和服务器最新代码进行Merge。
v3.0--多分支并行
我们知道每一款软件都会潜藏一些Bug,并且用户在使用软件的过程中会提出一些新的需求,这就要求我们不仅要修改这些Bug,还要完成新增功能模块,而往往修改Bug的进度比较快,而新增功能模块的周期比较长,这就导致我们不能在一个代码库中进行工作,如果这么做,那么修正了Bug以后就没法发布,因为包含新功能的代码还没有完成! 基于此,VCS演进到v3.0版本,支持多分支并行开发。举例来说,以刚刚发布的产品代码在Master分支,修改Bug团队创建branch-bug分支,而新增功能团队创建branch-new分支,两个团队在完成各自任务之后,将各自分支Merge到Master分支中。
v4.0--分布式
伴随着软件功能的不断增加,越来越多的团队加入进来,与此同时,出现了一些新的问题,由于VCS的服务器是集中式的,时不时出现宕机情况,导致开发人员无法提交代码;还有就是有些开发人员没有对代码进行好好测试就提交了,带出了很多bug,为了保证代码质量,能不能在代码提交之前有人对提交的代码进行审查。 基于上述两方面的考虑,VCS演进到v4.0版本,支持分布式,即每个开发人员本地都有代码仓库,它的架构图如下。首先,开发人员1和开发人员2从官方代码库中克隆,然后进行修改;修改完成之后,并不是将代码推送到官方代码库,而是推送到自己本地仓库;项目维护人员从开发人员代码仓库拉取修改过的代码,然后决定是否接受这个修改;最后项目维护人员将修改完成的代码推送到官方代码仓库。
欢迎关注微信公众号:木可大大,所有文章都将同步在公众号上。
- 大数据时代的技术hive:hive介绍
- hadoop2.6分布式部署时 livenodes等于1的原因
- Hadoop运行wordcount时报classnotfound错误的一个原因
- 在WINDOWS下交叉编译LINUX程序运行不了是为什么?
- Hibernate的缓存机制
- error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": http:/
- 【Go 语言 redis内存数据库存储 demo】
- linux下基本操作记录mongodb
- ClassLoader究竟为何物?
- Oracle应用实战八(完结)——存储过程、函数+对象曹组
- 动态代理模式原理
- SQL可以正常用,但cmd启动不了mysql,报错[ERROR] unknown variable ;basedir=....问题
- Percona-toolkit的安装和配置(r8笔记第86天)
- 分布式服务框架 Zookeeper
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 拜托!这才是分布式系统CAP的正确打开方式!
- 接口管理这下总会了吧?
- 交子杯 - 2020 - AI赛道 - TOP1
- Valine 一款快速、简洁且高效的无后端评论系统
- 两段有趣的C代码
- 算法数据结构 | 三个步骤完成强连通分量分解的Kosaraju算法
- 并查集算法 详解
- SQL 中 EXISTS 用法详解
- Blazor带我重玩前端(六)
- PB 级大规模 Elasticsearch 集群运维与调优实践
- MySQL实时在线备份恢复方案
- Android通过原生请求直接获取网页内容
- matplotlib | Python强大的作图工具,让你从此驾驭图表(二)
- 设计模式 | Catalog设计模式,抵御业务方需求变动
- 【Flutter 专题】99 初识 EventBus